コンピュータサイエンスにおいて、ACID(原子性、一貫性、分離性、耐久性)とは、エラー、停電、その他の不測の事態が発生してもデータの妥当性を保証することを目的とした、データベーストランザクションの特性の集合です。例えば、ある銀行口座から別の銀行口座への資金移動は、一方の口座から引き落とし、もう一方の口座に入金するなど、複数の変更を伴いますが、これは単一のトランザクションです。
1983年、[ 1 ]アンドレアス・ロイターとテオ・ハーダーは、ジム・グレイ[ 2 ]による以前の研究に基づいてACIDという頭字語を作り出しました。グレイはトランザクションの概念を特徴づける際に、原子性、一貫性、耐久性を挙げましたが、分離性は挙げませんでした。これら4つの特性はトランザクションパラダイムの主要な保証であり、データベースシステムの開発の多くの側面に影響を与えています。
GrayとReuterによると、IBM情報管理システムは1973年には既にACIDトランザクションをサポートしていた(ただし、この頭字語は後から作られた)。[ 3 ]
BASE は、基本的に利用可能で、状態が柔らかく、最終的に一貫性があることを意味します。この頭字語は、BASE がACIDの反対であることを強調しています。これは、化学的に同等の酸と塩基のようなものです。ACID データベースは可用性よりも一貫性を優先します。トランザクション内のいずれかのステップでエラーが発生すると、トランザクション全体が失敗します。対照的に、BASE データベースは一貫性よりも可用性を優先します。トランザクションを失敗させる代わりに、ユーザーは一時的に一貫性のないデータにアクセスできます。データの一貫性は達成されますが、すぐには達成されません。データベースは ACID または BASE のいずれかに偏っており、両方になることはできません ( CAP 定理による)。たとえば、SQLデータベース ( MySQL、PostgreSQL、AWS Redshiftなど) は ACID モデルに基づいて構築されていますが、NoSQLデータベース ( DynamoDB [ 4 ]やMongoDBなど) は BASE アーキテクチャを使用しています。ただし、一部の NoSQL データベースは特定の ACID 特性を示す場合があります。[ 5 ]
ロイターとハーダーによって定義されたこれら4つの特性の特徴は以下のとおりです。
トランザクションは多くの場合、複数のステートメントで構成されます。アトミック性は、各トランザクションが単一の「単位」として扱われ、完全に成功するか完全に失敗するかのどちらかであることを保証します。トランザクションを構成するステートメントのいずれかが完了に失敗すると、トランザクション全体が失敗し、データベースは変更されません。アトミックシステムは、停電、エラー、クラッシュなど、あらゆる状況でアトミック性を保証しなければなりません。[ 6 ]アトミック性の保証により、データベースへの更新が部分的にしか行われないことが防止されます。これは、一連の更新全体を完全に拒否するよりも大きな問題を引き起こす可能性があります。結果として、トランザクションが進行中であることを他のデータベースクライアントから観測することはできません。ある時点ではまだ発生しておらず、次の時点では既に完全に発生しています(または、トランザクションが進行中にキャンセルされた場合は何も発生していません)。
一貫性により、トランザクションはデータベースをある一貫性のある状態から別の一貫性のある状態へしか移行できず、データベースの不変条件が維持されます。データベースに書き込まれるデータは、制約、カスケード、トリガー、およびそれらの組み合わせを含む、定義されたすべてのルールに従って有効でなければなりません。これにより、不正なトランザクションによるデータベースの破損が防止されます。データベースの不変条件の一例として、主キーと外部キーの関係を保証する参照整合性があります。[ 7 ]
トランザクションはしばしば並行して実行されます(たとえば、複数のトランザクションが同時にテーブルを読み書きする場合など)。分離性により、トランザクションの並行実行によってデータベースが、トランザクションが順次実行された場合と同じ状態に保たれることが保証されます。分離性は並行性制御の主な目的であり、使用される分離レベルによっては、未完了のトランザクションの影響が他のトランザクションから見えない場合があります。[ 8 ]
永続性とは、トランザクションが一度コミットされると、システム障害(停電やクラッシュなど)が発生した場合でもコミットされたままになることを保証するものです。これは通常、完了したトランザクション(またはその影響)が不揮発性メモリに記録されることを意味します。[ 9 ]
以下の例は、ACID特性をさらに詳しく説明するものです。これらの例では、データベーステーブルにはAとBの2つの列があります。整合性制約により、Aの値とBの値の合計は100でなければなりません。以下のSQLコードは、上記のようなテーブルを作成します。
CREATE TABLE acidtest ( A INTEGER , B INTEGER , CHECK ( A + B = 100 ));アトミック性とは、アトミック トランザクション内の一連のデータベース操作がすべて実行される(操作が成功)か、まったく実行されない(操作が失敗)かのいずれかであることを保証するものです。一連の操作は、一部だけが実行されるように分割することはできないため、一連の操作は「不可分」になります。アトミック性の保証により、データベースの更新が部分的にしか行われないことが防止され、これは一連の操作全体を完全に拒否するよりも大きな問題を引き起こす可能性があります。言い換えれば、アトミック性とは不可分性と還元不可能性を意味します。[ 10 ]あるいは、論理トランザクションは複数の物理トランザクションで構成されていると言うこともできます。すべての構成要素となる物理トランザクションが実行されるまで、論理トランザクションは発生しません。
アトミック トランザクションの例としては、銀行口座 A から口座 B への送金が挙げられます。これは、口座 A からお金を引き出し、口座 B に入金するという 2 つの操作から構成されます。口座 A から金額が引き落とされた後、口座 B にも送金されたことが確認されるまでは、その金額が口座 A から引き落とされたことを確認すべきではありません。これらの操作をアトミック トランザクションで実行することで、データベースが一貫した状態を維持することが保証されます。つまり、これらの 2 つの操作のいずれかが失敗した場合、お金は借方にも貸方にも計上されません。[ 11 ]
一貫性とは非常に一般的な用語で、データがすべての検証ルールを満たす必要があることを意味します。前の例では、検証はA + B = 100という要件です。一貫性を確保するには、すべての検証ルールをチェックする必要があります。トランザクションがBを変更せずにAから 10 を減算しようとするとします。一貫性は各トランザクションの後にチェックされるため、トランザクション開始前にA + B = 100であることがわかっています。トランザクションがAから 10 を正常に削除すれば、アトミック性が達成されます。しかし、検証チェックではA + B = 90となり、データベースのルールと矛盾することがわかります。トランザクション全体をキャンセルし、影響を受けた行をトランザクション前の状態にロールバックする必要があります。他の制約、トリガー、またはカスケードがあった場合、トランザクションがコミットされる前に、すべての変更操作が上記と同じ方法でチェックされます。他の制約でも同様の問題が発生する可能性があります。A と B の両方のデータ型が整数であることを要求している場合があります。例えば、Aに13.5という値を入力すると、トランザクションはキャンセルされるか、システムがトリガーの形でアラートを発生させる可能性があります(トリガーがそのような設定になっている場合)。別の例としては、整合性制約があります。これは、あるテーブルの主キーが他のテーブルの少なくとも1つの外部キーによって参照されている場合、そのテーブルの行を削除することを許可しないというものです。
分離性を示すために、2つのトランザクションが同時に実行され、それぞれが同じデータを変更しようとする場合を想定します。分離性を維持するためには、一方のトランザクションが他方のトランザクションの完了を待つ必要があります。
2つの取引について考えてみましょう。
これらを合わせると、4つの行動があります。
これらの操作が順番通りに実行されれば、T 2 は待機する必要があるものの、分離性は維持されます。T 1 が途中で失敗した場合を考えてみましょう。データベースは T 1の影響を排除し、T 2 は有効なデータのみを参照します。
トランザクションを交互に実行することで、実際のアクションの順序は次のようになる可能性があります。
ステップ4でT1がBを変更中に失敗した場合、何が起こるかを考えてみましょう。T1が失敗する時点で、T2はすでにAを変更しています。無効なデータベースを残さずに、T1の前にあった値に戻すことはできません。これは、2つのトランザクションが同じデータフィールドに書き込もうとしたため、書き込み競合として知られています[ 12 ] 。一般的なシステムでは、この問題は、最後に正常だった状態に戻り、失敗したトランザクションT1をキャンセルし、中断されたトランザクションT2を正常状態から再開することで解決されます。
AからBへ10を転送するトランザクションを考えてみましょう。まず、Aから10を削除し、次にBに10を追加します。この時点で、ユーザーにはトランザクションが成功したことが通知されます。しかし、変更内容はまだディスクバッファにキューイングされたままで、ディスクへの書き込みを待っています。停電が発生し、変更内容は失われますが、ユーザーは(当然ながら)変更内容が保持されていると想定します。
トランザクションの処理には、多くの場合、さまざまな理由で失敗する可能性のある一連の操作が必要です。たとえば、システムのディスク ドライブに空き容量がなかったり、割り当てられた CPU 時間を使い果たしたりする可能性があります。よく使われる手法には、ライト アヘッド ロギングとシャドウ ページングの 2 つの種類があります。どちらの場合も、更新するすべての情報に対してロックを取得する必要があり、分離レベルによっては、読み取られる可能性のあるすべてのデータに対してもロックを取得する必要がある場合があります。ライト アヘッド ロギングでは、データベースを変更する前に変更内容を永続ログに書き込むことで、永続性が保証されます。これにより、クラッシュが発生した場合でもデータベースを一貫性のある状態に戻すことができます。シャドウイングでは、更新はデータベースの部分的なコピーに適用され、トランザクションがコミットされたときに新しいコピーがアクティブ化されます。
多くのデータベースは、ACID特性を実現するためにロックに依存しています。ロックとは、トランザクションがアクセスするデータにマークを付けることで、DBMSが最初のトランザクションが成功または失敗するまで他のトランザクションによるデータの変更を許可しないようにする仕組みです。ロックは、読み取りのみで変更されないデータを含め、データを処理する前に必ず取得する必要があります。複雑なトランザクションは通常、多数のロックを必要とするため、オーバーヘッドが大きくなるだけでなく、他のトランザクションの実行もブロックされます。例えば、ユーザーAが、ユーザーBが変更したいデータ行を読み取るトランザクションを実行している場合、ユーザーBはユーザーAのトランザクションが完了するまで待たなければなりません。完全な分離を保証するために、 2相ロックがよく用いられます。
ロックの代替手段として、マルチバージョン同時実行制御があります。これは、データベースが各読み取りトランザクションに、別のアクティブなトランザクションによって変更されているデータの以前の未変更バージョンを提供するものです。これにより、読み取り側はロックを取得せずに操作できます。つまり、書き込みトランザクションが読み取りトランザクションをブロックせず、読み取り側が書き込み側をブロックしません。先の例に戻ると、ユーザー A のトランザクションがユーザー B が変更しているデータを要求すると、データベースはユーザー B がトランザクションを開始した時点で存在していたデータのバージョンを A に提供します。他のユーザーがデータを変更している場合でも、ユーザー A はデータベースの一貫したビューを取得できます。スナップショット分離と呼ばれる実装では、分離特性が緩和されます。
分散データベースを介した分散トランザクションにおいて、トランザクションに影響を与えるすべてのデータに対して単一のノードが責任を負わない場合、ACID 特性を保証することは、さらに複雑な問題を引き起こします。ネットワーク接続が失敗したり、あるノードがトランザクションの一部を正常に完了した後、別のノードの障害のために変更をロールバックする必要が生じる可能性があります。2相コミット プロトコル( 2 相ロックと混同しないように注意) は、分散トランザクションに原子性を提供し、トランザクションの各参加者がトランザクションをコミットするかどうかについて合意することを保証します。[ 13 ]簡単に言うと、第 1 相では、1 つのノード (コーディネーター) が他のノード (参加者) に問い合わせ、すべてのノードが準備完了と応答したときにのみ、コーディネーターが第 2 相でトランザクションを形式化します。
、Query、Scanなどの読み取り操作には、オプションの ConsistentRead パラメーターがあります。ConsistentRead を true に設定すると、DynamoDB は、成功した以前のすべての書き込み操作からの更新を反映した最新のデータを含むレスポンスを返します。
読み取り、書き込むことができる操作。これにより、操作が完了するまで、他のプロセッサやI/Oデバイスがメモリに書き込みや読み取りを行うことができなくなります。