このドキュメントについて

HBase は ACID 準拠データベースではありません。ただし、HBase が保証している特定のプロパティもいくつかあります。

ここでは、HBase の ACID プロパティを列挙します。

定義

用語についての共通理解を得るために、以下の語については定義を示した上で使用します。

アトミック性 (Atomicity)
ある操作がすべて完了するか、またはまったく完了しないかのいずれかになる場合、その操作はアトミックである
一貫性 (Consistency)
すべてのアクションにおいて、テーブルはある有効な状態から別の有効な状態へと直接遷移する (更新中に行が失われることはない、など)
独立性 (Isolation)
ある操作が、同時に行われるほかのあらゆるトランザクションから独立して完了するように見える場合、その操作は独立している
永続性 (Durability)
クライアントに“成功”と報告されたどの更新も、失われることはない
可視性 (Visibility)
更新がその後のどの読み取りによってもコミットされたものとして見える場合、その更新は可視状態であるとみなされる

しなければならない (must)」と「することがある (may)」という語は、RFC 2119 で規定されている意味で使われています。簡単に言えば、「しなければならない (must)」という語は、そこで言明されている内容が真でないケースがある場合、それがバグであることを暗に意味しています。「することがある (may)」という語は、たとえ現在のリリースで保証が提供されていても、ユーザーはそのことを全面的に信用すべきでないことを暗に意味しています。

関連 API

  • 読み取り API
    • get
    • scan
  • 書き込み API
    • put
    • バッチ put
    • delete
  • 読み書き (読み取り-修正-書き込み) API
    • incrementColumnValue
    • checkAndPut

保証されること

アトミック性

  1. すべての変更は、1 つの行内ではアトミックです。あらゆる put は、全体が成功するか、全体が失敗するかのいずれかです。
    1. “成功”コードを返す操作は、完全に成功しています。
    2. “失敗”コードを返す操作は、完全に失敗しています。
    3. タイムアウトする操作は、成功していることもあれば、失敗していることもあります。ただし、部分的に成功していたり、部分的に失敗していたりすることはありません。
  2. 上のことは、変更が、ある行の中の複数の列ファミリにまたがる場合でも真です。
  3. 複数の行を変更する API は、対象となる複数の行の全体でアトミックになるわけではありません。たとえば、行 'a'、'b'、および 'c' を対象とする multiput は、一部の行だけを変更し、変更がすべての行に及ばない状態で返ることがあります。このような場合、これらの API は成功コードのリストを返し、リスト内のそれぞれのコードは、すでに説明したように、成功、失敗、またはタイムアウトのいずれかになります。
  4. checkAndPut API は、多くのハードウェアアーキテクチャにみられる典型的な compareAndSet (CAS) 操作のように、アトミックに実行されます。
  5. 複数の変更は、行ごとに明確に定義された順序で行われることになっており、変更の順序がちぐはぐになることはありません。たとえば、ある writer が "a=1,b=1,c=1" とする変更を発行し、別の writer が "a=2,b=2,c=2" とする変更を発行した場合、変更の対象となった行は "a=1,b=1,c=1" か、"a=2,b=2,c=2" のいずれかにならなければならず、"a=1,b=2,c=1" のような状態になることはありえません
    1. これは、複数行を対象としたバッチ変更において、対象となる複数の行の全体に対しても真であるわけではない点には注意してください。

一貫性と独立性

  1. 任意のアクセス API を経由して返された行はいずれも、テーブルの履歴の中のある 1 点において存在していた完全な行です。
  2. このことは、複数の列ファミリに対してもあてはまります。すなわち、1 行全体を get する操作を、いくつかの変更 1,2,3,4,5 と並行して実行した場合、返される行は、1 から 5 までの間のある i に対し、i から i+1 までの間のある 1 点において存在していた完全な行です。
  3. ある行の状態は、その行に対する編集の履歴の中で、前方へ向かってのみ進んでいきます。

scan の一貫性

scan は、あるテーブルの一貫したビューではありません。scan にはスナップショットの独立性ありません

その一方で、scan には次のプロパティがあります。

  1. scan によって返されたどの行も、一貫したビューになります (すなわち、そのバージョンの完全な行は、過去のある 1 点において存在していた行です)[1]。
  2. scan には、少なくともその scan 操作の開始時と等しい新しいデータのビューが必ず反映されます。このことによって、以下で取り上げる可視性の保証が満たされます。
    1. たとえば、クライアント A がデータ X を書き込み、ついでサイドチャネルを経由してクライアント B に通知した場合、クライアント B によって開始されたすべての scan には、少なくとも X に等しい新しいデータが含まれます。
    2. scan は、scanner の構築以前にコミットされたすべての変更を反映 *していなければならず*、scanner の構築後にコミットされた変更の一部を反映 *していることがあります*。
    3. scan は、scan に先立って書き込まれたすべてのデータを含んでいなければなりません (データがその後に変更された場合は除きます。この場合、scan はこの変更を反映 *していることがあります*)。

リレーショナルデータベースについての知識があるユーザーは、この独立性レベル (分離レベル) が「READ COMMITTED」であることがわかるでしょう。

scanner の一貫性に関して上に挙げた保証は、「トランザクションのコミット時間」についてのものであって、各セルの“timestamp”フィールドについてのものではありません。すなわち、時間 t において開始された scanner では、もしその scanner の構築以前に行われた編集があって、その編集が「時計を先に進めた」 timestamp を使ってコミットされている場合、t よりも大きな timestamp 値を持つ編集が見えることがあります。

可視性

  1. クライアントがある変更から“成功”応答を受け取った場合、その変更は、そのクライアントと、そのクライアントがサイドチャネルを経由してあとで通知したほかのクライアントのどちらにも、ただちに可視状態になります。
  2. 行が、いわゆる「タイムトラベル」プロパティを示すことは決してありません。すなわち、一連の変更によって、ある行が一連の状態を順番にたどっていく場合、並行する読み取りが連続して行われると、これらの読み取りで返されるのは、行がたどる状態のサブシーケンスになります。
    1. たとえば、ある行の複数のセルが "incrementColumnValue" API を使って変更される場合、いずれかのセルの値が減少する現象がクライアントから見えることは決してありません。
    2. これは、変更内容を読み直すのにどの読み取り API が使われるかにかかわらず、真です。
  3. 読み取り操作に対して返されたセルのどのバージョンも、永続的に格納されていることが保証されます。

永続性

  1. 可視状態のすべてのデータは、永続性のあるデータでもあります。すなわち、読み取りによって、ディスク上に永続化されていないデータが返されることは決してありません[2]。
  2. “成功”コードを返す (例外をスローしないなど) すべての操作は永続化されます。
  3. “失敗”コードを返すすべての操作は永続化されません (上に示したアトミック性の保証の条件に従います)。
  4. 妥当な失敗のシナリオはいずれも、このドキュメントで示している保証のどれにも影響を与えません。

調整可能性 (Tunability)

上に挙げた保証のすべては、HBase 内では可能でなければなりません。一部の保証をパフォーマンスとトレードオフしたいユーザー向けに、HBase はいくつか調整のためのオプションを提供していることがあります。次に例を示します。

  • 可視性は読み取りごとに調整することができるので、古い無効な読み取り (stale read) やタイムトラベルを許容することができます。
  • 永続性は調整できますが、その結果得られることは、データを定期的にディスクにフラッシュすることだけです。

脚注

[1] 一貫したビューは、行内 scan 操作 (intra-row scanning) では保証されません。行内 scan 操作とは、ある RPC において 1 行の一部を取得し、ついで、続く RPC においてその行の別の一部を取得する操作をいいます。行内 scan 操作は、Scan#next ごとに返す値の数を制限している場合に発生します (Scan#setBatch(int) を参照してください)。

[2] HBase のコンテキストにおいては、「ディスク上に永続化される」という表現は、トランザクションログに対して hflush() が呼び出されたことを意味しています。これは実際には、磁気メディアに対する fsync() を意味しているのではなく、ログのすべてのレプリカ上で OS のキャッシュにデータが書き込まれたことを意味しています。したがってデータセンター全体で停電が起きた場合、編集内容は本来の意味で永続的ではない可能性があります。