cassandraを学ぶ
学ぼうと思った経緯
転職先で、ポリグロット永続化をしていた。cloudSQL(MySQL),cassandra,elasticsearch,radisなど多種多様なデータストアを使用していたので、まずはcassandraから勉強しようと思った(今までRDBMSしか使ってこなかった)。
cassandraについて
Facebookが自社の大規模DBを管理する為に開発。今は、Apache Foundationが管理しているオープンソースのNoSQLデータベース。
以下公式サイト
一言で表現すると、
「パフォーマンスを損なうことなくスケーラビリティと高可用性を実現できる、オープンソースのNoSQL分散データベース」
特徴
-
分散アーキテクチャ
データはクラスタ全体に分散保存されます。
特定のサーバに依存せず、全ノードが対等な「P2P(ピア・トゥ・ピア)」構成。
(→ブロックチェーンと同じ考え)- ノード:データサーバー
- クラスタ:ノードの集合体
-
スケーラビリティ
ノードを追加すればほぼ増やした台数に比例してスケールアウト可能。
数百 TB〜PB級のデータにも対応。 -
高可用性
ノード障害が起きてもデータは自動でレプリケーションされる。
ダウンタイムなしで運用できる。 -
柔軟なデータモデル
RDBのように固定スキーマではなく、Key-Value型+カラム指向(Wide Column Store)のデータモデル。- Key-Value型→ノードにvalue(レコード)のキーを紐づけているので読み書きが高速
- カラム指向(Wide Column Store)→ バリューはRDBのようにカラム数に制約はなく、データ行ごとに持っている列の数や内容が異なってもOkという考え方
Key: ユーザー123
Value: {名前: "田中", メール: "tanaka@mail", 電話: "090-1111", 住所: -}
Key: ユーザー124
Value: {名前: "田中", メール: "tanaka@mail", 電話: - , 住所: "福岡県" }
- チューニング可能な一貫性モデル
書き込み・読み込みごとに「一貫性レベル」を選択できる。
QUORUM (過半数確認), ONE, ALL など。
例)- SNSの「いいね」数 → 少しずれててもOK → ONE
- 銀行の残高 → 絶対に正確にしたい → ALL
RDBとの比較
- RDBはBツリー構造で順番に枝を辿るので、データ量が大きくなればなるほど処理時間も増える。cassandraはキーバリューストアなので、ノードのどの場所に格納されているかをキーで一発で引っ張ってこれるので、データが増えても処理時間はほぼ変わらない。
- RDBはマスターサーバーが落ちると、一時的にアクセス不可になる。
- レプリカを作る設定もあるが、cassandraより複雑らしい
- RDBは列の構造が固定されている。
- 新しい情報を追加したいときは ALTER TABLE で列を追加する必要がある。
- しかし大規模データの場合、この操作が重くなる。Cassandraは 行ごとに持つ列を自由に変更可能
Aさんは電話番号だけ、Bさんは住所だけ、Cさんは名前だけ…でもOK。 - 列が増えすぎても全体のパフォーマンスに影響が少ない
それぞれの設計思想まとめ
特徴 | RDB | Cassandra |
---|---|---|
データ構造 | 固定スキーマの表 | 柔軟な列構造(行ごとに違ってもOK) |
一貫性 | 高い(ACID) | 選択可能(スピード優先も可能) |
スケール | スケールアップ中心(1台を強化) | スケールアウト中心(ノード追加で拡張) |
可用性 | マスター依存で停止リスクあり | ノード障害でも止まらない |
検索・集計 | 複雑な検索・JOINに強い | 単純検索・Key-Valueアクセスに最適 |
向いている用途 | 銀行、会計、ERP | SNS(例えばいいね数など)、IoT、ログ、広告配信 |
- RDB
データの関係性を明確に管理し、整合性は悲観的な考え。 - ccasandra
大量データを止まらずに高速に扱うサービスが得意だが、整合性は楽観的な考え。よく結果整合性という表現をされる(最初はデータが完全に一致していなくても、時間が経てば最終的に全ノードのデータが揃うことが保証されている)。
疑問に思ったこととその答え
JOINが難しい理由はなんで?
answer
例:SNSユーザー情報と投稿情報を結合
ユーザー情報はノードA、投稿情報はノードB、ノードCにもレプリカあり
JOINするときは 複数ノードのデータを集めて、結合して、さらに整列 する必要がある
これを分散環境でやると:
- ノード間通信が発生 → 遅くなる
- 障害があると一貫性が崩れるリスク
- そもそもCassandraは「単純なKey-Value検索」を高速化する設計なので、JOINは想定外
じゃあ、そもそも1レコードにJOINした状態で最初から定義しておけばいいじゃん
answer
例:
- ユーザー情報 + 投稿情報を1つのレコードにまとめる
- 「ユーザーID → その人のプロフィール+全投稿」と1つに格納
一見、JOIN不要で高速アクセスできそうです。
[問題点]
データ量が膨大になると、ノードの負荷が高くなるため。
- 投稿が増えるたびに 1つのレコードが巨大化
- 巨大レコードを読み書きするとノード負荷が高くなる。
- また複数ノードにコピー(レプリケーション)されている場合、更新のたびに全コピーを同期する必要がある
Cassandraは「書き込み高速・分散に強い」設計ですが、巨大データの更新は負荷が大きく遅くなってしまう。→分散型にしている意味がなくなる。
TODO:クイックスタートしてみる