ハードウェア

CassandraHardwareを参照して下さい。

チューニング

PerformanceTuningを参照して下さい。

スキーマ管理

ノードのクロックをntpなどで同期して下さい。クロックが同期していない場合、更新時刻のずれによってスキーマ変更が無効と見なされる可能性があります。 LiveSchemaUpdatesを参照して下さい。[0.7で導入された機能]

リング管理

それぞれのCassandraサーバ(ノード)には、そのホストを最初のレプリカ先として使用するキーを決定するためのトークンが割り当てられます。ノードのトークンでソートした場合、あるノードが担当するキー範囲は(前のノードのトークン、自ノードのトークン]です。即ち、「前の」トークン(その値は含まない)から自分のトークン(値を含む)までの間隔です。リングの中で最も小さいトークンを持つノードはそのトークン値以下のキーに加えて、最大のトークンよりも大きいすべてのキーを担当します。これは"範囲ラップ"と呼ばれています。

(障害シナリオでは「プライマリレプリカ」は特別な意味を持たないことに注意して下さい。すべてのレプリカは同等です。)

RandomPartitionerが使用されている場合、トークンは0から2^127までの範囲の整数です。キーはMD5ハッシュによってこの範囲にマップされ、トークンと比較されます。(キー値からトークン空間へは可換ですが、その逆は真ではありません。)

トークン選択

強いハッシュ関数を使うことによって平均的にはRandomPartitionerのキーはキー空間に均一に分散されますが、もしトークンがキー範囲を均等に分割できていなければノード間のアンバランスが発生するかもしれません。このような場合はInitialTokenをi * (2**127 / N) (i は 0 .. N-1)に設定する必要があるでしょう。Cassandra 0.7ではcassandra.yamlinitial_tokenを指定できます。

NetworkTopologyStrategyを使う場合は、それぞれのデータセンター毎に別個にトークンを計算する必要があります。トークンはリング中で一意でなければならないので、2つめのデータセンターではトークンに1を追加、3つめのデータセンターでは2を追加などとするのがよいでしょう。従って2つのデータセンターにまたがる4ノードクラスターを構成する場合、次のようなトークン割り当てになるでしょう。

DC1
node 1 = 0
node 2 = 85070591730234615865843651857942052864

DC2
node 3 = 1
node 4 = 85070591730234615865843651857942052865

それぞれのデータセンターに同数のノードを配置する場合は、データセンターが交互に現れるようにトークンを割り当てるのもよいでしょう。

[DC1] node 1 = 0
[DC2] node 2 = 42535295865117307932921825928971026432
[DC1] node 3 = 85070591730234615865843651857942052864
[DC2] node 4 = 127605887595351923798765477786913079296

順序保存パーティショナではキーの分散度合いはアプリケーション依存になります。あなたはできるだけ適切な初期トークンを設定すべきですが(可能なら実データをサンプリングして決定した方がいいでしょう)、後述する能動的な負荷分散設定や、負荷集中箇所へのノード追加などに依存することも多いでしょう。

クラスタ上で一度データが配置されたら、データの削除・再起動なしにパーティショナを変更することはできません。

レプリケーション

カサンドラクラスタのキー空間は上述したトークンによって複数の区間に分割されますが、追加のレプリカの配置は設定ファイルのIReplicaPlacementStrategyによってカスタマイズできます。標準のストラテジは次の通りです。(レプリケーションファクターをNとします)

* RackUnawareStrategy: レプリカはトークンを昇順で並べた場合の「次のN-1個のノード」に配置されます。

* RackAwareStrategy: 二つめのレプリカはリングを順次辿る上で最初に見つかる「別のデータセンターに設置されているノード」に配置されます。残りのN-2個のレプリカはできる限り一つめのレプリカが格納されたノードと同一のラックに設置されているノードに配置されます。

RackAwareStrategyを使用する際はデータ配置の偏りを避けるため、リング上で隣接するノードは異なるデータセンターに配置するべきであることに注意してください。例えばノードA、B、C、Dからなるリングがあり、この順番でトークンが設定されているとします。ここでノードA、Bがデータセンター1.、ノードC、Dがデータセンター2に配置されている場合、ノードA、Cは常に「他のデータセンターで最初に見つかるノード」になります。このためノードA、CにはB、Dより多くのデータが蓄積されるでしょう。

* これらの議論の帰結として、次のことが言えます。複数のデータセンターを同時に構築しない場合、即ち最初に一つ目のデータセンターを構築し、後で二つ目を追加する場合、二つ目のデータセンターでは徐々にノードを追加していくのではなく、一つ目のデータセンターと同数のノードを一度に設置すべきです。

稼働中のクラスターでレプリケーションファクターを変更することは想定されていませんが、コンセプト的には単純です。CLIからreplication_factorを更新(後述)した後、新しいレプリカ定義に基づいてそれぞれのノードに適切なデータを格納させるために、クラスターの各ノードに対してrepairを実行してください。

Repairが完了するまで、3つの選択肢があります。

レプリケーションストラテジを変更する場合も同じ選択肢が適用されます。

レプリケーションファクターを減らすのは簡単です。レプリケーションファクターを減らした後、余分なレプリカデータを削除するためにcleanupを実行して下さい。

稼働中のクラスターのレプリケーションファクターを更新するには、cassandra.yamlのことは忘れて下さい。代わりに、cassandra-cli を使用して以下のコマンドを実行して下さい。

ネットワークトポロジー

レプリケーションストラテジーによってデータセンター間のレプリカ配置を制御できますが、これに加えてデータセンター内でどのノードが同じラックに設置されているかをCassandraに認識させることができます。Cassandraはreadやトークン範囲変更のためのデータの移動の際にこの情報を使用して最も近いレプリカを使用します。近接ノード検出の挙動は設定ファイルで差し替え可能なEndpointSnitchクラスで変更可能です。

EndpointSnitchはレプリケーションストラテジーに関係していますが、レプリケーションストラテジーそのものとは異なるものです。RackAwareStrategyが適切にレプリカを配置するには正しく構成されたSnitch が必要です。しかしデータセンターを意識したレプリケーションストラテジーを使用しない場合もCassandraはノード間の近接情報を必要としています。

カスタムスニッチの実装例が次のリンクで紹介されています。 http://svn.apache.org/repos/asf/cassandra/tags/cassandra-0.6.1/contrib/property_snitch/

トークン範囲の変更

ブートストラップ

新規ノードを追加することを「ブートストラップする」といいます。

ノードをブートストラップするには設定ファイルでAutoBootstrapをonにして起動します。

InitialTokenを設定で明示的に指定した場合は、新規ノードはリング中の指定箇所でブートストラップします。InitialTokenを指定していない場合はリング内で最もディスク使用量が多いノードのトークン範囲を半分に分割した箇所のトークンを自動的に取得します。ただし他のノードが既にそのトークン範囲でブートストラップ中であればその範囲を避けます。

注意点:

  1. 複数ノードの追加を行う場合、一つのブートストラップノードの情報がGossipによってクラスタのすべてのノードに行き渡るまで、次のブートストラップの開始を始めるべきではありません。新規ノードは起動から2分経過し、安全になった状態で"Bootstrapping"とログ出力します。(データ分散状況を確認するのに90秒、他のノードから担当キー範囲のデータの転送が開始されるまでに30秒待ちます。)
  2. 1に関連しますが、クラスタ内の既存のノード数をNとすると、自動トークン検出によって一度にブートストラップできるノードの数は最大Nです。もしクラスタのノード数を2倍以上に増やしたい場合は、最初に追加するNノードのブートストラップが完了するまで他のノードの追加を待つ必要があります。例えばクラスタが5ノードで構成されており、7ノードを追加したい場合、最初に追加の5ノードのブートストラップが完了するのを待ってから残りの2ノードをブートストラップしなければなりません。
  3. 安全のため、トークン範囲の変更により担当から外れ、他のノードに移動したデータの自動削除は行われません。追加したノードがレプリカデータを取得し、正しく動作しているのを確認してからすべてのソースノード(同じトークン範囲を担当していたノード)で nodetool cleanup を実行して下さい。cleanupを実行しないかぎり、古いデータもノードの負荷の一部とみなされます。この状態で新たなブートストラップを行うと、新規ノードの自動トークン選択に影響を与えます。

  4. 新規ノードのブートストラップを行う場合、既存ノードはレプリケーションを始める前にキー空間を分割する必要があります。これにはある程度の時間がかかります。
  5. ブートストラップ中のノードはThriftポートを閉塞するため、 nodetoolからアクセス不能になります。

  6. 大量のデータを移動する必要がある場合、ブートストラップは何時間にも及ぶ可能性があります。 ブートストラップの進捗を確認するにはStreamingを参照して下さい。

EndpointSnitchが正しく構成されていればCassandraは自律的に近接ノードを判別してデータを転送します。従って対象キー範囲のレプリカノードの一つが同じデータセンターにある限り、追加ノードをプライマリレプリカノードと同じデータセンターに設置する必要性はありません。

ブートストラップの進捗はnodetoolnetstats引数(0.7以降)またはstreams 引数(Cassandra 0.6)で監視できます。

ブートストラップ中にnodetoolで監視していると追加したノードがデータストリームの送受信をしていないように見える場合があるかもしれません。これはソースノードが送信ストリーム用のデータをローカルで取り出している最中に発生します。この場合はソースノードに"AntiCompacting... AntiCompacted"というログが出力されます。

ノードの移動と削除

ノードの削除

稼働中のノードをクラスタから取り除くにはnodetool decommissionを実行します。停止中のノードをクラスタから取り除くには稼働中のノードでnodetool removetokenを実行し、削除対象ノードのトークンを指定します。削除されたノードが担当していたキー範囲は稼働中のノードに割り当てられ、データのレプリケートが実施されます。decommissionを実行した場合はdecomissionされるノードから新しい担当ノードにデータ転送されます。removetokenを実施した場合は残存するレプリカノードから新しい担当ノードにデータ転送されます。

データはdecomissionされるノードから自動削除されません。もしそのノードを別のトークンを指定してクラスタに再接続する場合は、あらかじめ手動でデータを削除して下さい。

ノードの移動

nodetool move: ノードを指定したトークンに移動します。この操作は基本的にはdecommissionとbootstrapを組み合わせたものです。

ブートストラップの進捗確認については, Streamingを参照して下さい。

負荷分散

単純にノードを追加した場合、クラスタリングのデータ格納バランスは不均等になるでしょう。これを調整して均等な格納バランスを得るためには、すべてのノードのトークンを計算し直し、nodetool moveコマンドによってトークンを割り当て直す必要があります。

以下にトークンを再計算するためのpythonプログラムを示します。この話題についてはCassandra Summit 2010におけるBen Blackによるプレゼンテーションでさらに詳しく説明されています。http://www.datastax.com/blog/slides-and-videos-cassandra-summit-2010

Cassandra 0.7.*以降ではnodetool loadbalanceコマンドが用意されています。これは基本的には decomission と bootstrap を組み合わせたような機能で、ターゲットのノードに移動先のトークン値を指定する代わりに、auto bootstrap と同様のヒューリスティックなアルゴリズムに基づいて新しいトークン値を自動的に選択します。ただし、このコマンドではリング全体の負荷均等化はできません。

moveやloadbalance操作の進捗状況はnodetool netstatコマンドで確認できます。(Cassandra 0.6.* 以前では streams コマンドを使用します。)

整合性

Cassandraではreadやwriteにおいて必要な整合性レベルをクライアントが指定できます(API参照)。R、W、Nがそれぞれ読み出したレプリカ数、書き込んだレプリカ数、レプリケーションファクターを示すとすると、R + W > N であればすべての read は最新の write を読むことができます。この条件を満たさない場合、タイミングによっては read は古いデータを返すかもしれません。これは結果整合性"evantual consistency"と呼ばれています。

結果整合性の詳細については以下の資料を参照して下さい。 http://www.allthingsdistributed.com/2008/12/eventually_consistent.html http://queue.acm.org/detail.cfm?id=1466448

整合性のあるバックアップについては後述します。

失われたデータや、一貫性のないデータの修復

Cassandraは2つの方法でデータ修復を行います:

  1. Read Repair: readが実行される度、Cassandraはレプリカされたデータ間のバージョン確認を行い、古いデータを持つノードに最新のデータを配布します。クライアントから整合性要求レベルが低いリクエストを受け取った場合は、遅延を最小化するためにバージョン比較はバックグラウンドで実施されます。
  2. Anti-Entropy: nodetool repairを実行すると、直近で参照されておらず、同期されていないデータを検出するため、Cassandraはそのノードに格納されているデータ範囲のMerkle treeを計算し、他のレプリカノードと比較します。Merkle treeの計算にはノード上の全データのスキャンが必要であるため、ディスクI/OやCPUを多く消費します(ネットワーク帯域の観点からは効率的です)。 このためnodetool repairをあまり頻繁に実行することは設計時に想定されていません。

nodetool repairの実行: 0.7の他のnodetool 操作と同様、repairはブロックします: 即ち、nodetoolはリペアが完了するまで待ち、その後exitします。リペア対象となるデータセットが大きい場合、リペアには長い時間がかかります。 複数ノードで同時にリペアをかけても安全です。ただしアプリケーション負荷への影響を最小化する為には、一つのノードのリペアが完了してから次のノードでリペアを開始することをお勧めします。

nodetool repairの頻度

あなたのアプリケーションが削除をまったく行わないのでない限り、本番環境のクラスタのすべてのノードで定期的にnodetool repairを実行することは不可欠です。repairの実行間隔の上限はGCGraceSecondsの設定値によって決まります(DistributedDelete 参照)。削除指示されたデータについて「削除の喪失」が発生しないようにするためには、すべてのノードでGCGraceSecondsで指定された期間の間に確実にrepairを実施する必要があります。

repairの実行スケジュールはよく検討してください。repairに関与するノードでは余分のdiskおよびCPU消費が発生するので、一般的にはrepairの実施を時間的に分散するのが良いでしょう。これによりrepairが多くのノードで同時に実行される可能性を減らすことができます。

GCGraceSeconds以内にnodetool repairが実施されなかった場合の対処

GCGraceSecondsが経過するまでにnodetool repairが一度も実行されない場合、「削除の喪失」が発生する可能性があります (DistributedDelete参照)。 このようなケースでは、削除したはずのデータが再び現れる可能性に加えて、複数のレプリカノードから返される値に不整合が発生するかもしれません。このような不整合はread repairやnodetool repairでは解消されません。後者の問題についてはCASSANDRA-1316に詳説されています。

このシナリオが発生した場合の対処として少なくとも3つの方法が考えられます。

  1. 疑わしいノードを障害ノードとみなし、後述する方法で入れ替えを行います。
  2. 削除の喪失を最小限にするため、まずGCGraceSecondsの値をクラスタ全体で増やします(ローリングリスタートが必要です)。すべてのノードでフルリペアを実施した後、GCGraceSecondsを元に戻します。この手法ではtombstoneを可能な限り再配布することになるため、「削除したはずのデータが復活する」現象を最小限にすることができます。
  3. もう一つのオプションは、単純に'nodetool repair'を全ノードで実施した後、compactionを実行してtombstoneをexpireするすることです。以降はread repairと通常の'nodetool repair'によってシステムの整合性が回復します。この方法は前の手法よりも実施が容易ですが、より多くの「削除の喪失」が発生することになるでしょう。

ノード障害への対処

ノードが一時的な停止の後で回復した場合にデータの整合性を回復するには通常のrepair機構で十分でしょう。しかし注意して頂きたいのは、ノードの停止中に更新が実行され、設定されたGCGraceSeconds(標準値は10日)以内にノードのrepairが行われなかった場合は、その期間の削除操作が完全に失われるということです。あなたのアプリケーションが削除をまったく行わないのでない限り、このようなケースでは障害ノードのデータを完全に削除し、再ブートストラップし、従来使用していたトークンについてremovetokenを実行する必要があります(下記を参照)。

ノードが完全に停止し、回復の見込みがない場合は、2つの選択肢があります:

  1. (推奨する対処方法)代替のノードを新しいIPアドレスで用意し、cassandra.yaml(0.6およびそれ以前ではstorage-conf.xml)でinitial_tokenを(failure node's token) - 1に、auto_bootstrapパラメータをtrueに指定します。この設定により、代替ノードは障害ノードの直前に配置され、ブートストラップします。ブートストラップが完了するまで、代替ノードはreadを受け付けません。ブートストラップ完了後、障害ノードに割り当てられていたトークンをnodetool removetokenでクラスタから除去し、その後各ノードでnodetool cleanupを実施します。これは障害ノードに対する古いHinted Handoffを削除するためです。障害ノードのトークンは稼働しているノードに対してnodetool ringを実行することで取得できます。

  2. (もう一つの手法)稼働しているノードに対してnodetool ringを実施し、障害ノードに割り当てられていたトークン値を取得します。代替ノードに障害データのトークンを割り当て、障害ノードと同じIPアドレスで立ち上げ、nodetool repairを実行します。repairが完了するまで、このノードだけからreadするクライアントにはデータが返りません。readの際に高いConsistencyLevelを指定すれば、これを避けることができます。

データのバックアップ

nodetool snapshotによってオンラインでデータのスナップショットを取ることができます。取得したスナップショットを任意のシステムでバックアップすることもできますが、巨大なクラスタ環境ではそのままスナップショットを取得した場所に残しておくのも選択肢の一つでしょう。 nodetool snapshotは当該ノードの全データをフラッシュさせますので、snapshotコマンド実行以前のすべての書き込みがスナップショットに含まれます。

OSやJVMの組み合わせによってはスナップショット中にプロセス生成に関連するエラーがレポートされる可能性があります。例えばLinux上の場合

Exception in thread "main" java.io.IOException: Cannot run program "ln": java.io.IOException: error=12, Cannot allocate memory

これはOSが子プロセス"ln"のために、"ln"には過大であるに関わらず、親プロセス(Cassandraサーバ)と同じサイズのメモリを確保しようとするためです。つまり、もし8GB RAM、スワップなしのシステムでcassandraに6GBを割り当てていた場合、OSは合計12GBの仮想メモリを必要とするため、プロセス生成は失敗します。

このエラーは以下のいずれかの方法で回避可能です:

あるいは

あるいは

スナップショットをリストアするには:

  1. ノードを停止する
  2. 古いcommitlogとsstableを削除する
  3. スナップショットのsstableを本番データ領域に移動する

整合性のあるバックアップ

すべてのノードでスナップショットを取ることで、結果整合なバックアップを取得できます。どの個別ノードのバックアップも整合性は保証されませんが、スナップショットからリストアした環境にアクセスしたクライアントは、通常通り結果整合性のある応答を得ることができます。

writeをConsitencyLevel=ALLで実行しない限り、厳密な意味で整合性のあるビューは存在しません。

インポート / エクスポート

スナップショットを取る代わりに、bin/sstable2jsonコマンドでSSTableをJSONフォーマットでエクスポートすることもできます:

Usage: sstable2json [-f outfile] <sstable> [-k key [-k key [...]]]

bin/sstable2jsonは必須引数としてSSTableデータファイルのフルパス(-Data.dbで終わるファイル名を含む)、オプション引数として出力ファイル(標準では標準出力に出力されます。)を取ります。-kオプションでエクスポート対象を特定のキーに限定することも可能です。

注意: Cassandraの実行環境以外にあるSSTableに対してエクスポートを実行する場合、幾つか気をつけるべき点があります。

  1. 適切な設定がされていること(ノードに対して実行する場合と同様)
  2. SSTableがキースペースの名前のディレクトリに格納されていること(本番ノードと同様)

JSON形式でエクスポートされたSSTableはbin/json2sstableで新しいSSTableとしてインポートできます:

Usage: json2sstable -K keyspace -c column_family <json> <sstable>

bin/json2sstable は引数としてキースペースとカラムファミリの名前、JSON、JSON形式の入力ファイルのフルパスと出力先SSTableファイルのフルパスを取ります。

BinaryMemtableインターフェースを使用してシリアライズされる前の行をインポートすることも可能です。これはHadoopや他のデータソース上で加工されたデータをインポートするのに有用です。

注意: バージョン0.7より、json2sstableとsstable2jsonはschemaをsystem tableからロードできるような環境で実行する必要があります。これはcassandra.yamlファイルがclasspath上に存在し、適切なストレージディレクトリを参照するように構成されていることを意味します。

監視

Cassandraは内部の統計情報をJMXデータとして公開しています。これはJVMの世界では一般的です。程度に差はあるもののOpenNMS、Nagios、MuninでJMXがサポートされています。JMXインターフェースの仕様はJmxInterfaceで解説されています。

nodetool cfstatsを実行するとカラムファミリごとの概略とクラスタの状態を示す主要な統計情報を取得できます。JMX以外のクライアントを使いたい場合には、JMXからRESTへのブリッジが利用可能です。http://code.google.com/p/polarrose-jmx-rest-bridge/

カラムファミリ単位の主要統計情報には次のような情報が含まれます: Read Count、Read Latency、Write Count、Write Latency Pending Tasksを見ると滞留しているタスクを知ることができます。これらの統計情報はjconsoleのようなJMXクライアントでも確認できます。(JConsoleをファイアウォールの背後のマシンにプロキシするためには http://simplygenius.com/2010/08/jconsole-via-socks-ssh-tunnel.html を参照して下さい。)

スレッドプールのPendingTaskはconsoleのMBeansタブでも確認できます。もし特定のスレッドが滞留している場合、何か問題が発生している可能性があります。例えばROW-MUTATION-STAGEで滞留している場合、流入するwriteリクエストが多すぎて処理が追いついていないことを示します。より精妙な例はFLUSHステージです。FLUSHステージで滞留が発生している場合、Cassandraはwriteを十分に速くメモリに読み込んでいますが、ソート・ディスクへの書き込みで遅延が発生していることを示しています。

大量のタスクが滞留しているなら、おそらくハードウェアかパラメータチューニングがボトルネックです。

jconsoleを使いたくないのであれば、nodetool tpstatsを実行することですべてのスレッドをダンプ出力できます。

例:

Pool Name                    Active   Pending      Completed
FILEUTILS-DELETE-POOL             0         0            119
MESSAGING-SERVICE-POOL            3         4       81594002
STREAM-STAGE                      0         0              3
RESPONSE-STAGE                    0         0       48353537
ROW-READ-STAGE                    0         0          13754
LB-OPERATIONS                     0         0              0
COMMITLOG                         1         0       78080398
GMFD                              0         0        1091592
MESSAGE-DESERIALIZER-POOL         0         0      126022919
LB-TARGET                         0         0              0
CONSISTENCY-MANAGER               0         0           2899
ROW-MUTATION-STAGE                1         2       81719765
MESSAGE-STREAMING-POOL            0         0            129
LOAD-BALANCER-STAGE               0         0              0
FLUSH-SORTER-POOL                 0         0            218
MEMTABLE-POST-FLUSHER             0         0            218
COMPACTION-POOL                   0         0            464
FLUSH-WRITER-POOL                 0         0            218
HINTED-HANDOFF-POOL               0         0            154

MX4Jによる監視

mx4jはJMXへのHTMLおよびHTTPインターフェースを提供します。Cassandra 0.7.0よりmx4jをより簡単に統合できます。 Cassandraノードでmx4jを有効にする手順は次の通りです:

http://cassandra:8081/ にアクセスすればHTMLインターフェースが使用できます。

XMLが必要ならURLの最後に&template=identityを追加して下さい。(例: http://cassandra:8081/?&template=identity

詳細は次のURLを参照して下さい。 https://issues.apache.org/jira/browse/CASSANDRA-1068

stats

Operations_JP (last edited 2013-11-14 23:39:21 by GehrigKunz)