レプリケーション ( 1 )

August 06, 2018

レプリケーション動作原理

レプリケーションにおける考え方は「2 つのデータベースに含まれるデータが同じであり、それに対して加える変更も同じであれば結果も同じである」というもの。
マスターに対してどのような変更が加えられたかを連続的に記録し、同じ変更をスレーブに転送する。スレーブ上では、マスターから送られてきた変更履歴を連続的に再生する。そうすることで、スレーブのデータはマスターに追随することになる。
以上の仕組みを実現させるために、MySQL には以下の機能が実装されている。

  • マスター上の変更を記録するためのバイナリログ
  • スレーブへデータを転送するためのマスタースレッド
  • スレーブ上でデータを受け取り、リレーログに記録するための IO スレッド
  • リレーログからデータを読み取り、それを再生するための SQL スレッド

f:id:shiro_kochi:2018××××××××:plain:w100:left

バイナリログ

バイナリログとは、MySQL サーバ上で発生した全ての変更を直列化し、記録するための仕組み。バイナリログは MySQL のデータディレクトリ上に作成され、log_bin オプションで指定したファイル名のプレフィクスに 6 桁の連番がついた名前のファイルとして格納される。
実際に /etc/my.cnf にて log_bin オプションを指定すると、/var/lib/mysql/ 配下にログが配置されることを確認できる。

$ cat /etc/my.cnf  
[mysqld]  
datadir=/var/lib/mysql  
socket=/var/lib/mysql/mysql.sock  
# Disabling symbolic-links is recommended to prevent assorted security risks  
symbolic-links=0  
# Settings user and group are ignored when systemd is used.  
# If you need to run mysqld under a different user or group,  
# customize your systemd unit file for mysqld according to the  
# instructions in http://fedoraproject.org/wiki/Systemd  
log_bin=mysql-bin  
expire_logs_days = 7  
  
[mysqld_safe]  
log-error=/var/log/mysqld.log  
pid-file=/var/run/mysqld/mysqld.pid  
  
$ ls -l /var/lib/mysql/mysql-bin.*  
-rw-rw---- 1 mysql mysql 509  86 04:51 /var/lib/mysql/mysql-bin.000001  
-rw-rw---- 1 mysql mysql  19  86 04:50 /var/lib/mysql/mysql-bin.index  

上記の mysql-bin.index はバイナリログインデックスファイルであり、バイナリログのファイル名がリストアップされている。

$ sudo cat /var/lib/mysql/mysql-bin.index   
./mysql-bin.000001  

また、SHOW BINARY LOGS でも確認可能。
このコマンドはバイナリログインデックスファイル (mysql-bin.index) の中身を読み取り、且つ個々のバイナリログを日ありて、ファイルサイズを読み取って表示するというもの。

mysql> SHOW BINARY LOGS;  
+------------------+-----------+  
| Log_name         | File_size |  
+------------------+-----------+  
| mysql-bin.000001 |       509 |  
+------------------+-----------+  
1 row in set (0.00 sec)  

上記はバイナリログの中身には一切関与しないため、中身を見るには SHOW BINLOG EVENTS コマンドを使うか、mysqlbinlog コマンドを利用する。

mysql> SHOW BINLOG EVENTS;  
+------------------+-----+-------------+-----------+-------------+----------------------------------------------------------------+  
| Log_name         | Pos | Event_type  | Server_id | End_log_pos | Info                                                           |  
+------------------+-----+-------------+-----------+-------------+----------------------------------------------------------------+  
| mysql-bin.000001 |   4 | Format_desc |         1 |         107 | Server ver: 5.5.60-log, Binlog ver: 4                          |  
| mysql-bin.000001 | 107 | Query       |         1 |         190 | create database hoge                                           |  
| mysql-bin.000001 | 190 | Query       |         1 |         301 | use `hoge`; create table hogehoge (id int, name varchar(20))   |  
| mysql-bin.000001 | 301 | Query       |         1 |         369 | BEGIN                                                          |  
| mysql-bin.000001 | 369 | Query       |         1 |         482 | use `hoge`; insert into hogehoge (id, name) values (0, 'hoge') |  
| mysql-bin.000001 | 482 | Xid         |         1 |         509 | COMMIT /* xid=9 */                                             |  
+------------------+-----+-------------+-----------+-------------+----------------------------------------------------------------+  
6 rows in set (0.00 sec)  
$ sudo mysqlbinlog /var/lib/mysql/mysql-bin.000001 | head -10  
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;  
/*!40019 SET @@session.max_insert_delayed_threads=0*/;  
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;  
DELIMITER /*!*/;  
# at 4  
#180806  4:50:35 server id 1  end_log_pos 107 	Start: binlog v 4, server v 5.5.60-log created 180806  4:50:35 at startup  
# Warning: this binlog is either in use or was not closed properly.  
ROLLBACK/*!*/;  
BINLOG '  
m9NnWw8BAAAAZwAAAGsAAAABAAQANS41LjYwLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA  

MySQL 5.0 までは、バイナリログは SQL 文そのものが記録されており、この方式をステートメントベースレプリケーション (SBR) と呼ぶ。
SBR には問題があり、UUID () 関数を使う場合など、結果がその都度ことなる SQL 文を発行する際にマスター - スレーブ間で整合性が崩れる点である。
このように実行するたびに結果が同じになることが保証されない SQL は非決定性 (Non-deterministic) であるといわれ、SBR にとっては天敵である。以下のようなものが該当する。

  • 非決定性の UDF やストアドプログラムを含む SQL 文
  • ORDER BY 句なしで LIMIT 句が適用された UPDATE / DELETE
  • 次の関数を含む SQL 文

    • LOAD_FILE()
    • UUID() / UUID_SHORT()
    • USER()
    • FOUND_ROWS()
    • SYSDATE()
    • GET_LOCK()
    • IS_FREE_LOCK()
    • IS_USED_LOCK()
    • MASTER_POS_WAIT()
    • RAND()
    • RELEASE_LOCK()
    • SLEEP()
    • VERSION()

このような非決定性の SQL に起因する問題を克服するため、MySQL 5.1 において、行ベースレプリケーション (RBR) というモードが追加された。
これは SQL を実行した結果、変更が生じた行の変更前と変更後の値を記録する方法である。行単位で記録するため、SBR よりもバイナリログのサイズが大きくなるものの、SQL が非決定性かどうか振り回される心配はない。

また、さらに Mixed ベースレプリケーション (MBR) も存在する。これは SBR と RBR を必要に応じて使い分ける、というものであり、非決定性 SQL が出た段階で RBR に自動で切り替わるものである。


 © 2023, Dealing with Ambiguity