mysqlのslave_net_timeoutとMASTER_HEARTBEAT_PERIOD

前置き

mysqlのリプリケーション環境において、スレーブのslavenettimeoutに設定された時間(デフォルトは3600秒)マスターからスレーブに対して何の通信もなかった場合、スレーブはレプリケーションを再接続します。これは、スレーブがリプリケーションコネクションが何らかの理由で死んでいても気づけない場合の対応としての仕様です。ということは、何らかの原因でリプリケーションのコネクションが死んでしまうと、最大3600秒はリプリケーションが停止してしまう可能性がある!ということになります。スレーブをバックアップとしてのみ使用しているサービスであれば許容できるifなのかもしれませんが、スレーブをアプリケーションよりの参照データストレージとして使用しているサービスではこのifは到底許容できる物ではないでしょう。

じゃぁこの設定を短くすればいいのでは?と考えちゃうのですが

1
2
# my.cnf
slave_net_timeout=300 # default 3600 sec

マスターにて特にイベントがない場合も、通信がないと認識されてslavenettimeoutの閾値に引っかかってしまうので、ネットワーク不調の場合等を考慮して上記の設定をたとえば5分とすると、マスターにて5分間イベントが発生がしない場合も(深夜、サービスが暇で更新クエリが発生しなかった等)スレーブの再接続が発生しちゃいます。

テスト

例えば、slavenettimeoutを3で設定なんかしちゃうと、、、、

1
2
3
4
5
6
7
8
9
-rw-rw---- 1 mysql mysql     302 Jan 24 18:43 relay-mysql-bin.000089
-rw-rw---- 1 mysql mysql     253 Jan 24 18:43 relay-mysql-bin.000090
-rw-rw---- 1 mysql mysql      74 Jan 24 18:43 relay-mysql-bin.index
..
3秒後には(3sec later)
..
-rw-rw---- 1 mysql mysql     302 Jan 24 18:43 relay-mysql-bin.000090
-rw-rw---- 1 mysql mysql     253 Jan 24 18:43 relay-mysql-bin.000091
-rw-rw---- 1 mysql mysql      74 Jan 24 18:43 relay-mysql-bin.index

鬼のような勢いでリレーログがローテートしていきます。夜な夜な結構な勢いでリレーログがローテートされてるサーバを想像すると、、、ちょっと残念な気持ちになっちゃいますよね。

MASTERHEARTBEATPERIOD!!

しかし大丈夫。そんな状況のためにMASTER_HEARTBEATという機能が存在します。ハートビートとは(説明するまでもないですが)生存確認のサインを主従の主より従に対して定期的に行うことです。これによって従は主が健常に役割を果たしていることを確認できます。言わずもがなですが、mysqlの場合はmasterがでよりslaveがになります。この機能を使うにはchange master toのMASTERHEARTBEATPERIOD項目を設定します。

1
2
3
4
# mysql
stop slave;
change master to MASTER_HEARTBEAT_PERIOD=1;
start slave;
1
2
3
4
5
6
7
8
9
-rw-rw---- 1 mysql mysql     156 Jan 24 18:44 relay-mysql-bin.000001
-rw-rw---- 1 mysql mysql     253 Jan 24 18:44 relay-mysql-bin.000002
-rw-rw---- 1 mysql mysql      74 Jan 24 18:44 relay-mysql-bin.index
...
3秒たっても(3sec later)
...
-rw-rw---- 1 mysql mysql     156 Jan 24 18:44 relay-mysql-bin.000001
-rw-rw---- 1 mysql mysql     253 Jan 24 18:44 relay-mysql-bin.000002
-rw-rw---- 1 mysql mysql      74 Jan 24 18:44 relay-mysql-bin.index

ほら大丈夫。ワシは死んでないぞ!!!暇かもしれんがな!!とマスターが1秒おきに教えてくれるおかげで、再接続が行われなくなります。

まとめ、というか個人的な好み

ネットワークがちょっと不安定な環境でのリプリケーションを行う場合はこの設定を環境に合わせて設定するのが吉だと思われます(万が一にも最悪1時間もリプリケーションがされないなんて、、、個人的には無理)。

幸いなことに私自身は比較的安定したネットワーク環境でサーバを構築していますが、個人的にはビビり症なので、以下な感じの設定値を今は採用してます。もちっと攻めても良いかな?と思ったりしますが、ばかみたいにハートビートを受け取るのもねぇ、、、と。

1
2
# my.cnf
slave_net_timeout=300 # default 3600 sec
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# mysql
change master to MASTER_HEARTBEAT_PERIOD=60;
{% endhighlight%}

設定値の確認等々はいかのコマンドから。


{% highlight bash%}
# mysql

SHOW STATUS LIKE '%heartbeat%';
+---------------------------+-------+
| Variable_name             | Value |
+---------------------------+-------+
| Slave_heartbeat_period    | 1.000 |
| Slave_received_heartbeats | 924   |
+---------------------------+-------+
2 rows in set (0.00 sec)

SHOW VARIABLES LIKE '%slave%';
+---------------------------+------------+
| Variable_name             | Value      |
+---------------------------+------------+
| init_slave                |            |
| log_slave_updates         | ON         |
| slave_compressed_protocol | OFF        |
| slave_exec_mode           | STRICT     |
| slave_load_tmpdir         | /tmp       |
| slave_max_allowed_packet  | 1073741824 |
| slave_net_timeout         | 3          |
| slave_skip_errors         | OFF        |
| slave_transaction_retries | 10         |
| slave_type_conversions    |            |
| sql_slave_skip_counter    | 0          |
+---------------------------+------------+
11 rows in set (0.00 sec)

おっと、設定がテスト時のままだった、、、、(新規案件の本番向けハードでこの記事用のデータをとった、、、)