やる気
通常のRDBMSシステムとは対照的に、 CAP定理と呼ばれる定式化されたヒューリスティックルールがある場合、NoSQLソリューションのクラスがACIDを完全にサポートできないことは誰にとっても秘密ではありません。 多くのタスクではこれは必要ではなく、要素の1つをサポートすることで、残りの解決に妥協をもたらすことになります 。その結果、さまざまな既存のソリューションが必要になります。 この記事では、トランザクションシステムの要件を部分的に提供するという問題を解決するためのさまざまなアーキテクチャアプローチを検討します。
「A」原子性
アトミック性により、トランザクションがシステムに部分的にコミットされないことが保証されます。 彼女のすべてのサブオペレーションが完了するか、単一のサブオペレーションが完了しないかのいずれかです。
NoSQLシステムは通常、トランザクションのセマンティクスではなく、高いパフォーマンスを選択します。NoSQLシステムを使用すると、処理コストが追加されるためです。 多くのシステムは、キーまたは行レベルの保証(Google BigTable)を提供するか、アトミックオペレーション用のAPI(Amazon DynamoDB)を提供します。 。 ほとんどのシステムは、非ブロッキングの読み取り-変更-書き込みループに準拠しています。 サイクルは、値の読み取り、変更、書き込みの3つの段階で構成されます。 ご覧のとおり、マルチスレッド環境では、たとえば読み取りと書き込みのフェーズの間に誰かがレコードを変更した場合など、多くの問題が発生する可能性があります。 このような競合を解決する主なメカニズムは、 Compare and Swapアルゴリズムの使用です。サイクル中に誰かがレコードを変更した場合、レコードが変更されたことを理解し、値が確立されるまでサイクルを繰り返す必要があります。書き込みロック機構。 このようなサイクルの数は非常に多くなる可能性があるため、操作には一定のタイムアウトが必要であり、その後は操作が拒否されます。
「C」の一貫性
トランザクションは正常に完了し、その結果を修正して、データベースの一貫性を維持します。 サーバー間で情報を配布するためのNoSQLの仕様を考えると、これは、データのコピーを含むすべてのレプリカが常に同じバージョンのデータを含むことを意味します
仕様により、最新のNoSQLは高可用性とクラスターを水平にスケーリングする機能を選択する必要があります。システムは完全なデータ整合性を提供できず、整合性の定義にいくつかの仮定を立てていることがわかります。 2つのアプローチがあります。
厳格な一貫性
このようなシステムにより、ユーザーに返されるデータの単一バージョンについてレプリカが常に同意できるようになります。 レプリカの中にはこの値を含まないものもありますが、システムがキーによる値の要求を処理するとき、マシンは常にどの値を返すかを決定できます-常に最後であるとは限りません。 仕組み-たとえば、同じキーのレプリカがN個あります。 キー値を更新する要求が来ると、 Wレプリカが更新を受信したと応答するまで、システムは結果をユーザーに提供しません。 ユーザーが値を要求すると、少なくともRレプリカが同じ値を返したときに、システムはユーザーに応答を返します。 次に、条件R + W> Nが満たされる場合、システムは厳密に一貫していると見なします。 RとWの値の選択は、回答がユーザーに返される前に回答するマシンの数に影響します。通常は、 R + W = N + 1の条件が選択されます-厳密な一貫性を確保するための最小必要条件。
可能な一貫性
一部のシステム( Voldemort、Cassandra、Riak ) では、 R + W <NであるRおよびWを選択できます。 ユーザーが情報を要求すると、システムがキー値のバージョン間の競合を解決できない場合があります。 競合を解決するために、ベクトルクロックと呼ばれるバージョン管理タイプが使用されます。 これは、各レプリカの変更カウンターを含む各キーに関連付けられたベクトルです。 サーバーA 、 B 、およびCを同じキーのレプリカとすると、ベクトルには3つの値(N_A、N_B、N_C)が含まれ、最初は(0,0,0)に初期化されます。 レプリカがキーの値を変更するたびに、ベクトル内のカウンターの値が増加します。 Bが以前にバージョン(39、1、5)を持っていたキーの値を変更すると、ベクトルはその値を(39、2、5 )に変更します。 別のレプリカ( Cなど)がレプリカBから更新を受け取ると、ベクトルの値とそれ自体の値を比較します。 すべてのベクトルカウンタがBからのものよりも少ない限り、表示される値は安定したバージョンになり、独自のコピーを上書きできます。 (39、2、5)および(39、1、6 )のように、一部のカウンターが大きく、一部のカウンターが小さいBおよびCのベクトルがある場合、システムは競合を識別します。
この競合の解決はシステムによって異なるため、Voldemortは値のコピーをいくつか返し、ユーザーに競合の解決を提供します。 サイト上のユーザーバスケットの2つのバージョンは情報を失うことなくマージできますが、1つの編集可能なドキュメントの2つのバージョンをマージするにはユーザーの介入が必要です。 各レコードのタイムスタンプを保存するCassandraは、競合が検出されると最新の情報を返します。この方法では、情報を失うことなく2つのバージョンをマージすることはできませんが、クライアント部分は簡素化されます。
「私」の分離
トランザクション中、同時トランザクションは結果に影響を与えません。 ここでは、トランザクション分離レベルの概念も重要です。
バージョン1.1以降のCassandraでは、更新を行うと次のことが保証されます。
UPDATE Users
SET login='login' AND password='password'
WHERE key='key'
競合する読書ではデータの部分的な更新は表示されません(ログインは変更されていますが、パスワードは変更されていません)。これは、同じ列ファミリ内にあり、共通キーを持つ行レベルでのみ当てはまります。 これは、 失われた更新の競合が解決される、 コミットされていない読み取りトランザクション分離レベルに対応する場合があります。 しかし、 Cassandraはクラスターレベルでロールバックメカニズムを提供しません。たとえば、ログインとパスワードが特定の数のノードに保存されるが、ユーザーに正しい結果を与えるのに十分なWではなく、ユーザーがこの競合を自分で解決するように強制される状況が可能です。 分離を保証するメカニズムは、変更される各レコードに対して、非表示の分離されたクライアントバージョンが作成され、その後、上記の比較およびスワップメカニズムによって古いバージョンが自動的に置き換えられることです。
「D」信頼性
下位レベルの問題(たとえば、システムの停電や機器の誤動作)に関係なく、正常に完了したトランザクションによる変更は、システムが仕事に戻った後も保存されたままでなければなりません。 言い換えると、ユーザーがシステムからトランザクションが完了したという確認を受け取った場合、ユーザーが行った変更が障害のためにキャンセルされないことを確認できます。
最も予測される障害シナリオは、停電またはサーバーの再起動です。 この場合、完全に信頼できるシステムは、メモリからハードディスクにすべての変更を書き込むまで、ユーザーに応答を返すべきではありません。 ディスクへの書き込みが長すぎるため、多くのNoSQLシステムがパフォーマンスを低下させます。
同じサーバーで信頼性を提供する
標準ディスクは、毎秒70〜150回の操作に耐えることができます。これは、最大150 Mb / s、ssd-700 Mb / s、DDR-6000-17000 Mb / sのスループットに相当します。 したがって、1台のサーバー内で信頼性を確保しながら高いパフォーマンスを確保するには、ランダムアクセスでレコードの数を減らし、順次記録を増やします。 理想的には、システムはfsync呼び出し(メモリおよびディスク上のデータ同期)間のレコード数を最小限に抑える必要があります。 これには、いくつかの手法が使用されます。
Fsync周波数制御
Redisは、 fsyncをいつ呼び出すかを構成するいくつかの方法を提供します。 レコードを変更するたびに呼び出されるように構成できます。これは、最も遅くて安全な選択です。 パフォーマンスを改善するために、 N秒ごとにディスクへのフラッシュを行うことができます。最悪の場合、最後のN秒でデータが失われますが、これは一部のユーザーにとっては許容範囲です。 信頼性がまったく重要でない場合は、fsyncを無効にし、ある時点でシステム自体がディスクとメモリを同期するという事実に依存することができます。
ロギングにより順次記録を増やす
効果的なデータの取得のために、NoSQLシステムは多くの場合、インデックスを構築するためのBツリーなどの追加の構造を使用し、それを操作するとディスクへの複数のランダムアクセスが発生します。 これを減らすために、一部のシステム( Cassandra、HBase、Riak )は、 redo logと呼ばれる順次書き込まれるファイルに更新操作を追加します 。 一部の構造はめったにディスクに書き込まれませんが、ログは頻繁に書き込まれます。 落下後、ログを使用して不足しているエントリを復元できます。
レコードをグループ化して帯域幅を増やす
Cassandraは 、短いウィンドウで複数の同時変更をグループ化し、1つのfsyncに結合できます。 group commitと呼ばれるこのアプローチでは、1人のユーザーの応答時間が長くなります。 彼は他のいくつかのトランザクションを修正するのを待たなければなりません。 ここでの利点は、全体的なスループットを増加させることにより得られます。 複数のランダムエントリを組み合わせることができます。
サーバークラスターの信頼性の確保
ディスクとサーバーの予期しない障害の可能性があるため、複数のマシン間で情報を配布する必要があります。
Redisは、データ複製用の古典的なマスタースレーブアーキテクチャです。 マスターに関連付けられているすべての操作は、ログの形式でレプリカになります。
MongoDBは、指定された数のサーバーが各ドキュメントを格納する構造です。上記のサーバー数W <Nを設定することができます。これは、制御を記録してユーザーに返すために最小限必要です。
HBaseは、分散HDFSファイルシステムの使用により、マルチサーバーの信頼性を実現します。
一般に、データの一貫性を高める傾向にある現代のNoSQLツールの傾向に気付くことができます。 しかし、それでもSQLとNoSQLツールは存在し、並行して開発でき、まったく異なる問題を解決できます。