Consistency Level 検証
2010/4/22
Gourmet Navigator Inc.
Fumihiko Sato
Agenda
- 目的
- Cassandra の Consistency ( おさらい ) Write / Read Consistency Level
- 検証内容
- 検証結果
- わかったこと
目的
Cassandra の整合性は、基本 Eventual( 結果整合 性 ) だが、
最新のデータが常に必要な場合も想定される。 その場合、 Write / Read において、
Consistency Level をどのように指定すべきか?
☞ Write / Read 時に設定する Consistency Level の 違いによる整合性およびパフォーマンスを確認 する。
Cassandra の Consistency
if W + R > N then
Strong(ish) Consistency
else
Eventual Consistency
R : Read 時のレプリカ数
W : Write 時のレプリカ数
N : レプリケーションファクター
[Write] Consistency Level
ZERO(0) バックグラウンドで書き込み ( 保証なし )
ANY(6) どこかひとつに書き込まれたことを保証 (hinted write まで ?)
ONE(1) 1 ノードの CommitLog と Memtable に 書き込まれたことを保証
QUORUM(2) (N / 2 + 1) ノードに書き込まれたことを 保証
ALL(5) N ノードに書き込まれたことを保証
※保証:処理が完了してから Client にレスポンスが返る
[Read] Consistency Level
ZERO(0) X
ANY(6) X
ONE(1) 最初に反応できるノードが返す
(Backgrond で ReadRepiar が 走る ) QUORUM(2) 全ノード (N) を検索して、
最新の Timestamp を持つデー タを返す ALL(5) 現状、未対応
検証内容
環境: 3 ノード (CPU:3GHzX2, Memory:2GB の実機 X 3 台 )
Ver. : 0.6.0 final
設定:デフォルト Keyspace にて、 N=3 とする 手法: Write -> Read の処理をそれぞれの
ConsistencyLevel
およびクラスタノードの組み合わせで網羅的に実行し Write データと Read データの整合性 (一致率 ) と、 そのパフォーマンスを検証する。
※パターンごと 100 回の繰り返し処理にて検証 ※Write/Read は別プロセス
※テスト機なので、パフォーマンスは相対評価
検証内容
Ring の状態:
RandomPartitioner でこんな感じ 2:
61446018221543147101105931579091659139 〜
103512866876623624100545932159826494567 1: 103512866876623624100545932159826494567 〜 168028486273975865909091688912107023531 3: 168028486273975865909091688912107023531 〜 61446018221543147101105931579091659139
検証内容
検証のための Write/Read データ:
Keyspace1.Standard2['sato-f']['conlevtest']
Key = 'sato-f' の RandomPartitioner による Token は 86736244234436851987398379006022327675 → Node2 が PrimaryReprica となるはず
上記の Key, ColumnPath のデータを、
0 〜 1000 のランダム値にて書き込みを行う
検証内容
if W + R > N then Strongish Consistency なのであれ ば、
今回 N = 3 なので、
- Write(*) + Read(QUORUM) --> Strongish - Write(ALL) + Read(*) --> Strongish - Write(QUORUM) + Read(ONE) --> Strongish? - Write(ZERO,ANY,ONE) + Read(ONE) -->
Eventual
となるはず。
検証結果 (1/9)
Write(Node1) -> Read(Node1)
※Write と Read の時間差は 10 〜 20ms くらい
Read \ Write
ZERO ANY ONE QUORUM ALL
ONE 100%
W: 2.42 ms R: 2.77 ms
W: 2.42 ms100% R: 2.71 ms
100% W: 2.36 ms
R: 2.64 ms
W: 3.40 ms100% R: 2.66 ms
W: 3.48 ms100% R: 2.68 ms
QUORUM 100%
W: 2.37 ms R: 4.48 ms
W: 2.36 ms100% R: 4.42 ms
W: 2.47 ms100% R: 4.60 ms
W: 3.59 ms100% R: 4.48 ms
W: 3.69 ms100% R: 4.61 ms
検証結果 (2/9)
Write(Node1) -> Read(Node2)
Read \ Write
ZERO ANY ONE QUORUM ALL
ONE 100%
W: 2.54 ms R: 2.50 ms
W: 2.38 ms100% R: 2.45 ms
100% W: 2.20 ms
R: 2.48 ms
W: 3.37 ms100% R: 2.54 ms
W: 3.64 ms100% R: 2.46 ms
QUORUM 100%
W: 2.41 ms R: 5.04 ms
W: 2.56 ms100% R: 4.66 ms
W: 2.26 ms100% R: 4.97 ms
W: 3.30 ms100% R: 5.31 ms
W: 3.84 ms100% R: 4.59 ms
検証結果 (3/9)
Write(Node1) -> Read(Node3)
Read \ Write
ZERO ANY ONE QUORUM ALL
ONE 100%
W: 2.41 ms R: 3.51 ms
W: 2.36 ms100% R: 3.35 ms
100% W: 2.40 ms
R: 3.10 ms
W: 3.14 ms100% R: 3.16 ms
W: 3.53 ms100% R: 2.93 ms
QUORUM 100%
W: 2.58 ms R: 5.34 ms
W: 2.51 ms100% R: 5.62 ms
W: 2.29 ms100% R: 5.45 ms
W: 3.28 ms100% R: 5.48 ms
W: 3.64 ms100% R: 5.37 ms
検証結果 (4/9)
Write(Node2) -> Read(Node1)
Read \ Write
ZERO ANY ONE QUORUM ALL
ONE 100%
W: 2.31 ms R: 2.84 ms
W: 2.40 ms100% R: 2.87 ms
100% W: 2.56 ms
R: 2.73 ms
W: 3.16 ms100% R: 2.78 ms
W: 3.18 ms100% R: 2.70 ms
QUORUM 100%
W: 2.29 ms R: 4.32 ms
W: 2.34 ms100% R: 4.54 ms
W: 2.62 ms100% R: 4.27 ms
W: 3.35 ms100% R: 4.43 ms
W: 3.38 ms100% R: 4.34 ms
検証結果 (5/9)
Write(Node2) -> Read(Node2)
Read \ Write
ZERO ANY ONE QUORUM ALL
ONE 100%
W: 2.48 ms R: 2.50 ms
W: 2.63 ms100% R: 2.56 ms
W: 2.50 ms100% R: 2.54 ms
W: 3.37 ms100% R: 2.57 ms
W: 3.34 ms100% R: 2.47 ms
QUORUM 100%
W: 2.34 ms R: 4.55 ms
W: 2.45 ms100% R: 4.49 ms
W: 2.43 ms100% R: 4.72 ms
W: 3.09 ms100% R: 4.46 ms
W: 3.68 ms100% R: 4.76 ms
検証結果 (6/9)
Write(Node2) -> Read(Node3)
Read \ Write
ZERO ANY ONE QUORUM ALL
ONE 100%
W: 2.44 ms R: 2.89 ms
W: 2.62 ms100% R: 2.85 ms
100% W: 2.56 ms
R: 2.98 ms
W: 3.03 ms100% R: 2.83 ms
W: 3.35 ms100% R: 2.76 ms
QUORUM 100%
W: 2.42 ms R: 5.04 ms
W: 2.71 ms100% R: 4.84 ms
W: 2.50 ms100% R: 5.20 ms
W: 3.19 ms100% R: 4.79 ms
W: 3.29 ms100% R: 4.75 ms
検証結果 (7/9)
Write(Node3) -> Read(Node1)
Read \ Write
ZERO ANY ONE QUORUM ALL
ONE 100%
W: 2.52 ms R: 2.62 ms
W: 2.67 ms100% R: 2.61 ms
100% W: 2.66 ms
R: 2.75 ms
W: 3.50 ms100% R: 2.82 ms
W: 3.59 ms100% R: 2.95 ms
QUORUM 100%
W: 2.54 ms R: 4.24 ms
W: 2.93 ms100% R: 4.40 ms
W: 2.69 ms100% R: 4.29 ms
W: 3.48 ms100% R: 4.32 ms
W: 3.87 ms100% R: 4.27 ms
検証結果 (8/9)
Write(Node3) -> Read(Node2)
Read \ Write
ZERO ANY ONE QUORUM ALL
ONE 100%
W: 2.60 ms R: 2.47 ms
W: 2.42 ms100% R: 2.71 ms
100% W: 2.28 ms
R: 2.59 ms
W: 3.45 ms100% R: 2.59 ms
W: 3.57 ms100% R: 2.50 ms
QUORUM 100%
W: 2.66 ms R: 4.69 ms
W: 2.36 ms100% R: 4.42 ms
W: 2.68 ms100% R: 4.61 ms
W: 3.27 ms100% R: 4.68 ms
W: 3.65 ms100% R: 4.67 ms
検証結果 (9/9)
Write(Node3) -> Read(Node3)
Read \ Write
ZERO ANY ONE QUORUM ALL
ONE 100%
W: 2.53 ms R: 2.74 ms
W: 2.67 ms100% R: 2.88 ms
100% W: 2.32 ms
R: 3.11 ms
W: 3.57 ms100% R: 2.60 ms
W: 3.40 ms100% R: 2.77 ms
QUORUM 100%
W: 2.39 ms R: 4.61 ms
W: 2.43 ms100% R: 4.76 ms
W: 2.50 ms100% R: 4.71 ms
W: 3.25 ms100% R: 4.63 ms
W: 3.50 ms100% R: 4.90 ms
わかったこと
このレベルの検証では、
いずれのパターンでも 100% 一致
Consistency Level による整合性の差は出なかっ た・・・
[ 反省点 ]
この検証 ( シングルタスク ) 以外は無風状態 クラスタノード数 = N だったから? X 対象とするデータが小さすぎた? X
Write -> Read の間隔をもっと縮めれば違いが出る? X
わかったこと
パフォーマンス面 Write
ZERO, ANY, ONE でそれほど変わらない
QUORUM, ALL でそれほど変わらない (N が少ないの で ) QUORUM 系は ZERO 系の 1.5 倍ほどの時間がかかる Read
QUORUM は ONE の約 2 倍程度の時間がかかる Write のほうがローコストであることは確認できた ( 設計されている通り )
わかったこと ( おまけ )
Insert 系 API で指定する timestamp は
ミリ秒 (→注)
よくある「やってみました・・・」のサンプルではUNIX エポックタイム (秒 )を突っ込んでますが、 cassandra-cli ではミリ秒を突っ込んでるので、
いつまでたっても cli で入れたデータに勝てません!
org.apache.cassandra.cli.CliClient.java より抜粋
さすがに頻繁に書込みがある状況で秒精度はないよね・・・ (注) 0.6.0-rc1 からマイクロ秒 (timestampMicros) になっ た・・・
わかったこと ( おまけ )
PHP(no APC) にて
transport->open(); --> 0.016sec client->insert(...ZERO); --> 0.003sec
client->get(...ONE); --> 0.003sec transport->close(); --> 0.000sec
transport->open() のコストが API 操作と比較して 高いようなので、接続はなるべく保った方が良い。 ( 当たり前か )
わかったこと ( おまけ )
get 時に指定のデータが存在しない場合、 空のデータが返るのではなく、
NotFoundException が発生するのでハンドリングに注意
。
わかったこと ( おまけ )
Consistency Level = QUORUM, ALL の場合、
N の中に不調なノードが出てくると、 Timeout してしま う。 リトライしつつ Level を下げていくなどの対処が必要?