MySQL のレプリケーション実装
はじめに
どうも、年明けおもしろ荘を見ながらブログを書いているけんつです。
前にMySQL 8 と docker-compose を使ってレプリケーションを構築する記事を書いたのだけど、そこではただバイナリログのポジションベースのレプリケーションを構築しただけだったので
この記事でその実装と仕組みを追っていく。
前のレプリケーション構築記事
GTID ベースのレプリケーションには触れていない。
rabbitfoot141.hatenablog.com
レプリケーション実装
レプリケーションはマスターが DB の全ての更新や削除といった変更をバイナリログベースで追跡することがベースとなっている。
このバイナリログはサーバが起動した瞬間からデータ変更以外にもデータベースの構造が変わるなどのイベントを全て記録する。また変更が伴わない SELECT 等はバイナリログ上で追跡されない。
MySQL のレプリケーションは、マスタに変更があった場合にスレーブにデータをプッシュするのではなく、マスターからデータをプルするという表現が近い。
また実際に送信されるデータはバイナリログであり、スレーブはこのバイナリログのイベントを再現することで、マスターと同様のデータを再現する。
また各スレーブは独立しているため、スレーブはデータベースのコピーを独自のペースで読み取り、更新できレプリケーションプロセスを他のレプリケーションプロセスに影響を与えることなく開始、停止することが可能となっている。
実装の詳細
MySQL のレプリケーションはマスタサーバに1つ、スレーブサーバに2つのスレッドを使用することで実装されている。
サーバ側
- Binlog dump thread: マスターがスレーブに接続するときにバイナリログの内容をスレーブに送信するスレッドを作る。これがそれ。マスター側で SHOW PROCESSLIST で binlog dumo thread を確認できる。このスレッドはスレーブに送信される各イベントの読み取りの
スレーブ側
- Slave I/O Thread: START SLAVE がスレーブ側で実行され、マスターに接続した段階でバイナリログの更新記録の送信を要求する I/O スレッドを要求する。このスレッドは Binlog dump Thread が送信するバイナリログの各イベントを読み取るためにマスターのバイナリログでロックを取る。*1
- Slave SQL Thread: スレーブは Slave I/O Thread によって書き込まれたリレーログを読み取るこのスレッドを作成し、そこに含まれるイベントを実行する。
スレーブは2つのスレッドを使用して、マスターからの更新を読み取ることと、それらを実行することを独立タスクに分類する。
そのため、ステートメント実行が遅い場合でもステートメントを読み取るタスクが遅くなることはない。
SQL スレッドがかなり遅れている場合でも、全てのバイナリログを起動時にフェッチ出来る。またSQL スレッドがフェッチ済みのステートメントの実行を完了する前にスレーブが停止した場合でも安全なコピーがリレーログとしてスレーブローカルに保存されているため次の起動時に実行を開始することができる。これによってバイナリログは送ってさえしまえばマスターで長時間保持する必要がない。
おわりに
MySQL 8 のドキュメント翻訳みたいになってきた。
*1:イベントがスレーブに送信される前でも
docker-compose を使って MySQL8 の レプリケーションを構築する
はじめに
どうも、最近アローを見ていてフラッシュに出てくるアローのキャストと同じで感動してるけんつです。フェリシティいいよね。
ようやくアドカレが終わったので、気分転換にやろうやろうと思っていた MySQL のレプリケーションを docker-compose で構築する方法でもまとめます。
qiita とかみたら実例があるけども、それを見たらあまり勉強にならないのでなるべく MySQL 8 の公式ドキュメントを見ながら構築していく。
今回はいつの間にか降ってきていた MySQL 8.0.18 の docker コンテナを使ってやっていく。
MySQL のレプリケーション
そもそも MySQL におけるレプリケーションとはそもそも何なのかと言うと、Master のデータを1つ以上の Slave にコピーできる機能。
そしてこのレプリケーション機能は、デフォルトで非同期なので Slave は Master からのデータを受け取るために永続的に接続している必要がない。
また構成に応じて全てのデータベース、選択したデータベース、テーブルなどを選択して複製することができる。
レプリケーションを取る利点しては以下の通り。
- スケールアウト: 複数のスレーブに負荷を分散する。書き込みに関することはマスターで行う必要があるが。読み込みに関してはスレーブを利用させることで負荷を減らす。
- データセキュリティ: データはスレーブに複製され、スレーブはレプリケーションプロセスを一時停止させることができるためマスターデータを壊すこと無くスレーブでバックアップを実行することができる。
- 分析; 理由はスケールアウトと似ている。負荷の高い情報の読み取りを行うような分析に関することではマスターの負荷を上げることなくスレーブで実行できる。
- 長距離データ配布: マスターへの永続的なアクセスを必要とせず、レプリケーションを使用してデータをローカルコピーできる。
目的とする構成
まず、Master 1 台に対して Slave 1 台の構成を目指す。
Slave2 という設定が github レポジトリにはあるがそれは今後 GTID レプリケーションを構成する用の設定なので無視していい
成果物
Binary Log File Position Based Replication の構築
Master サーバの設定
レプリケーションを構築するためにはマスターでバイナリロギングが有効になっている必要がある。MySQL 8ではデフォルトで有効になっている。MySQL 5.7 以下ではデフォルトで有効にならないため、設定する必要がある。
バイナリログはデフォルトで /var/lib/mysql/ に binlog*** という命名で作成される。これは log_bin_basename で変更可能。
また、server_id という 1~2^32 - 1 の正の整数値で指定するサーバを一意に求めることの出来る ID を設定する必要がある。また、これは設定しない場合はデフォルトで 0 が設定されているがその状態だとマスターはスレーブからの接続を拒否するため必ず設定する必要がある。
それらを踏まえて my.cnf(master.cnf) に以下の設定を追加する。
[mysqld] ... server_id=1
確認する。
MySQL [(none)]> select @@global.log_bin; +------------------+ | @@global.log_bin | +------------------+ | 1 | +------------------+ 1 row in set (0.00 sec) MySQL [(none)]> select @@global.server_id; +--------------------+ | @@global.server_id | +--------------------+ | 1 | +--------------------+ 1 row in set (0.00 sec)
おっけーっぽい。
Slave の設定
こちらも同様に server_id を設定する必要がある。
レプリケーションを取りたい MySQL サーバ同士で ID が被らないように以下の様に設定を追加する。
slave1.cnf
[mysqld] ... server_id=2
設定を確認する。
MySQL [(none)]> select @@global.log_bin; +------------------+ | @@global.log_bin | +------------------+ | 1 | +------------------+ 1 row in set (0.00 sec) MySQL [(none)]> select @@global.server_id; +--------------------+ | @@global.server_id | +--------------------+ | 2 | +--------------------+ 1 row in set (0.00 sec)
一応 log_bin の設定値を確認したが Slave でバイナリロギングを有効にする必要は実はない。
有効になっていれば、データバックアップとクラッシュリカバリに Slave のバイナリロギングを利用することができるらしい。
レプリケーションユーザを作成する
必ずレプリケーション専用のユーザを作らないといけないわけではないが、レプリケーションのユーザ名とパスワードは mysql.slave_master_info にプレーンテキストとして保存されるため必要最低限の権限を与えた専用ユーザを作成するべきらしい。
といってもやることはユーザを作成して REPLICATION SLAVE の GRANT を付与するだけ。
以下のシェルスクリプトを slave 用 mysql コンテナの docker-entrypoint-initdb.d 以下にマウントする。
またレプリケーション専用アカウントの情報は適宜 docker-compose yaml に追加する
#!/bin/sh mysql -u root -v mysql <<SQL CREATE USER '${MYSQL_REPLICATION_USER:+repl}'@'%' IDENTIFIED BY '${MYSQL_REPLICATION_PASSWORD:+repl}'; GRANT REPLICATION SLAVE ON *.* TO '$MYSQL_REPLICATION_USER'@'%'; SQL
レプリケーションマスターバイナリログのポジション取得
まず、レプリケーションを構築するにはやることがある。
初回起動時は docker-compose yaml の値をもとにユーザなどが作成されるがバイナリログを有効にしているためこれらのログが存在する。
そのため、master のバイナリログをリセットする必要がある。*1
その前提の元に、データスナップショットを取るために必要な手順を追っていく。
まずはバイナリログのどこからレプリケーションを開始するのが正しいかを判断するためにバイナリログのポジションを取得する。
この際に、更新が走ってしまうとバイナリログの位置が変わってしまうため READ LOCK をかける。
この2つを行うため、さっきのシェルスクリプトに以下の SQL を追加する。
#!/bin/sh ... mysql -u root -v mysql <<SQL RESET MASTER; FLUSH TABLES WITH READ LOCK; SQL
次に SHOW MASTER STATUS を参照してバイナリログファイルとポジションを取得する。
それらの情報は Slave を Master に接続するために必要となる。
#!/bin/sh ... binlogfile=`mysql -u root -h master -e "SHOW MASTER STATUS\G" | grep File: | awk '{print $2}'` position=`mysql -u root -h master -e "SHOW MASTER STATUS\G" | grep Position: | awk '{print $2}'`
mysqldump を使って master のスナップショットを作成する
次に、スナップショットを作成する。今回は全てのデータベースを対称にするため以下のようにする。
めんどうなのでついてに master のスナップショットを slave に突っ込む。
#!/bin/sh ... mysqldump -u root -h master --all-databases --master-data > /tmp/master.sql mysql -u root < /tmp/master.sql
slave1.cnf
[mysqld] ... skip-slave-start
-
- skip-slave-start が無いと、この mysqldump を実行した段階でスレーブが開始してしまうためスレーブ側で STOP SLAVE を実行する必要がある。
Slave を開始する
CHANGE MASTER TO で、接続先と開始するログファイルにポジションを指定して START SLAVE によって開始する。
そのあとで Master の READ LOCK を取っているからそれをアンロックする。
なぜか skip-slave-start が有効にならなかったので STOP SLAVE をしている
#!/bin/sh ... mysql -u root -v -e "STOP SLAVE"; mysql -u root -v -e "RESET SLAVE"; mysql -u root -v -e "CHANGE MASTER TO MASTER_HOST='master', MASTER_USER='root', MASTER_PASSWORD='', MASTER_LOG_FILE='${binlogfile}', MASTER_LOG_POS=${position};" mysql -u root -v -e "START SLAVE;" mysql -u root -h master -v -e "UNLOCK TABLES;"
動作確認
$ docker-compose exec slave1 mysql -e 'show slave status \G' ... Slave_IO_Running: Yes Slave_SQL_Running: Yes ... $ docker-compose exec slave1 mysql -e "select * from sample.hello;" +----+--------+ | id | lang | +----+--------+ | 1 | Golang | | 2 | SQL | | 3 | PHP | | 4 | Java | | 5 | C | +----+--------+ $ docker-compose exec master mysql -e "insert into sample.hello(lang) values ('Scala')" $ docker-compose exec slave1 mysql -e "select * from sample.hello;"+----+--------+ | id | lang | +----+--------+ | 1 | Golang | | 2 | SQL | | 3 | PHP | | 4 | Java | | 5 | C | | 6 | Scala | +----+--------+
できてるっぽい。
おわりに
もう少しこのレプリケーション周りのオプションだったり、バイナリログ周りは追っていく必要がありそうだけどとりあえずできた。
*1:MySQL :: MySQL 8.0 Reference Manual :: 13.4.1.2 RESET MASTER Statement https://dev.mysql.com/doc/refman/8.0/en/reset-master.html
アドカレを通して CMU Database Systems をひたすら追ってみて
この記事は「けんつの1人 DBMS アドベントカレンダー Advent Calendar 2019 - Adventar」 25 日目の記事です。
はじめに
以下の記事に触発されて CMU Database Systems を追っていって途中から DBMS の自作に切り替えてアドカレにしてみて、色々と思うところやどこまでできたのかをまとめられたらいいなと思う。
なにをやったか
CMU Database Systems を追った
DBMS について体系的に学習するために以下の講義を追った。
- 01 Relational Data Model
- 02 Advanced SQL
- 03,04 Database Storage
- 05 Buffer Pools
- 06 Hash Tables
- 07, 08 Tree Indexes
- 09 Index Concurrency Control
- 10 Query Processing
- 16 Concurrency Control Theory
- 17 Two-Phase Locking
- 19 Multi-Version Concurrency Control
- 20 Logging Schemes
- 21 Database Recovery
ほとんどが DBMS の中でも DB Storage に関する内容。
ところどころ抜けている部分は JOIN アルゴリズムだったり、内部的にクエリで得た検索結果をソートしたりといった内容で、後半で行った DBMS の実装に含めないことにした部分。
DBMS の実装の一部
Database Storage については実装を進めた。やってくるクエリを直列で捌くぐらいなら問題内程度の実装にはなっている。
そのあたりは 11 ~ 18 日あたりの雑な記事を参照するとわかりそう。
クエリのパーサ何かはこの後書くけど諸事情で断念したので、終盤のトランザクション周りとクエリあたりは実装できていない。
既存の実装を調べた
途中で、実際に MySQL, PostgreSQL ではどのように実装されているのかというところも諸々調べてみた。
rabbitfoot141.hatenablog.com
rabbitfoot141.hatenablog.com
rabbitfoot141.hatenablog.com
ストレージだけ実装した
前述の通り、トランザクションは実装できていないけどひとまずストレージだけは実装した。
構成要素としては以下の通り
- Catalog
- Tuple
- Page
- Buffer Pool
- B Tree Index
- Clock Sweep Cache
- LRU Cache
- Disk Manager
Page, Tuple は Protocol Buffer を使わず、 gob も使わず自前で byte 列にシリアライズしている。
Buffer Pool 周りは PostgreSQL 8*1を参考に実装している。
ひとまず、ページに対してタプル*2の追加はできるし、テーブルという単位でそれらを管理することもできる
あとは B Tree では int32 相当の値と string の検索に対応することもできた。
やってみて
辛さ半分、楽しさ半分
辛いところ
最初にあげた記事にもあるようにコンピュータ・サイエンスの基本的な知識が要求されるため、現役学部生といえど情報工学を専攻している身には新しく学ぶことになる前提知識が多くてかなり大変だった。
この一連の流れを通して学習することが、CS の基本知識 + DBMS の理論についてなのでかなり盛りだくさんだったのは言うまでもなく苦労の連続だった。
そして最も厳しかったのは B Tree や Buffer Pool の実装で、これはデータ構造とアルゴリズムの実装が連続するため知識としてもっていても
またそれらを実装できるのは全く別の話なのでかなり時間を食ってしまったし、わかるとできるを結びつけるのを締め切りに迫られながらやるのはかなりメンタルに来るものがある。
楽しかったところ
まず、DBMS に関して体系的に学べたのは新しい発見の連続でこれはかなりワクワクする内容だった。特にストレージ周りは新しく学ぶことばかりで、日々の勉強が楽しかった。このワクワク、なかなか伝わりにくいとは思うが新しく学んだことを試行錯誤しながら実装するのはめちゃくちゃ楽しい。
以前、 Linux Kernel モジュールを書いていたことがあるのだけど講義内で出てくる仮想記憶や mmap などのシステムコールについても解説があり
自分のなかで断片として持っていた知識が「あぁ実際にはこういう実装に使えるのか。それでこの DBMS はこういう実装になっているのか」とつながっていく感覚もさらに実装の幅が広がったのもワクワクの連続だった。
また、既存の DBMS についての実装もかなり追ったので MySQL*3 の binlog, LRU Cache や PostgreSQL の BufferPool に関連する本来ブラックボックスのようになっているものの裏側をきちんと理解することが出来てので当初の目的通り最低限そういった知見が得られたのは非常に良かったと思う。
Golang 力があがった
これは sansan の荒川さんのレポジトリを参考にして作っていたというのが関係している。
github.com
例えば、Slice と Array の使い方だったり、 B Tree のような構造の実装であったりとすごく得るものがあった。
B Tree で Node がもつ Item で Interface を使っていたが、interface の使い方で普段は迷うことが多いのですごく参考になった。
また実装に入った段階で出来るだけ異なるアプローチや仕組みを実装しようと思っていたので、常に試行錯誤の連続も何度も書いて消してを繰り返したので必然的に Golang 力があがった。
あとは Goroutine 周り。あまりヘビーな使い方をしたことがなかったが、ラッチ相当の機能を実装するために sync.RWMutex なんかを多用したため、そのあたりの排他制御に関する知見と実装方法にたいする理解も深まった。
既存の実装への理解が深まった
楽しかったところにもあったが、これもひとつ大きな副次的効果だと思う。めちゃくちゃ調べて
こういった Page の物理的構成に関する記事を見て参考にしたり
http://www.interdb.jp/pg/pgsql08.html
こういったものも参考にしたので、自然と既存の実装について理解がかなり深まった。
MySQL のドキュメントもかなり参照した。
反省点
SQL に対する理解と見通しが甘かった
今回はこれに尽きる。
後々、JOIN やサブクエリ等の実装もしたかったので、再帰降下構文解析でなく goyacc で実装しようとは最初から思っていたのだが
簡単に出来ると思っていて*4、ストレージの実装にかなりの時間を使ったのだが実際やってみると B Tree や Buffer Pool の実装の比にならないほど難航した。
そのため、その後に控えていたトランザクションの実装をする時間がなくなってしまったという事態になってしまった。
めちゃくちゃ見通しが甘かった。
CS の基礎が不足している
これも想像以上に時間がかかった理由になっている。
本来 DBMS の理論の学習に時間を割くべきだが、そこで前提とされている CS に関する基礎知識が不足していたためにところどころで遅れを招いた。
これは普段から、如何にライブラリ何かがいい感じにしてくれるバックグラウンドにあるものを理解できていないかというところが露呈したと思っている。
どうにかそのあたりも勉強しないといけないと痛感した。
CMU Database Systems をひたすら追っていく ~21 Database Recovery~
この記事は「けんつの1人 DBMS アドベントカレンダー Advent Calendar 2019 - Adventar」 24 日目の記事です。
はじめに
今回は実際にリカバリをどのように行うかという話。
Aries
Algorithm for Recovery and Isolation Exploiting Semantics の略で IBM が 1990 年代に研究したもの。
これを完全に採用しているものは少ないが、この手法に類似した方法を取っている。
ARIES の処理手順
WAL Records
ログレコード形式を拡張して、追加情報を持つ必要がある。全てのログレコードに LSN*1を追加することで対応する。
- 各ページには Page LSN が含まれ、最新の更新を示す。
- またフラッシュされた最大の LSN も持つ
- ディスクに書き込まれる前に、 page LSN <= flushed LSN となるようにログをフラッシュする
Normal Execution
Transaction Commits
ARIES Recovery
ARIES は 3 つのフェーズで構成されている。
クラッシュ後は起動時にそのフェーズを逐次実行していく。
おわりに
簡単にまとめたけど、これを一つずつちゃんとまとめないと理解できない気がしてきた
*1:ログシーケンス番号
CMU Database Systems をひたすら追っていく ~20 Logging Schemes~
この記事は「けんつの1人 DBMS アドベントカレンダー Advent Calendar 2019 - Adventar」 23 日目の記事です。
- はじめに
- Logging Schemes
- Failure Classification
- Buffer Pool Management Policies
- Write-Ahead Logging
- Checkpoint
- おわりに
はじめに
今日はログ周りの話。
WAL とか、ACID の原子性、耐久性、一貫性などを担保するための重要な要素。
Logging Schemes
リカバリアルゴリズムはデータベースに置いて一貫性、原子性、耐久性を確保する上で需要な要素となっている。
このリカバリアルゴリズムで行う大きく分けて2つにわかれる。
またここのでキーワードとして以下の2つがある。
Failure Classification
DBMS で起こる障害は大きくわけて 3 つに分類できる。
Transaction Failures
System Failure
Storage Media Failure:
- Non-Repairable Hardware Failure: ディスク障害、不揮発性ストレージの一部がクラッシュする。これから回復するにはアーカイブバージョンから復元するしかない。
Buffer Pool Management Policies
バッファプールを管理するポリシーの2つを紹介する。
例えば、No-Steal + Force で実装するなら。
変更がディスクに書き込まれなかった場合は、中止されたトランザクションによる変更を元に戻す必要はない。
また、コミット時に全ての変更がディスクに書き込まれることが保証されているため変更をやり直す必要はない。
ただし、トランザクションが変更する必要のある全てのデータがメモリに収まらない場合、トランザクションがコミットする前のダーティページをディスクに書き込まないため、そのトランザクションを実行できないという制限がある。
Write-Ahead Logging
ディスクページに変更が加えられる前にデータベースに加えられた全ての変更のログをログファイルに記録する手法。
殆どの DBMS で使用されているが、リカバリするためにはログを追う必要があるので処理に時間が掛かる。
ログはDBを復旧するための UNDO, REDO に必要な全ての情報を持っている。
Steal + No-Force システムを例に解説する。
Implementation
更新されたページの関連する全てのログレコードはページ自体がストレージに書きこまれるよりも前に永続化される。
- 全てのログレコードがストレージに書き込まれ、永続化されるまでトランザクションがコミットされたとはみなされない
- トランザクションが開始したら、各トランザクションのログに BEGIN レコードが書き込まれ開始点としてマークされる。
- トランザクションが終了したら、COMMIT レコードをログに書き込み、ログレコードがフラッシュされることを確認する。
- 各ログエントリには トランザクションID, オブジェクトID, 変更前の値(UNDOに使用)、変更後の値(REDOに使用) が格納される。
- トランザクションのコミット時にディスク全体のログ記録を行う必要がある。
Deferred Updates
Checkpoint
WAL の大きな問題としログファイルが肥大化するという問題がある。
クラッシュ時にこのログファイルが肥大化していると、ログを追ってリカバリする処理に時間がかかることがある。
そのため、チェックポイントを設け定期的にバッファの持つ情報をディスクにフラッシュする必要がある。
チェックポイントはどの程度設けるのが良いという基準はなく、チェックポイントが多すぎるとパフォーマンスが低下し、少なすぎるとその意味が薄れてしまう。
そのため、DBMS が担う役割や要求パフォーマンスに左右される。
おわりに
次はリカバリについて
CMU Database Systems をひたすら追っていく ~19 Multi-Version Concurrency Control~
この記事は「けんつの1人 DBMS アドベントカレンダー Advent Calendar 2019 - Adventar」 22 日の記事です。
はじめに
今回は MySQL や PostgreSQL でも採用されている MVCC について。
Multi-Version Concurrency Control
これは単に同時実行制御に収まらない広い概念として存在している。過去10年間に実装されたあたらしい DBMS では最も広く利用されているらしい。
これが何かというと、DBMS は DB 内の単一論理オブジェクトにたいして複数の物理バージョンを維持する。
具体的には以下のような処理を行う。
Key Properties
書き込みは読み込みをブロックしない。読み込みも書き込みをブロックしない。
読み取り専用トランザクションはロックを取得せずに一貫したスナップショットを読み取る。
DBMS がスナップショットで実行できるクエリをサポートする。
Version Storage
DBMS が論理オブジェクトの物理バージョンを持つ方法のこと。具体的にはポインタフィールドを使用して論理タプル毎にバージョンチェーンを作成する。
これによって DBMS は実行時に特定のトランザクションから見えるバージョンを見つけることができる。
インデックスは常にチェーンの先頭を指し、スレッドは読み取るべきバージョンを見つけるまでチェーンを検索する。
Append Onky Storage
新しいバージョンは同じテーブルスペースに追加される。
- Oldest To Newest: 新しいバージョンをチェーンの最後に追加する
- Newest To Oldest: チェーンの先頭は最新となるため高速に検索できるが、インデックスはバージョンごとに更新する必要がある。
Time Travel Storage
古いバージョンは別のテーブルスペースにコピーされる。
Delta Storage
変更された属性の元の値が別のデルタレコードスペースにコピーされる。
Garbage Collection
DBMS は時間の経過とともに DB から開放可能な物理バージョンを削除する必要がある。
これには2つのアプローチがある。
Tuple Level Garbage Collection
- Background Vacuuming: 個別のスレッドが定期的にテーブルをスキャンし、開放可能なバージョンを探す
- Cooperative Cleaning: ワーカスレッドはバージョンチェーンを検索するときに再利用可能なバージョンを検索する
おわりに
次はログ周りだったかな
CMU Database Systems をひたすら追っていく ~17 Two-Phase Locking~
この記事は「けんつの1人 DBMS アドベントカレンダー Advent Calendar 2019 - Adventar」 21 日目の記事です。
はじめに
今日は Two-Phase Locking について。
Transaction Locks
ラッチというのは以前にも何度か解説していると思うがこれからはロックの話。
ロックには2つ種類がある。
- 共有ロック:複数のトランザクションが同じデータを読み取ることができるロック。トランザクションが共有ロックを取っている間に他のトランザクションが共有ロックを同じデータに対して取ることができる。
- 排他ロック:トランザクションがデータを変更するときにかけるロック。このロックは重複してかけることができず、同時に1つのトランザクションのみ排他ロックを取ることができる。
またトランザクションは以下のようにロックマネージャーを用いて実行・管理される。
Two Phase Locking
Two Phase Locking (2PL) は悲観的な同時実行制御プロトコルであり、トランザクションがその場でDB内のオブジェクトにアクセスできるかどうかを決定する。
トランザクションが競合した場合は、2PL で十分に対応できる。しかし、トランザクションが ABORT し、他のトランザクションをロールバックする必要がある場合は無駄な処理が生まれる。
以下の手順を具体的にはとる。
Phase1: Growing
- 各トランザクションはロックマネージャから必要なロックを要求する
- ロックマネージャはロック要求を許可または拒否する。
2PL Deadlock Handling
Two-Phase Locking ではデッドロックを解消するために検出する場合と防止する2つの方法がある。
おわりに
次は MVCC