6.1 略語の戦い: BASE vs. 酸
「化学では、pH は水溶液の相対的な酸性度を測定します。pH スケールは 0 (強酸性物質) から 14 (強アルカリ性物質) まであり、25°C の純水の pH は 7 で中性です。 データ エンジニアは、トランザクションの信頼性に関してデータベースを比較するためにこの比喩を採用しています。」 おそらく、考えられたのは、pH が高いほど、つまり、データベースが「アルカリ」(「BASE」) に近づくほど、トランザクションの信頼性は低くなります。 |
MySQL などの一般的なリレーショナル データベースは、まさに ACID に基づいて登場しました。しかし、過去 10 年間、いわゆる NoSQL データベースは、この名前でいくつかの非常に異なるタイプのデータベースを組み合わせたもので、ACID がなくてもかなりうまく機能しました。実際、NoSQL データベースを使用していて、トランザクションとその信頼性をまったく気にしていない開発者が多数います。それらが正しいかどうか見てみましょう。
NoSQL データベースについて一般的に語ることはできません。それは単に優れた抽象化にすぎないからです。NoSQL データベースは、データ ストレージ サブシステムの設計、さらにはデータ モデルにおいても互いに異なります。NoSQL は、ドキュメント指向の CouchDB とグラフ Neo4J の両方です。しかし、トランザクションのコンテキストでそれらについて話す場合、それらは 1 つの点で似ている傾向があります。つまり、それらは限定されたバージョンのアトミック性と分離性を提供するため、ACID 保証は提供しません。これが何を意味するかを理解するために、「ACID ではない場合、何が提供されるのでしょうか?」という質問に答えてみましょう。なし?
あまり。結局のところ、リレーショナル データベースと同様に、それらも美しいパッケージで販売する必要があります。そして彼らは独自の「化学」の略語であるBASEを思いつきました。
6.2 アンタゴニストとしてのBASE
ここでも文字の順番ではなく、基本的な用語である一貫性から始めます。この一貫性は ACID からの一貫性とはほとんど関係がないため、認識効果を平準化する必要があります。一貫性という用語の問題は、それがあまりにも多くの文脈で使用されていることです。しかし、この一貫性はより広い範囲で使用されており、実際、これはまさに分散システムを議論するときに議論される一貫性です。
上で説明したリレーショナル データベースは、さまざまなレベルのトランザクション分離を提供しており、最も厳密なものでは、あるトランザクションが別のトランザクションによって行われた無効な変更を認識できないことが保証されています。あなたが店のレジに立っていて、その瞬間に家賃のお金が口座から引き落とされたが、家賃の送金トランザクションが失敗し、あなたの口座が以前の価値に戻った場合(お金は引き落とされない)、その場合、チェックアウト時の支払いトランザクションは、これらのジェスチャに誰も気づかなくなります。結局のところ、そのトランザクションは決して完了せず、トランザクション分離の要件に基づいて、その一時的な変更は他のトランザクションによって認識されません。
多くの NoSQL データベースは分離保証を省略し、最終的には有効なデータが表示される「結果整合性」を提供しますが、トランザクションが無効な値、つまり一時的な値、部分的に更新された値、または古い値を読み取る可能性があります。読み取り時に「遅延」モード (「読み取り時に遅延」) でデータの一貫性が保たれる可能性があります。
NoSQL はリアルタイム分析用のデータベースとして考案され、高速化を実現するために一貫性を犠牲にしました。そして、BASEという用語を作ったのと同じ人物であるエリック・ブリュワーは、いわゆる「CAP定理」を定式化しました。それによると、次のようになります。
分散コンピューティングの実装では、次の 3 つのプロパティのうち 2 つだけを提供できます。
- データの一貫性 (一貫性) - 異なるノード (インスタンス) 上のデータは互いに矛盾しません。
- 可用性 ( availability ) - 分散システムへのリクエストはすべて正しい応答で終了しますが、すべてのシステム ノードの応答が同じであるという保証はありません。
- パーティション トレランス(パーティション トレランス) - ノード間に接続がない場合でも、ノードは互いに独立して動作し続けます。
CAP について非常に簡単に説明したい場合は、ここを参照してください。
CAP 定理は機能せず、一般的に定式化が抽象的すぎるという意見があります。いずれにしても、NoSQL データベースは、CAP 定理のコンテキストで一貫性を拒否することがよくあります。これは、次の状況を説明します。データは複数のインスタンスを持つクラスター内で更新されましたが、変更はすべてのインスタンスでまだ同期されていません。上で DynamoDB の例について言及したことを思い出してください。変更は永続的になりました - ここに HTTP 200 があります - しかし、変更は 10 秒後にしか確認できませんでした。開発者の日常生活からのもう 1 つの例は、DNS (ドメイン ネーム システム) です。知らない人のために説明すると、これはまさに http アドレスを IP アドレスに変換する「辞書」です。
更新された DNS レコードは、キャッシュ間隔の設定に従ってサーバーに伝達されるため、更新はすぐにはわかりません。同様の一時的な不整合 (つまり、最終的な整合性) がリレーショナル データベース クラスター (MySQL など) にも発生する可能性があります。結局のところ、この整合性は ACID からの整合性とは何の関係もありません。したがって、この意味では、クラスター内の複数のインスタンスに関しては、SQL データベースと NoSQL データベースが大きく異なる可能性は低いことを理解することが重要です。
さらに、エンドツーエンドの一貫性は、書き込みリクエストが順不同で行われることを意味する場合があります。つまり、すべてのデータが書き込まれますが、最終的に受信される値は書き込みキューの最後の値ではありません。
非 ACID NoSQL データベースには、エンドツーエンドの整合性モデルにより、いわゆる「ソフト状態」があり、これは、入力がなくてもシステムの状態が時間の経過とともに変化する可能性があることを意味します。しかし、このようなシステムは、より優れたアクセシビリティを提供しようと努めています。100% の可用性を提供することは簡単な作業ではないため、ここでは「基本的な可用性」について説明します。そして、「基本的に利用可能」、「ソフトステート」 (「ソフトステート」)、「最終整合性」という 3 つの概念を合わせて、頭字語 BASE を形成します。
正直に言うと、BASE の概念は、ACID よりも空虚なマーケティング ラッパーであるように私には思えます。なぜなら、BASE は何も新しいものを提供せず、データベースをまったく特徴づけないからです。また、特定のデータベースにラベル (ACID、BASE、CAP) を付けると、開発者が混乱するだけです。データベースを勉強するときにこの用語を回避するのは難しいため、とにかくこの用語を紹介することにしました。しかし、それが何であるかを理解したので、できるだけ早く忘れてほしいと思います。そして、孤立の概念に戻りましょう。
6.3 では、BASE データベースは ACID 基準をまったく満たしていないということですか?
基本的に、ACID データベースが非 ACID と異なる点は、非 ACID では実際に分離が行われないことです。これを理解することが重要です。しかし、データベースのドキュメントを読んで、Hermitage プロジェクトの人々が行っている方法でテストすることはさらに重要です。あれやこれやのデータベースの作成者が、自らの発案を ACID か BASE、CAP か CAP でないかを正確にどのように呼ぶかは、それほど重要ではありません。重要なことは、このデータベースまたはそのデータベースが正確に何を提供するかということです。
データベースの作成者が ACID 保証を提供していると主張している場合、これにはおそらく理由がありますが、実際にそれが保証されているかどうか、またどの程度保証されているかを理解するには、自分でテストすることをお勧めします。彼らのデータベースがそのような保証を提供していないと宣言した場合、これは次のことを意味する可能性があります。
-
DB はアトミック性を保証しません。一部の NoSQL データベースはアトミック操作用に別の API を提供します (DynamoDB など)。
- DB は分離性を保証しません。これは、たとえば、データベースがデータを書き込まれた順序で書き込まないことを意味する場合があります。
耐久性の保証に関しては、多くのデータベースはパフォーマンスのためにこの点で妥協しています。ディスクへの書き込みは操作に時間がかかりすぎるため、この問題を解決するにはいくつかの方法があります。データベース理論にはあまり立ち入りたくないですが、どの方法で調べればよいのかを大まかに理解できるように、さまざまなデータベースが耐久性の問題をどのように解決するかを一般的な用語で説明します。
さまざまなデータベースを比較するには、特に、特定のデータベースのデータ保存および取得サブシステムの基礎となるデータ構造を知る必要があります。つまり、データベースが異なれば、インデックス作成、つまりデータへのアクセスの編成の実装も異なります。それらの中には、より速くデータを書き込むことができるものや、より速くデータを読み取ることができるものもあります。ただし、一部のデータ構造によって耐久性が高くなるか低くなるかは一概に言えません。
6.4 さまざまなデータベースがデータのインデックスを作成する方法と、それが耐久性にどのような影響を与えるかなど
データの保存と取得には、主に 2 つのアプローチがあります。
データを保存する最も簡単な方法は、ログのような方法でファイルの末尾に操作を追加することです (つまり、追加操作が常に発生します)。データを追加、変更、削除するかどうかは関係ありません。 CRUD 操作は単純にログに書き込まれます。ログの検索は非効率的です。そこでインデックスが登場します。インデックスは、データが保存されている正確な場所に関するメタデータを保存する特別なデータ構造です。ログの最も単純なインデックス付け戦略は、キーと値を追跡するハッシュ マップです。値は、ファイル内に書き込まれるデータのバイト オフセットへの参照になります。これはログ (ログ) であり、ディスクに保存されます。このデータ構造は完全にメモリに保存されますが、データ自体はディスク上にあり、LSM ツリー (ログ構造化マージ) と呼ばれます。
あなたはおそらく、「私たちの業務を常にジャーナルに書き込むと、そのジャーナルは法外に増大するのではないか?」と疑問に思ったことでしょう。はい。そこで、一定の周期性を持ってデータを「クリーンアップ」する、つまり各キーに最も関連性の高い値のみを残すか削除する、圧縮技術が発明されました。また、ディスク上に複数のログがあり、それらがすべてソートされている場合、SSTable (「ソートされた文字列テーブル」) と呼ばれる新しいデータ構造が得られ、これにより間違いなくパフォーマンスが向上します。メモリ内でソートしたい場合、同様の構造、いわゆる MemTable が得られますが、問題は、致命的なデータベースクラッシュが発生した場合、最後に書き込まれたデータ (MemTable にあるものの、まだ書き込まれていない) であることです。ディスク)を紛失してしまいました。実際、
インデックス付けのもう 1 つのアプローチは、B ツリー (「B ツリー」) に基づいています。B ツリーでは、データは固定サイズのページでディスクに書き込まれます。これらのデータ ブロックのサイズは多くの場合約 4 KB で、キーごとにソートされたキーと値のペアが含まれています。1 つの B ツリー ノードは、さまざまなページへのリンクを含む配列のようなものです。最大。配列内のリンクの数は分岐係数と呼ばれます。各ページ範囲は、他のページ範囲へのリンクを持つ別の B ツリー ノードです。
最終的には、シート レベルで個々のページが表示されます。この考え方は、これらのページ参照がメモリではなくディスクに保存されることを除けば、低レベル プログラミング言語のポインタに似ています。データベース内で INSERT と DELETE が発生すると、分岐要素に一致するように一部のノードが 2 つのサブツリーに分割される可能性があります。プロセスの途中で何らかの理由でデータベースに障害が発生した場合、データの整合性が損なわれる可能性があります。これを防ぐために、B ツリーを使用するデータベースは、すべてのトランザクションが記録される「先行書き込みログ」(WAL) を維持します。この WAL は、B ツリーが破損した場合にその状態を復元するために使用されます。そして、これが B-tree を使用したデータベースの耐久性の点で優れていると思われます。ただし、LSM ベースのデータベースは、基本的に WAL と同じ機能を実行するファイルを維持することもできます。したがって、これまでに述べたことを、おそらく複数回繰り返します。選択したデータベースの操作メカニズムを理解してください。
ただし、B ツリーについて確かなことは、トランザクション性に優れているということです。各キーはインデックス内の 1 か所でのみ出現しますが、ジャーナル処理されたストレージ サブシステムは、異なるシャードに同じキーの複数のコピーを持つことができます (たとえば、次の圧縮が実行されます)。
ただし、インデックスの設計はデータベースのパフォーマンスに直接影響します。LSM ツリーではディスクへの書き込みは順次行われ、B ツリーでは複数のランダムなディスク アクセスが発生するため、書き込み操作は B ツリーよりも LSM の方が高速です。この違いは磁気ハードディスク ドライブ (HDD) で特に顕著であり、シーケンシャル書き込みはランダム書き込みよりもはるかに高速です。LSM ツリーでは、圧縮のさまざまな段階にあるいくつかの異なるデータ構造と SS テーブルを調べる必要があるため、読み取りが遅くなります。さらに詳しく言うとこんな感じです。LSM を使用して単純なデータベース クエリを作成する場合、まず MemTable 内のキーを検索します。そこにない場合は、最新の SSTable を調べます。そこにない場合は、最後から 2 番目の SSTable を調べます。要求されたキーが存在しない場合、LSM を使用すると、これが最後にわかります。LSM ツリーは、LevelDB、RocksDB、Cassandra、HBase などで使用されます。
データベースを選択する際には、さまざまなことを考慮する必要があることを理解していただけるよう、すべてを詳細に説明します。たとえば、データの書き込みと読み取りのどちらがより多く行われると考えられるかなどです。データ モデルの違いについてはまだ言及していません (グラフ モデルで許可されているように、データをトラバースする必要がありますか? データ内の異なる単位間に何らかの関係はありますか。その場合、リレーショナル データベースが役に立ちますか?)。 2 種類のデータ スキーマ - 書き込み時 (多くの NoSQL など) と読み取り時 (リレーショナルなど)。
耐久性の側面に戻ると、結論は次のようになります。インデックス作成メカニズムに関係なく、ディスクに書き込むデータベースはデータの耐久性を十分に保証できますが、特定のデータベースごとに対処する必要があります。 、それが正確に何を提供するか。
6.5 インメモリ DB の仕組み
ちなみに、ディスクに書き込むデータベースに加えて、主に RAM で動作するいわゆる「インメモリ」データベースもあります。つまり、インメモリ データベースは通常、書き込み速度と読み取り速度を速くするために耐久性が低くなりますが、アプリケーションによってはこれが適切な場合もあります。
実際のところ、RAM メモリは長い間ディスクよりも高価でしたが、最近では急速に安価になり始めており、新しいタイプのデータベースが誕生しています。RAM からのデータの読み書き速度を考慮すると、これは当然のことです。しかし、これらのデータベースのデータの安全性はどうなっているのかと疑問に思うのは当然です。ここでも、実装の詳細を確認する必要があります。一般に、このようなデータベースの開発者は次のメカニズムを提供します。
- バッテリ駆動の RAM を使用できます。
- 変更ログをディスク (前述の WAL のようなもの) に書き込むことは可能ですが、データ自体を書き込むことはできません。
- データベース状態のコピーを定期的にディスクに書き込むことができます (他のオプションを使用しないと、保証はされませんが、耐久性が向上するだけです)。
- RAM の状態を他のマシンにレプリケートできます。
たとえば、主にメッセージ キューまたはキャッシュとして使用されるインメモリ Redis データベースには、ACID による耐久性がありません。Redis はデータをディスクにフラッシュするため、正常に実行されたコマンドがディスクに保存されるという保証はありません (永続性が有効になっている)、定期的に非同期でのみ実行されます。
ただし、これはすべてのアプリケーションにとって重要なわけではありません。EtherPad 連携オンライン エディタの例を見つけましたが、これは 1 ~ 2 秒ごとにフラッシュされ、ユーザーは数文字または単語を失う可能性がありましたが、これはほとんど重要ではありませんでした。それ以外の場合、インメモリ データベースは、ディスク インデックスを使用して実装するのが難しいデータ モデルを提供するという点で優れているため、Redis を使用してトランザクションを実装できます。その優先キューを使用すると、これが可能になります。