データはどのようにして読み取られるか

DataStax Enterpriseが、読み取り要求を満たすために、アクティブなmemtableと複数の可能性があるSSTableの結果を組み合わせる方法。

DataStax Enterprise(DSE)データベースは、読み取り要求を満たすために、アクティブなmemtableと複数の可能性があるSSTableの結果を組み合わせる必要があります。memtableに目的のパーティション・データが含まれている場合は、そのデータが読み取られ、SSTableからのデータとマージされます。

このデータベースは、memtableのデータから開始してSSTableで終わるまで、読み取りパスの複数の段階でデータを処理して、データが格納されている場所を見つけます。
  1. memtableをチェックします
  2. 行キャッシュが有効な場合は、それをチェックします
  3. ブルーム・フィルターをチェックします
  4. チャンク・キャッシュ/メモリー内のパーティション・インデックス内のパーティション・オフセットを検索します
  5. 必要なインデックス・データがキャッシュに存在しない場合は、ディスクからデータを取り出します
  6. 圧縮されていないチャンク・キャッシュからデータを読み取ります
  7. 必要なデータ・チャンクがキャッシュに存在しない場合は、次の操作を行います。
    1. 圧縮オフセット・マップを使用して、ディスク上のデータを見つけます
    2. ディスク上のSSTableからデータをチャンク・キャッシュにフェッチします
1. 読み取り要求フロー

行キャッシュ

どのようなデータベースでも、最も需要があるデータがメモリーに入っているときに読み取りが最速になります。負荷の95%を読み取り操作が占めるような読み取りが非常に多い操作は、行キャッシュによってある程度改善されますが、OSのページ・キャッシュはパフォーマンスの向上に最適です。書き込みが多い操作では、行キャッシュはお勧めしません。行キャッシュが有効な場合は、ディスク上のSSTableに格納されているパーティション・データのサブセットがメモリーに格納されます。DataStax Enterprise 5.0以降では、行キャッシュは、Java仮想マシン(JVM)のガーベージ・コレクション圧力を軽減する実装方法を使用して、完全なオフヒープ・メモリーに格納されます。行キャッシュに格納されたサブセットは、指定された時間、構成可能なメモリー量を使用します。キャッシュが満杯になると、行キャッシュはLRU(最も長く使用されていない)排除方式に従ってメモリーを再要求します。

行キャッシュのサイズは、格納する行の数として構成できます。格納する行数を構成すると、「最後の10項目」のクエリーの読み取りが非常に速くなるため便利です。行キャッシュが有効な場合は、希望するパーティション・データが行キャッシュから読み取られ、そのデータを探すディスクへの2回のシークが節約される可能性があります。行キャッシュに格納される行は、アクセス頻度の多い行で、アクセスされたときにSSTableから行キャッシュにマージされて保存されます。格納後は、そのデータが後続のクエリーに利用されます。行キャッシュはライトスルーではありません。その行に対する書き込み要求があった場合、その行のキャッシュは無効にされて、読み取りが行われるまで、再度キャッシュされることはありません。同様に、パーティションが更新されると、そのパーティション全体がキャッシュから削除されます。目的のパーティション・データが行キャッシュで見つからない場合は、bloom filterがチェックされます。

ブルーム・フィルター

各SSTableにはブルーム・フィルターが関連付けされており、SSTableが特定のパーティション・データを含まないようにすることができます。また、ブルーム・フィルターは、キーのプールを絞り込むことでパーティション・データがSSTableに格納される可能性を判断できます。これによりパーティション・キーの検索が増加します。

DSEデータベースは、ブルーム・フィルターをチェックして、要求されたパーティション・データが存在する可能性があるSSTableを見つけます。ブルーム・フィルターでSSTableが見つからない場合、DSEデータベースはパーティション・インデックスをチェックします。ブルーム・フィルターによって識別されたすべてのSSTableにデータが存在するわけではありません。ブルーム・フィルターは確率的な機能であるため、偽陽性の結果を返す可能性があります。

ブルーム・フィルターはオフヒープ・メモリーに格納され、10億パーティション当たり約1~2ギガバイト(GB)まで拡大します。極端なケースでは、各行がパーティションを持つことができるため、1台のマシンで簡単に数十億のエントリーを持つことができます。パフォーマンスとメモリーをトレードするには、ブルーム・フィルタを調整します。

パーティション・インデックス

パーティション・インデックスは、パーティション・キーを行インデックスにマップし、必要に応じて部分的に指定されたパーティション位置からの反復をサポートします。データベース・パーティションのサイズは、多くの場合さまざまです。パーティション・インデックスのトライ木データ構造では、一意のバイト順序のパーティション・キー・プレフィックスを使用して次を指します。
  • 大きなパーティションを持つテーブルの行インデックス
  • 数行または1行だけを含むパーティションを持つテーブルのファイル内のデータ位置を直接

トライ木のリーフに到達した場合、パーティション・キーのプレフィックスはファイル内の一部のコンテンツと一致しますが、それがパーティション・キーの完全な一致かどうかは不明です。リーフ・ノードは、行インデックスまたはデータ・ファイル内の場所を指します。いずれの場合も、指定された位置の最初のバイトにはパーティション・キーのシリアライズが含まれます。これはマップされたキーと比較されます。それが一致すると、パーティションが見つかります。一致しない場合、格納されているプレフィックスが一意であるため、このパーティションのデータはSSTableに存在しません。

チャンク・キャッシュ内の非圧縮データ(メモリー)

チャンク・キャッシュは、データがSSTableに圧縮および書き込まれる前にデータをバッファリングします。データを読み取るとき、非圧縮データが最初にチェックされます。データが圧縮されてディスク上にある場合、このプロセスでは圧縮オフセット・マップを使用してディスク上のデータを特定して、SSTableをメモリーに圧縮解除します。「コンパクション」を参照してください。

圧縮オフセット・マップ

圧縮オフセット・マップには、目的のパーティション・データが見つかると予想されるディスク上の正確な場所を指すポインターが格納されています。この場所はオフヒープ・メモリーに格納され、パーティション・キー・キャッシュまたはパーティション・インデックスによってアクセスされます。圧縮オフセット・マップがディスクの場所を特定した後、目的の圧縮パーティション・データが正しいSSTableからフェッチされます。次にそのクエリーによって結果セットを受け取ります。
注: パーティション内では、すべての行がクエリーに対して負担が等しいわけではありません。パーティションの先頭(キー定義によってクラスター化されている最初の行)は、パーティション・レベルのインデックスを調べる必要がないため、クエリーの負担がやや低くなります。

圧縮オフセット・マップは、圧縮状態でテラバイト(TB)ごとに1~3ギガバイト(GB)まで拡大します。より多くのデータが圧縮されるほど、より多くの圧縮ブロック数が必要になり、圧縮オフセット・テーブルが大きくなります。圧縮オフセット・マップの参照によりCPUリソースが使用されますが、圧縮はデフォルトで有効になっています。圧縮を有効にしておくと、ページ・キャッシュの効率が上がり、一般に検索時間が短縮されます。