時々、特に開発ビルドのリリース間で、Couchbase Serverのいくつかのコンポーネントに問題があるため、結果が失われるという可能性があります。このセクションでは、どのコンポーネントか、もしくはどのコンポーネントが失敗していないかを識別するためにデバッグする方法について説明します。
先に進む前に、ファイルシステム内の1ファイルに正確に対応した(couchstoreコンポーネントによって作成された)CouchDBデータベースによって、各vbucketが物理的に表現されているということに言及する必要があり、(たとえば、簡単にするために)16 vbucketsのみを使用した4ノードとレプリカなしの開発環境の例を以下に示します。
shell> tree ns_server/couch/0/ ns_server/couch/0/ ??? _replicator.couch.1 ??? _users.couch.1 ??? default ??? 0.couch.1 ??? 1.couch.1 ??? 2.couch.1 ??? 3.couch.1 ??? master.couch.1 ??? stats.json 1 directory, 8 files shell> tree ns_server/couch/1/ ns_server/couch/1/ ??? _replicator.couch.1 ??? _users.couch.1 ??? default ??? 4.couch.1 ??? 5.couch.1 ??? 6.couch.1 ??? 7.couch.1 ??? master.couch.1 ??? stats.json ??? stats.json.old 1 directory, 9 files shell> tree ns_server/couch/2/ ns_server/couch/2/ ??? _replicator.couch.1 ??? _users.couch.1 ??? default ??? 10.couch.1 ??? 11.couch.1 ??? 8.couch.1 ??? 9.couch.1 ??? master.couch.1 ??? stats.json ??? stats.json.old 1 directory, 9 files shell> tree ns_server/couch/3/ ns_server/couch/3/ ??? _replicator.couch.1 ??? _users.couch.1 ??? default ??? 12.couch.1 ??? 13.couch.1 ??? 14.couch.1 ??? 15.couch.1 ??? master.couch.1 ??? stats.json ??? stats.json.old 1 directory, 9 files
この特定の例では(./cluster_connect -n 4 -r 0
を実行した)レプリカは無効
なので、各ノードはその責任範囲であるvbuckets(アクティブvbuckets)のデータベースファイルのみを持っています。各データベースファイル名の数字の接尾辞は、データベースファイルが作成されたときに1から開始され、vbucketがコンパクションされるたびに1ずつ増加します。例えば、./cluster_connect -n 4 -r 1
を実行するなどして、レプリケーションが有効になっている場合、各ノードは責任範囲内のvbucket(アクティブvbuckets)のためと、いくつかのレプリカvbucketsのためのvbucketデータベースファイルを持っています:
shell> tree ns_server/couch/0/ ns_server/couch/0/ ??? _replicator.couch.1 ??? _users.couch.1 ??? default ??? 0.couch.1 ??? 1.couch.1 ??? 12.couch.1 ??? 2.couch.1 ??? 3.couch.1 ??? 4.couch.1 ??? 5.couch.1 ??? 8.couch.1 ??? master.couch.1 ??? stats.json 1 directory, 12 files shell> tree ns_server/couch/1/ ns_server/couch/1/ ??? _replicator.couch.1 ??? _users.couch.1 ??? default ??? 0.couch.1 ??? 1.couch.1 ??? 13.couch.1 ??? 4.couch.1 ??? 5.couch.1 ??? 6.couch.1 ??? 7.couch.1 ??? 9.couch.1 ??? master.couch.1 ??? stats.json 1 directory, 12 files shell> tree ns_server/couch/2/ ns_server/couch/2/ ??? _replicator.couch.1 ??? _users.couch.1 ??? default ??? 10.couch.1 ??? 11.couch.1 ??? 14.couch.1 ??? 15.couch.1 ??? 2.couch.1 ??? 6.couch.1 ??? 8.couch.1 ??? 9.couch.1 ??? master.couch.1 ??? stats.json 1 directory, 12 files shell> tree ns_server/couch/3/ ns_server/couch/3/ ??? _replicator.couch.1 ??? _users.couch.1 ??? default ??? 10.couch.1 ??? 11.couch.1 ??? 12.couch.1 ??? 13.couch.1 ??? 14.couch.1 ??? 15.couch.1 ??? 3.couch.1 ??? 7.couch.1 ??? master.couch.1 ??? stats.json 1 directory, 12 files
次のURLのクエリを実行することにより、どのvbucketが各ノード上でアクティブかがわかります:
shell> curl -s http://localhost:9000/pools/default/buckets | json_xs [ { "quota" : { "rawRAM" : 268435456, "ram" : 1073741824 }, "localRandomKeyUri" : "/pools/default/buckets/default/localRandomKey", "bucketCapabilitiesVer" : "", "authType" : "sasl", "uuid" : "89dd5c64504f4a9414a2d3bcf9630d15", "replicaNumber" : 1, "vBucketServerMap" : { "vBucketMap" : [ [ 0, 1 ], [ 0, 1 ], [ 0, 2 ], [ 0, 3 ], [ 1, 0 ], [ 1, 0 ], [ 1, 2 ], [ 1, 3 ], [ 2, 0 ], [ 2, 1 ], [ 2, 3 ], [ 2, 3 ], [ 3, 0 ], [ 3, 1 ], [ 3, 2 ], [ 3, 2 ] ], "numReplicas" : 1, "hashAlgorithm" : "CRC", "serverList" : [ "192.168.1.81:12000", "192.168.1.82:12002", "192.168.1.83:12004", "192.168.1.84:12006" ] }, (....) ]
検査のためのフィールドにはvBucketServerMap
という名前が付けられており、そしてそれはvBucketMap
とserverList
という名前の2つの重要なサブフィールドを含み、どのノードがどのvbuckets(アクティブvbuckets)の責任範囲かを調べるために使用されます。
これらの2つのフィールドを確認すると、次のアクティブおよびレプリカvbucketをノードへマッピングすることができます。
vbuckets 0、1、2と3はノード192.168.1.81:12000でアクティブであり、vbuckets 4、5、8、12はその同じノードではレプリカです
vbuckets 4、5、6、7は、ノード192.168.1.82:12002でアクティブであり、vbuckets 0,1、9と13は、同じノードではレプリカです
vbuckets 8、9、10および11は、ノード192.168.1.83:12004でアクティブであり、vbuckets 2、6、14と15は、同じノードではレプリカです
vbuckets 12、13、14および15は、ノード192.168.1.84:12006アクティブであり、vbucketの3、7、11、10は、同じノードではレプリカです
vBucketMap
の値は2つの要素の配列の配列です。各サブ配列がvbucketに対応しているので、最初のものはvbucketの0、次のものはvbucketの1、など、最後のものはvbucketの15に関連しています。各サブ配列要素は、serverList
配列へのインデックス(0から始まる)です。各サブ配列の最初の要素は、どのノードがアクティブとしてマークされたvbucketに対応しているかをを示し、二番目の要素がどのサーバがレプリカとしてマークされたvbucketを持っているを示しています。
レプリケーション因子が1よりも大きい場合(N>1)には、各サブ配列は、N+1の要素をもち、最初の要素は、常にvbuketをアクティブとしているサーバ/ノードのインデックスとなり、残りの要素は1番目、2番目、3番目など、vbucketのレプリカを持っているサーバのインデックスとなります。
どのvbucketsが各ノードでアクティブになっているか知った後、アクティブなvbucketデータベースのファイルを分析するため、couch_dbinfo
とcouch_dbdump
のようないくつかのツールを使用することができます。それらのツールを見ていく前に、まずデータベースのシーケンス番号が何であるかを調べましょう。
CouchDBのデータベース(それぞれがvbucketに対応していることを忘れないでください)が作成されると、そのupdate_seq(更新シーケンス番号)は0となります。ドキュメントが作成、更新または削除されるとき、その現在のシーケンス番号が1ずつインクリメントされます。だから、次のアクションのシーケンスのすべてが、5の最終シーケンス番号になります:
ドキュメントdoc1を作成し、ドキュメントdoc2を作成し、ドキュメントdoc3を作成し、ドキュメントdoc4を作成し、ドキュメントdoc5を作成する
ドキュメントdoc1を作成し、ドキュメントdoc1を更新し、ドキュメントdoc1を更新し、ドキュメントdoc1を更新し、ドキュメントdoc1を削除する
ドキュメントdoc1を作成し、ドキュメントdoc1を削除し、ドキュメントdoc2を作成し、ドキュメントdoc2を更新し、ドキュメントdoc2を更新する
ドキュメントdoc1を作成し、ドキュメントdoc2を作成し、ドキュメントdoc3を作成し、ドキュメントdoc4を作成し、ドキュメントdoc2を更新する
などなど
他の情報の中で、couch_dbinfo
コマンドラインツールを使用して、vbucketデータベースのファイルの現在のupdate_seqを見ることができ、たとえば、最初のノードでアクティブなvbucketの0を使用した例は次の通りです:
shell> ./install/bin/couch_dbinfo ns_server/couch/0/default/0.couch.1 DB Info (ns_server/couch/0/default/0.couch.1) file format version: 10 update_seq: 31250 doc count: 31250 deleted doc count: 0 data size: 3.76 MB B-tree size: 1.66 MB total disk size: 5.48 MB
vbucketデータベース内のすべてのドキュメントを更新した後、update_seqは倍増します:
shell> ./install/bin/couch_dbinfo ns_server/couch/0/default/0.couch.1 DB Info (ns_server/couch/0/default/0.couch.1) file format version: 10 update_seq: 62500 doc count: 31250 deleted doc count: 0 data size: 3.76 MB B-tree size: 1.75 MB total disk size: 10.50 MB
重要なのは、明白ではない場合、各vbucketデータベースのシーケンス番号に、1つそしてただ1つのドキュメントIDが関連付けられているということです。いつでも、ドキュメントIDに関連付けられている1つの更新シーケンス番号があり、常に最新状態となっています。couch_dbdump
コマンドラインツールを使用してこのドキュメントIDを確認することができます。ID doc1というドキュメントとID doc2というドキュメントの2つのドキュメントだけをもつ、以下の例を見てください。
shell> ./install/bin/couch_dbdump ns_server/couch/0/default/0.couch.1 Doc seq: 1 id: doc1 rev: 1 content_meta: 0 cas: 130763975746, expiry: 0, flags: 0 data: {"value": 1} Total docs: 1
空のvbucket 0 データベースで、{"value": 1}
のJSON値を持っているIDdoc1
のドキュメントを作成します。このドキュメントは現在更新シーケンス番号1に関連付けられています。次に{"value": 2}
のJSONの値を持っているID *doc2* の別のドキュメントを作成すると、couch_dbdump
の出力は次の通りです:
shell> ./install/bin/couch_dbdump ns_server/couch/0/default/0.couch.1 Doc seq: 1 id: doc1 rev: 1 content_meta: 0 cas: 130763975746, expiry: 0, flags: 0 data: {"value": 1} Doc seq: 2 id: doc2 rev: 1 content_meta: 0 cas: 176314689876, expiry: 0, flags: 0 data: {"value": 2} Total docs: 2
ドキュメントdoc2
は、vbucket 0 データベースの更新シーケンス番号2に関連付けられています。次に{"value": 1111}
の新しいJSONの値でドキュメントdoc1
を更新すると、couch_dbdump
は次を示します。
shell> ./install/bin/couch_dbdump ns_server/couch/0/default/0.couch.1 Doc seq: 2 id: doc2 rev: 1 content_meta: 0 cas: 176314689876, expiry: 0, flags: 0 data: {"value": 2} Doc seq: 3 id: doc1 rev: 2 content_meta: 0 cas: 201537725466, expiry: 0, flags: 0 data: {"value": 1111} Total docs: 2
ドキュメントdoc1
は現在、更新シーケンス番号3に関連付けられています。更新がドキュメントに対する最新の操作となるため、もはやシーケンス番号1には関連付けられていないことに注意してください。(3つの操作のみ可能であることを忘れないでください:作成、更新、または削除)同様にデータベースはもはやシーケンス番号1のレコードがありません。この後、{"value": 2222}
のJSON値でドキュメントdoc2
をアップデートすると、couch_dbdump
から以下のような出力を得ます:
shell> ./install/bin/couch_dbdump ns_server/couch/0/default/0.couch.1 Doc seq: 3 id: doc1 rev: 2 content_meta: 0 cas: 201537725466, expiry: 0, flags: 0 data: {"value": 1111} Doc seq: 4 id: doc2 rev: 2 content_meta: 0 cas: 213993873979, expiry: 0, flags: 0 data: {"value": 2222} Total docs: 2
ドキュメントdoc2
は今シーケンス番号4に関連付けられていて、データベースファイルにはもはやシーケンス番号2のレコードがありません。最後に、ドキュメントdoc1
を削除すると、次のような情報が得られます:
shell> ./install/bin/couch_dbdump ns_server/couch/0/default/0.couch.1 Doc seq: 4 id: doc2 rev: 2 content_meta: 0 cas: 213993873979, expiry: 0, flags: 0 data: {"value": 2222} Doc seq: 5 id: doc1 rev: 3 content_meta: 3 cas: 201537725467, expiry: 0, flags: 0 doc deleted could not read document body: document not found Total docs: 2
ドキュメントの削除は実際にはデータベースファイルからドキュメントを削除せず、その代わりに、そのドキュメントが削除されたというフラグをつけ、そのJSON(またはバイナリ)の値を削除するということに注意してください。ドキュメントdoc1
は今では、シーケンス番号5に関連付けられており、以前のシーケンス番号3に関連付けられたレコードはvbucket 0 データベースファイルから削除されています。これによって例えば、削除操作に関連付けられた更新シーケンス番号がないので、インデックスはドキュメントが削除されたかどうか知るための方法を持っていませんが、削除されたドキュメントのmap関数で以前に出力されてたすべてのキーバリューペアが削除されなければならないことをインデックスは知ることができます。
シーケンス番号やドキュメント操作の詳細によって、インデックスはCouchbase Server(そして同様にApache CouchDB)内で増分更新することができます。
Couchbase Serverでは、インデックスは各vbucket データベースで参照される最新のupdate_seqをヘッダ(状態)内に格納しています。簡単に言えば、インデックスの構築/更新が完了したかどうかは、各vbucketデータベースが処理するヘッダ内の最新のupdate_seqに格納します。vbucket データベースは状態もインデックス内に持っており、その状態はサーバ内のvbucket状態と必ずしも一致していません。このwikiページの目的としては、インデックスヘッダ内に現在格納されているアクティブなvbucketのupdate_seqが対応するvbucketデータベースの現在のupdate_seqよりも小さい場合のみ、stale=false
を使用したビューのリクエストはブロックされるということを言及することだけが重要で、 - もし少なくとも1つのアクティブなvbucketでこれがtrueであれば、(まだ実行中でない場合)インデックス更新はすぐさまスケジュールされ、完了したとき、リクエストをアンブロックします。もし他の状態 (passive, cleanup, replica) のインデックス内のvbucketsのupdate_seqが対応するvbucketデータベースの現在のupdate_seqよりも小さければ、stale=false
のリクエストはブロックされません。 - 理由としては、クエリはアクティブvbucketsに存在するドキュメントから生成される行だけ参照しているということです。
次のURLでクエリを実行することによって、インデックス内のvbucketsの状態とインデックス内のupdate_seqsを参照できます(単純化のために、16 vbucketsのみの例):
shell> curl -s 'http://localhost:9500/_set_view/default/_design/dev_test2/_info' | json_xs { "unindexable_partitions" : {}, "passive_partitions" : [], "compact_running" : false, "cleanup_partitions" : [], "replica_group_info" : { "unindexable_partitions" : {}, "passive_partitions" : [ 4, 5, 8, 12 ], "compact_running" : false, "cleanup_partitions" : [], "active_partitions" : [], "pending_transition" : null, "db_set_message_queue_len" : 0, "out_of_sync_db_set_partitions" : false, "expected_partition_seqs" : { "8" : 62500, "4" : 62500, "12" : 62500, "5" : 62500 }, "updater_running" : false, "partition_seqs" : { "8" : 62500, "4" : 62500, "12" : 62500, "5" : 62500 }, "stats" : { "update_history" : [ { "deleted_ids" : 0, "inserted_kvs" : 38382, "inserted_ids" : 12794, "deleted_kvs" : 38382, "cleanup_kv_count" : 0, "blocked_time" : 1.5e-05, "indexing_time" : 3.861918 } ], "updater_cleanups" : 0, "compaction_history" : [ { "cleanup_kv_count" : 0, "duration" : 1.955801 }, { "cleanup_kv_count" : 0, "duration" : 2.443478 }, { "cleanup_kv_count" : 0, "duration" : 4.956397 }, { "cleanup_kv_count" : 0, "duration" : 9.522231 } ], "full_updates" : 1, "waiting_clients" : 0, "compactions" : 4, "cleanups" : 0, "partial_updates" : 0, "stopped_updates" : 0, "cleanup_history" : [], "cleanup_interruptions" : 0 }, "initial_build" : false, "update_seqs" : { "8" : 62500, "4" : 62500, "12" : 62500, "5" : 62500 }, "partition_seqs_up_to_date" : true, "updater_state" : "not_running", "data_size" : 5740951, "cleanup_running" : false, "signature" : "440b0b3ded9d68abb559d58b9fda3e0a", "max_number_partitions" : 16, "disk_size" : 5742779 }, "active_partitions" : [ 0, 1, 2, 3 ], "pending_transition" : null, "db_set_message_queue_len" : 0, "out_of_sync_db_set_partitions" : false, "replicas_on_transfer" : [], "expected_partition_seqs" : { "1" : 62500, "3" : 62500, "0" : 62500, "2" : 62500 }, "updater_running" : false, "partition_seqs" : { "1" : 62500, "3" : 62500, "0" : 62500, "2" : 62500 }, "stats" : { "update_history" : [], "updater_cleanups" : 0, "compaction_history" : [], "full_updates" : 0, "waiting_clients" : 0, "compactions" : 0, "cleanups" : 0, "partial_updates" : 0, "stopped_updates" : 0, "cleanup_history" : [], "cleanup_interruptions" : 0 }, "initial_build" : false, "replica_partitions" : [ 4, 5, 8, 12 ], "update_seqs" : { "1" : 31250, "3" : 31250, "0" : 31250, "2" : 31250 }, "partition_seqs_up_to_date" : true, "updater_state" : "not_running", "data_size" : 5717080, "cleanup_running" : false, "signature" : "440b0b3ded9d68abb559d58b9fda3e0a", "max_number_partitions" : 16, "disk_size" : 5726395 }
サーバの問題を診断するのに有用ないくつかのフィールドが出力されます。フィールドreplica_group_info
は、このwikiの目的を無視し(フェイルオーバ中だけ有用となるでしょう)、含まれている情報はトップレベルの情報と類似しており、メインで主要なインデックスのためのもので、安定状態の間やリバランスの間に注意するべきものです。
トップレベルのフィールドのいくつかとその意味は次のとおりです:
active_partitions
- これは、インデックス内のアクティブとしてマークされたすべてのvbucketsのIDのリストです。
passive_partitions
- これは、インデックス内のパッシブとしてマークされたすべてのvbucketsのIDのリストです。
cleanup_partitions
- これは、インデックス内のクリーンアップとしてマークされたすべてのvbucketsのIDのリストです。
compact_running
- インデックスの圧縮が継続中であればtrue、そうでなければfalse。
updater_running
- インデックスの構築/更新が継続中であればtrue、そうでなければfalse。
update_seqs
- これによって、インデックスがデータを反映したvbucketデータベースに何が起こっているのかがわかります。キーはvbucketのIDで、値がupdate_seqsです。ここではupdate_seqsは、partition_seqs
とexpected_partition_seqs
の値より小さいか、または等しくなります。ここでupdate_seqの値がpartition_seqs
または、expected_partition_seqs
で対応する値よりも小さくなる場合、インデックスは最新でなく(古くなっており)、後続のstale=false
を伴ったクエリはブロックされ、(まだ実行されていない場合)インデックス更新が発生するということを意味します。
partition_seqs
- これにより、各vbucketデータベースの現在のupdate_seqsが何であるかがわかります。ここでupdate_seqの値がupdate_seqs
内の対応する値よりも大きい場合、インデックスが最新ではない(古い)といえます。上記のupdate_seqs
の説明を参照してください。
expected_partition_seqs
- これは通常partition_seqs
(上記参照)とまったく同じです。インデックスの各プロセスはvbucketデータベースの更新を監視したり、現在のupdate_seqsを追跡するのに最適化されており、このためインデックスがこれらの情報を知る必要があるとき、データベースからこれらの情報を取り出す(パフォーマンスの観点から高い、高負荷な処理をする)必要がありません。このフィールドのupdate_seqsは、各データベース・ファイルを参照することによって得られます。partition_seqs
内の対応する値と一致しない場合、ビューエンジンに問題があるといえます。
unindexable_partitions
- このフィールドは、リバランス時のみ空ではありません。このメタ状態 "unindexable"にあるvbucketsは、インデックスの更新はこれらvbucketsを無視することを意味します。この状態への遷移とこの状態からの遷移は、リバランス中のビューの一貫性のためにns_serverによって使用されます。リバランス中でない場合、このフィールドは常に空となり、そうでない場合、どこかに問題があるということになります。空でない場合のこのフィールドのための値は、キーがvbucketのIDで、値はupdate_seqsというオブジェクトになります。
このURLによって得られる情報を使用して(ノード単位であることを忘れないでください)、couch_dbinfo
とcouch_dbdump
ツールと一緒に(アクティブなvbucketデータベースのファイルすべてに対して)、vbucketの状態やインデックスされたupdate_seqsを確認することで、どこに(どのコンポーネントに)問題があるのかデバッグすることができます。たとえば、最新のデータ/更新/削除処理でインデックスされていないインデックスがあるかどうか、memcached/ep-engineレイヤーがディスクへのデータ永続化/更新がしているかどうか、couchstore(データベースファイルに書き込むコンポーネント)でデータベースファイルにデータを書き込まない、もしくは間違ったデータを書き込むような問題がないかどうか、を調べるのに役に立ちます。
これらのツールやURL/_set_view/bucketname/_design/ddocid/_infoからの情報を使用して、どのコンポーネントがおかしな振る舞いをしているのかを調べることがとても重要であるという例はhttp://www.couchbase.com/issues/browse/MB-5534にあります。このケースではトミーは、問題がep-engineにあったことを識別することができました。