データベースシステムⅠ 第9回 今日の話題 • 同時実行制御 – ロックとデッドロック • 障害回復 – 障害の分類 – ログを用いた障害回復 デッドロック(dead lock) • ロックを用いる同時実行制御を行う場合、複 数のトランザクションが互いのアンロックを 延々と待ち続け一切処理が進まない状態に なってしまうことがある – これを「デッドロック」という • ロックを用いるデータベースシステムでは、 デッドロック状態にないかどうかをチェックした り、デッドロック状態を解消したりする機構を 持つ必要がある デッドロックの例 • データベースにA、Bの2つの項目が格納され ているとする – トランザクションT1がAにロックをかけ、 Bがアンロックされるのを待っている – トランザクションT2がBにロックをかけ、 Aがアンロックされるのを待っている という状態になると、デッドロックである • 二相ロッキングプロトコルを使っていたとして も、デッドロックは起こりうる デッドロックが起こる スケジュールの例 • トランザクションT1 XL1(A) W1(A) XL1(B) W1(B) UL1(A) UL1(B) ここでデッド ロックが起こる • トランザクションT2 XL2(B) W2(B) XL2(A) W2(A) UL2(A) UL2(B) デッドロック状態 ロック中 A T1 アンロック待ち アンロック待ち T2 B ロック中 デッドロックの検出法 • 待ちグラフ(wait-for graph)による方法 – どのトランザクションがどのトランザクションのアン ロックを待っているかをグラフにしたもの – トランザクションTjがロックしている項目がアンロックさ れるのをトランザクションTiが待っているときTi→Tjの 有向エッジをひく – 待ちグラフにサイクル(閉路)ができたらデッドロック 状態 • タイムアウトによる方法 – トランザクションが一定時間以上アンロック待ちに なったら、「デッドロックの可能性がある」として、強制 的にアボートする 待ちグラフの例 T2 T1 T1 T3 T2 デッドロックの回避法 ① 一括ロックする方法 ② データを順序付ける方法 ③ トランザクションを順序付ける方法 ① 一括ロックする方法 • ロックする必要のある項目を、それぞれのトラ ンザクションがその開始時に一括してロックす る方法 • すべてのロックがとれなかったら、一切ロック せず、しばらく待ってから再度ロックを試みる • この方法と二相ロッキングプロトコルを組み 合わせたものを「保守的二相ロッキングプロト コル(conservative two phase locking)」という 通常の二相ロック トランザクション 開始 ロ ッ ク の 量 コミット 成長相 縮退相 保守的二相ロック 厳格な二相ロック 開始 コミット 時間 ② データを順序付ける方法 • 項目にある種の順序をつけておき、各トラン ザクションがロックをかける順序はこの順序を 守るようにする方法 ロック中 T1 1 2 3 アンロック待ち × T2 ③ トランザクションを 順序付ける方法 • トランザクション開始時刻の時刻印(timestamp) を使ってトランザクションに順序を導入し、待ち関 係のサイクルができないようにする方法 – ウェイト・ダイ方式 – ワウンド・ウェイト方式 • 以下、トランザクションTiの時刻印をTS(Ti)と書く ウェイト・ダイ(wait-die)方式 • トランザクションTiがある項目をロックしようとした とき、それと競合するロックが別のトランザクショ ンTjによってすでになされていたら、 – TS(Ti)<TS(Tj)であれば、 TiはTjがアンロックするのを待つ – TS(Ti)>TS(Tj)であれば、 Tiはアボートする • すなわち、Tiの開始が先ならアンロックされるの を待ち(wait)、そうでなければTiはアボートする (die) ウェイト・ダイ方式 Ti ロック Ti は Tj の アンロックを待つ Tj ロック Ti Ti はアボートする ロック Tj ロック ワウンド・ウェイト(wound-wait)方式 • トランザクションTiがある項目をロックしようとした とき、それと競合するロックが別のトランザクショ ンTjによってすでになされていたら、 – TS(Ti)<TS(Tj)であれば、 Tjをアボートさせる – TS(Ti)>TS(Tj)であれば、 TiはTjがアンロックするのを待つ • すなわち、Tiの開始が先ならロックを持っているTj をアボートさせ(wound)、そうでなければTiはア ンロックされるのを待つ(wait) ワウンド・ウェイト方式 Ti Tj をアボートさせる ロック Tj ロック Ti ロック Tj ロック Ti は Tj の アンロックを待つ ③ トランザクションを順序付ける方法 • ウェイト・ダイ方式でも、ワウンド・ウェイト方式で も、最小の時刻印を持つトランザクション(実行 中のトランザクションのうち、一番最初に始まっ たトランザクション)はアボートされることがない • したがって、アボートされたトランザクションに元 と同じ時刻印を与えて再実行すれば(いつか必 ず最小の時刻印になるので)、いずれはアボート されることなく実行されることが保証される アプリケーションプログラムの デッドロック対策 • デッドロックが発生するといずれかのトランザク ションが強制的にアボートされる • また、デッドロックを回避するためにトランザク ションが強制的にアボートされることもある • したがって、アプリケーションプログラムは原則と して、強制アボートが起こったらトランザクション を再開するようにプログラミングされる必要があ る • デッドロックの発生頻度を下げるため、トランザク ションを小さくする(こまめにコミットするようにす る)という手法はよく使われる 障害回復 • トランザクションのACID属性を完全に実現す るためには、データベースシステム稼働中に 何らかの障害が起こった場合の対処が必要 となる • このような機能のことを障害回復機能という 障害の分類 • トランザクション障害 • システム障害 • メディア障害 トランザクション障害 (transaction failure) • 個々のトランザクションが何らかの理由でコ ミットに至る前に異常終了するケース • 以下のような場合がある – 何らかの理由でトランザクションが自主的にア ボートする場合 – アプリケーションプログラムの実行時エラーにより 強制的に終了させられる場合 – デッドロックによりトランザクションの続行が不可 能な場合、など システム障害(system failure) • ハードウェアあるいはソフトウェア上の問題か らシステムダウンが発生し、その時点でのす べてのトランザクションが異常終了してしまう ケース • 障害発生時のすべての主記憶上のデータは 消滅するが、ディスクから障害発生直前の状 態のデータを読み出すことは可能であるので、 これを用いて復旧する メディア障害(media failure) • データベースを格納したディスクに障害が発 生し、データの読み出しができなくなるケース • 復旧にはバックアップとログを用いる(後述) トランザクションと障害回復 • トランザクション障害が発生した場合は、トランザクション はアボートされる – したがって、もしそのトランザクションが障害発生前にデータ ベースに書き込みを行っていたら、それを元の値に戻す処理を しなければならない • システム障害が発生した場合には、リスタート処理が行わ れる – 障害発生時点でコミット済であったトランザクションとそれ以外 のトランザクションによる基本操作を区別し、その後始末を行う 必要がある – コミット済のトランザクションによるデータの書き込みは確実に データベースに反映しなければならない – コミット済でないトランザクションは確実にアボートさせなければ ならない 基本操作とバッファリング • アプリケーションはデータベースシステムに対して read/writeの基本操作を要求する • データベースシステムは、効率よく処理するため(ディ スクアクセスの回数を減らすため)バッファリングを行 う – バッファの内容をディスクに書き戻す処理を「フラッシュ (flush)」という • したがって、アプリケーションがwriteを実行したからと いって、必ずしもその時点でその内容がディスクに書 き込まれているとは限らない • バッファリングされた内容がディスクに書き込まれる前 に(フラッシュされる前に)障害が起こると問題となる 基本操作とバッファリング read / write バッファ (主記憶) アプリケーション プログラム データベース データベースシステム アプリケーションのread/writeと データベースシステムのread/writeの タイミングは一致しない システム障害発生時 read / write バッファ (主記憶) アプリケーション プログラム データベース データベースシステム 障害が発生すると、 バッファの内容がすべて 失われる システム障害のケース begin read(A, x) read(B, y) x := x – 10000 y := y + 10000 write(A, x) write(B, y) commit AからBへの送金 ・ Aから出金 ・ Bに入金 ケース(1) ここで障害が起こった場合 ケース(2) ここで障害が起こった場合 ケース(1) write(A, x)の直後に障害 • writeは終わっているのでxの値はバッファに書き 込まれているが、障害が発生する前にそれが ディスクに書き戻されていたかどうかが問題とな る • ディスクに書き戻されているとすると、Aからの出 金は終わってるのにBへの入金が終わっていな いことになる→不整合状態 • ディスクに書き戻されていないとすると、Aからの 出金も終わっていないことになる • いずれにせよ、システムリスタート時には、トラン ザクション開始前の状態に戻す必要がある ケース(2) commitの直後に障害 • write(A, x)、write(B, y)は終わっているのでx, yの値はバッファには書き込まれたが、障害 が発生される前にそれがディスクに書き戻さ れていたかどうかが問題となる • トランザクションはコミット済であるので、たと えディスクに書き戻される前に障害が発生し ていたとしても、システムリスタート時の処理 でデータベースがコミット後の状態になること を保証しなければならない ログを用いた障害回復 • 障害回復を実現するために最も一般的に用いられる のはログ(log)を用いる手法である – ログのことをジャーナル(journal)ということもある • ログとは、すべてのトランザクションのすべての基本 操作の内容をディスク中に記録したものである – ログの個々の操作の記録を「ログレコード(log record)」と いう • ログを見ると、いつ、どのトランザクションが、データ ベースのどの項目に対してどういう操作を行ったか、 がわかる • 障害が発生したら、システムリスタート時にこのログを 使ってデータベースを正しい状態に戻す処理を行う ログレコードの内容 • トランザクションTiの開始: begin [ B: Ti ] • トランザクションTiによる書き込み: write(A, x) [ W: Ti, A, Old, New ] • Old: Aの更新前の値(ビフォアイメージ(before image)) • New: Aの更新後の値(アフターイメージ(after image)) • トランザクションTiによる読み出し: read(A, x) [ R: Ti, A ] • トランザクションTiのコミット: commit [ C: Ti ] • トランザクションTiのアボート: abort [ A: Ti ] • なお、それぞれのログレコードには、LSN(log sequence number)と いう番号を順に付ける トランザクションの実行とログ トランザクションT1 トランザクションT2 begin read(A, x) begin write(B, 150) commit read(B, y) write(A, 200) commit この例では、 トランザクションが 始まる前のAとBの 初期値はともに「100」 としている(before image) ログ 1: 2: 3: 4: 5: 6: 7: 8: [ B: T1 ] [ R: T1, A ] [ B: T2 ] [ W: T1, B, 100, 150 ] [ C: T1 ] [ R: T2, B ] [ W: T2, A, 100, 200 ] [ C: T2 ] これがLSN スケジュールとログレコード • ログレコードの種類はB(begin)、R(read)、W(write)、 C(commit)、A(abort)の5種類 • ここで、「厳格な二相ロッキングプロトコル」などにより、 トランザクションのスケジュールが厳格であることが保 証される場合を考える • すると、「あるトランザクションがアボートする結果とし て同じ項目をreadしている別のトランザクションを連鎖 的にアボートさせる」ということが起きないので、障害 発生時にreadのことを考慮する必要がなくなる • 以下ではそのような状況を考え、readは無視し、write だけ考えることとする ログ先書きプロトコル (write ahead log protocol, WAL) • 基本操作write(A, New)が行われた場合、Newの値が バッファリングされ、やがてその内容がディスク内の データベースに書かれる • この操作が行われるとき、ログレコード [ W: Ti, Old, New ] が記録されるが、この記録もディスク上のファイル(ロ グファイル)に書かれる • 障害発生時にOldの値が必要になる可能性があること を考えると、データベースにNewを書くよりもさきに、ロ グファイルに上記のログレコードが先に書かれている 必要がある • この方式を「ログ先書きプロトコル」という ログファイルとバッファリング • 通常、ログファイルへのログレコードの記録も バッファリングされる – 毎回ファイルに書き込むのではなく、必要な時に まとめてフラッシュする • データベースシステムではLSN(log sequence number)を用いて現在どのログレコードまで がディスクに書き込み済みかを管理する 障害回復の方式 • no-undo/redo方式 • undo/no-redo方式 • undo/redo方式 • 障害発生後の回復処理(リスタート時の処 理)で、実行中だったトランザクションの基本 操作を元に戻す処理を「undo」、やり直す処 理を「redo」という no-undo/redo方式 • 障害回復(リスタート)時にはredoのみ行い、undoは 行わない方式 • トランザクション中でのwrite操作はログにのみ記録し、 そのトランザクションがコミットするまでデータベース本 体への更新は一切行わない • どの段階で障害が発生しても、コミット済でないトラン ザクションの操作はデータベースに書き込まれていな いので、障害回復時にundoの必要がない(したがって ビフォアイメージの記録の必要がない) • 障害回復時には、コミット済であるのにデータベース に書き込みが終わっていなかった処理を、redoする no-undo/redo方式 通常時: トランザクション実行中 read / write × アプリケーション プログラム 実行時には データベースには 書き込まず、 ログにのみ 記録を残す データ用 バッファ [ B: Ti ] [ W: Ti, ・・・] データベース × ログ用バッファ データベースシステム ログファイル no-undo/redo方式 通常時: コミット時① read / write アプリケーション プログラム コミット時にはまず、 ログの内容を ログファイルに 記録する (これにより、 コミット済状態となる) データ用 バッファ データベース [ B: Ti ] [ W: Ti, ・・・] [ C: Ti ] ログ用バッファ データベースシステム ログファイル no-undo/redo方式 通常時: コミット時② read / write アプリケーション プログラム その後、 バッファを フラッシュして データベースを 更新する データ用 バッファ データベース [ B: Ti ] [ W: Ti, ・・・] [ C: Ti ] ログ用バッファ データベースシステム ログファイル no-undo/redo方式 障害回復時: コミット済でない場合 read / write アプリケーション プログラム コミット済でない場合 データベースには 何も書き込まれて いないので、 回復処理で何もする 必要がない データ用 バッファ データベース [ B: Ti ] [ W: Ti, ・・・] [ C: Ti ] ログ用バッファ データベースシステム ログファイル no-undo/redo方式 障害回復時: コミット済の場合 read / write アプリケーション プログラム コミット済の場合 データベースの更新が 終わっていない可能性が あるので、ログを使って redoする データ用 バッファ データベース [ B: Ti ] [ W: Ti, ・・・] [ C: Ti ] ログ用バッファ データベースシステム ログファイル undo/no-redo方式 • 障害回復(リスタート)時にはundoのみ行い、redoは 行わない方式 • no-undo/redo方式の逆 • トランザクション中でのwrite操作はすべてデータベー スに対して更新し、そのトランザクションがコミットする 前にすべてのデータベース本体への更新を行う • どの段階で障害が発生しても、コミット済のトランザク ションの操作はデータベースへの更新が終わっている ので、障害回復時にredoの必要がない(したがってア フターイメージの記録の必要がない) • 障害回復時には、コミット済でないトランザクションが 行ったデータベースへの更新をundoする undo/no-redo方式 通常時: コミット時 read / write アプリケーション プログラム コミット時にはデータ ベースへの更新を行い、 ログもログファイルに 記録する(これにより、 コミット済状態となる) データ用 バッファ データベース [ B: Ti ] [ W: Ti, ・・・] [ C: Ti ] ログ用バッファ データベースシステム ログファイル undo/no-redo方式 障害回復時: コミット済の場合 read / write アプリケーション プログラム コミット済の場合 データベースの更新は すべて終わっているので、 何もする必要がない データ用 バッファ データベース [ B: Ti ] [ W: Ti, ・・・] [ C: Ti ] ログ用バッファ データベースシステム ログファイル undo/no-redo方式 障害回復時: コミット済でない場合 read / write アプリケーション プログラム コミット済でない場合 データベースの更新が 終わってしまっている 可能性があるので、 ログを使ってundoする データ用 バッファ データベース [ B: Ti ] [ W: Ti, ・・・] [ C: Ti ] ログ用バッファ データベースシステム ログファイル no-undo/redo方式と undo/no-redo方式 • どちらもシンプルな方式ではあるが、「コミット 済になるまでバッファをフラッシュできない (no-undo/redo方式の場合)」、あるいは、「コ ミットする前には必ずすべての更新をデータ ベースに対して行わないといけない (undo/no-redo方式の場合)」という、制約が ある • そのため、実際には次に説明するundo/redo 方式を採用するのが主流となっている undo/redo方式 • 障害回復(リスタート)時に必要に応じてundo処 理もredo処理もどちらも行う方式 時間 ログ B1 B2 C1 障害発生 – T1は障害前にコミットしているので必要に応じて redoする – T2は障害前にコミットしていないので必要に応じて undoする undo/redo方式の詳細 • トランザクションの開始: begin – ログレコード [B: Ti ] をログ用バッファに書き込む • トランザクションによる書き込み: write(A, x) – ログレコード [ W: Ti, Old, New ] をログ用バッファに書き込む – データ用バッファで A を含むページを更新する • このページをディスクに書き込む場合は、その前にログ用バッファを 書き込む(ログ先書きプロトコル) • トランザクションのコミット: commit – ログレコード [ C: Ti ] をログ用バッファに書き込んだ後、ログ用 バッファをフラッシュする • これにより、トランザクションは「コミット済」状態となる • トランザクションのアボート: abort – ログレコード [ A: Ti ] をログ用バッファに書き込んだ後、ログの 内容に基づきそのトランザクションが行ったwriteのundo処理を 行う undo/redo方式の例(1) トランザクションの開始 アプリケーション プログラム ログ用バッファに [ B: Ti ] を書き込む Old Old データ用 バッファ データベース [ B: Ti ] ログ用バッファ データベースシステム ログファイル undo/redo方式の例(2) トランザクションによる書き込み write アプリケーション プログラム ログ用バッファに [ W: Ti, Old New ] を書き込み、 新しい値 Newを データ用バッファに 書き込む New Old データ用 バッファ データベース [ B: Ti ] [ W: Ti, O, N] ログ用バッファ データベースシステム ログファイル undo/redo方式の例(3) トランザクションのコミット write アプリケーション プログラム ログ用バッファに [ C: Ti ]を書き込み、 ログ用バッファを フラッシュする New Old データ用 バッファ データベース [ B: Ti ] [ W: Ti, O, N] [ C: Ti ] ログ用バッファ データベースシステム [ B: Ti ] [ W: Ti, O, N] [ C: Ti ] ログファイル undo/redo方式の例(4) 障害回復処理 write アプリケーション プログラム ログを使って undo/redo処理する New Old データ用 バッファ データベース [ B: Ti ] [ W: Ti, O, N] [ C: Ti ] ログ用バッファ データベースシステム [ B: Ti ] [ W: Ti, O, N] [ C: Ti ] ログファイル 障害のタイミングと undo/redo処理の詳細 以下の例で考えてみる トランザクションT1 トランザクションT2 begin read(A, x) begin write(B, 150) commit ケース1: read(B, y) ここで障害発生 write(A, 200) commit ケース2: ここで障害発生 ログ 1: 2: 3: 4: 5: 6: 7: 8: [ B: T1 ] [ R: T1, A ] [ B: T2 ] [ W: T1, B, 100, 150 ] [ C: T1 ] [ R: T2, B ] [ W: T2, A, 100, 200 ] [ C: T2 ] ケース(1) トランザクションT1 トランザクションT2 begin read(A, x) begin write(B, 150) ログ 1: 2: 3: 4: [ B: T1 ] [ R: T1, A ] [ B: T2 ] [ W: T1, B, 100, 150 ] • この場合、ログから T1、T2ともにコミットしていないことがわかる • したがって、4: [ W: T1, B, 100, 150 ] をundoする ケース(2) トランザクションT1 トランザクションT2 begin read(A, x) begin write(B, 150) commit read(B, y) write(A, 200) ログ 1: 2: 3: 4: 5: 6: 7: [ B: T1 ] [ R: T1, A ] [ B: T2 ] [ W: T1, B, 100, 150 ] [ C: T1 ] [ R: T2, B ] [ W: T2, A, 100, 200 ] • この場合、ログから T1がコミットし、T2がにコミットしていない ことがわかる • したがって、4: [ W: T1, B, 100, 150 ] をredoし、 7: [ W: T2, A, 100, 200 ] をundoする チェックポイント(checkpoint) • undo/redo方式に基づく障害回復処理(リスター ト時の処理)では、システム起動時から障害発生 時までのログが必要になるが、これは膨大な量 になる – 障害回復時にこれをすべてundo/redoするのでは時 間がかかる • そこで、一定周期でバッファの内容をディスクに 書き込み(フラッシュし)、障害回復時にはその時 点以降のみundo/redoすればよいようにするの が普通である – これを「チェックポイント(checkpoint)」という 単純なチェックポイント処理手順 • 以下の手順により、チェックポイントを作る ① 新たなトランザクションの開始を禁止する ② アクティブな(実行中の)トランザクションがすべてコ ミットするかアボートするまで処理を続ける ③ アクティブなトランザクションが無くなったら、まずロ グ用バッファをフラッシュし、続いてデータ用バッファ をフラッシュする ④ ログ用バッファにログレコード [ CHECKPOINT ] を書 き込み、もう一度ログ用バッファをフラッシュする • これにより、CHECKPOINT以降に発生した障害 の回復処理は、CHECKPOINT以降のログのみを undo/redoすればよくなる メディア障害と対策 • データベース本体や、ログファイルを保存してお くディスク装置が故障するのがメディア障害であ る • メディア障害に対する対処としては以下のように なる – 定期的にデータベース全体のバックアップをとる – バックアップ時以降のログを使って回復する • どんな障害でもログが失われると回復処理が不 可能になるので、ログは異なる装置に二重・三 重に記録を取るようにする 成績評価 • 期末試験で60点以上取得し、かつ、実習課 題のレポートの本提出をすることを、単位の 条件とする • 合格者の評点(A~C)は、期末試験の結果と、 実習課題、レポート内容から決定する 期末試験について • 期末試験は、6月26日(木)に7C202(実習室3)で行う • 試験時間は5限(15時15分~16時30 分、75分間)に行う – 終わった人から提出し、退席してよい • 試験は、教科書・資料等の持ち込み可、端末の使用可、 ネットでの検索・閲覧可とする – 問題の分量が多いので、事前に予習をしっかりしておくこと – メール、チャット、SNS、Yahoo!知恵袋等の利用は不可とする • http://wombat.cc.tsukuba.ac.jp/dbsystem1/ に模 擬試験問題とその解答例・解説を載せておくの で、参考にすること レポートについて • レポートの締め切りは「本提出」と「再提出」の 2回がある – 本提出締切: 6月21日(土) 19時 – 再提出締切: 7月10日(木) 19時 • どちらも manaba で提出すること • 本提出締切には必ず提出すること(単位の要 件の一つ) • 再提出は必須ではないが、提出すればプラ スに評価する レポートの本提出について • 以下の内容を含めること – 実体関連図 – MySQLで作成したスキーマ(create table、create indexなど SQL文のリスト) – PHPのプログラムリスト – (PHPプログラムが完成している場合には)実行したPHPプロ グラムの主要なWeb画面のコピー(3~5画面程度) • 以下については、これまでの実習での提出後に加筆・ 修正を行った場合には、本提出のレポートに含めること – 機能一覧、画面フロー設計、画面設計、入出力項目の洗い 出し、データベース設計 • 作業したものをそのまま束ねて提出すればよい – 全体のつじつまがあってなかったり、完成していない部分が あってもよい レポートの再提出について • 以下の内容を含めること – (本提出より完成度を高めた)PHPのプログラムリ スト – 実行したPHPプログラムの主要なWeb画面のコ ピー(3~5画面程度) • 作業したものをそのまま束ねて提出すればよ い – 全体のつじつまがあってなかったり、完成してい ない部分があってもよい
© Copyright 2024 ExpyDoc