mariadbのスレーブトリガーを試してみる。(slave_run_triggers)

# まえがき

mariadb10.1より、Running Triggers on the Slave for Row-based Eventsという機能が実装されました。
これを個人的(＆社内的)には、
**スレーブトリガー**
　　　　or
**レプリケーショントリガー**
などと呼称しています。

* [Running Triggers on the Slave for Row-based Events(mariadb公式knowledgeより)](https://mariadb.com/kb/en/mariadb/running-triggers-on-the-slave-for-row-based-events/)

大まかにいうと、

Aテーブルがレプリケーションで更新される→**AテーブルにしかけておいたトリガーでBテーブルを更新**

といった機能です。

この機能をうまく使えば、例えば以下のような事が可能になるかなと思っています。

## できそうなこと。 

* BI用のスレーブサーバがある。
* 以下の様なログイン日時の入っているテーブルをマスタ機からレプリケーションしているとする。

```sql
MariaDB [test]> SELECT * FROM login_log ;
+--------+--------+--------------+---------------------+
| SEQ_ID | LOGID  | UID          | LOGIN_DATE          |
+--------+--------+--------------+---------------------+
| 000001 | 111110 | K.HANAZAWA   | 2016-04-12 18:49:10 |
| 000002 | 111111 | T.AYANA      | 2016-04-12 19:00:39 |
| 000003 | 111112 | Y.OGURA      | 2016-04-12 19:02:30 |
| 000004 | 111113 | K.ISHIHARA   | 2016-04-12 19:34:21 |
| 000005 | 111114 | Y.HORIE      | 2016-04-12 21:11:48 |
| 000006 | 111115 | Y.TAMURA     | 2016-04-12 21:39:53 |
| 000007 | 111116 | T.AMAMIYA    | 2016-04-13 08:59:04 |
| 000008 | 111117 | Y.NAKAMURA   | 2016-04-13 08:59:46 |
| 000009 | 111118 | A.SAKURA     | 2016-04-13 09:00:26 |
| 000010 | 111119 | R.HIDAKA     | 2016-04-13 09:00:58 |
+--------+--------+--------------+---------------------+
10 rows in set (0.02 sec)

MariaDB [test]> 
```

* ログインする度にLOGIN_DATEが更新される。
* スレーブトリガーを利用して、LOGIN_DATEが更新される度に別テーブルに日次の累計ログイン回数を記録。

こんなイメージです。

```sql
MariaDB [test]> SELECT * FROM daily_login_count ;
+--------+--------+--------------+---------------------+---------------------+
| SEQ_ID | LOGID  | UID          | COUNT_DATE          | COUNT               |
+--------+--------+--------------+---------------------+---------------------+
| 000001 | 111110 | K.HANAZAWA   |          2016-04-12 |                  27 |
| 000002 | 111111 | T.AYANA      |          2016-04-12 |                  26 |
| 000003 | 111112 | Y.OGURA      |          2016-04-12 |                  20 |
| 000004 | 111113 | K.ISHIHARA   |          2016-04-12 |                  22 |
| 000005 | 111114 | Y.HORIE      |          2016-04-12 |                 318 |
| 000006 | 111115 | Y.TAMURA     |          2016-04-12 |                 318 |
| 000007 | 111116 | T.AMAMIYA    |          2016-04-13 |                  22 |
| 000008 | 111117 | Y.NAKAMURA   |          2016-04-13 |                  36 |
| 000009 | 111118 | A.SAKURA     |          2016-04-13 |                  22 |
| 000010 | 111119 | R.HIDAKA     |          2016-04-13 |                  21 |
+--------+--------+--------------+---------------------+---------------------+
10 rows in set (0.02 sec)

MariaDB [test]> 
```

* BI用のスレーブ機のみにトリガーをしかけるだけで済む。(少しでもマスターDBの負荷低減ができる。)
* DBだけで完結できる。(DBでやるかは賛否両論あると思いますが。)

早速この機能を試してみました。

## 動作イメージ図
![レプリケーショントリガーイメージ.gif](https://qiita-image-store.s3.amazonaws.com/0/36284/845795ee-c0bb-ee0e-ae19-0dbc0603f8fe.gif)

# 設定
## パラメータについて

公式ドキュメントには以下の通り書いてあります。

| Value      | Meaning     | 
|:-----------|------------:|
|NO (Default)|	Don't invoke triggers for Row-based events|
|YES|Invoke triggers for Row-based events, don't log their effect into the binary log|
|LOGGING|Invoke triggers for Row-based events, and log their effect into the binary log|

* YESはレプリケーションでもトリガー発動するけど、binlogには書かない。
* LOGGINGならトリガー発動しつつ、binlogにも書き込む(トリガーのかかったテーブルを更にレプリケーションするならこっち？)


## パラメータ設定(非永続的)

```sql
SET GLOBAL  slave_run_triggers_for_rbr = 0/1/2;  
```

* 0=NO(デフォルト)、1=YES、2=LOGGING

## パラメータ設定(永続的)

/etc/my.cnf.d/server.cnfに以下を追記して、mysqldを再起動。
```
slave_run_triggers_for_rbr=1
```

## パラメータ確認。

```sql
MariaDB [(none)]> SET GLOBAL  slave_run_triggers_for_rbr = 1;                                                            
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE '%rbr%';  
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| slave_run_triggers_for_rbr | YES   |
+----------------------------+-------+
1 row in set (0.00 sec)

MariaDB [(none)]> SET GLOBAL  slave_run_triggers_for_rbr = 2;
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE '%rbr%';  
+----------------------------+---------+
| Variable_name              | Value   |
+----------------------------+---------+
| slave_run_triggers_for_rbr | LOGGING |
+----------------------------+---------+
1 row in set (0.00 sec)

MariaDB [(none)]> SET GLOBAL  slave_run_triggers_for_rbr = 0;
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE '%rbr%';  
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| slave_run_triggers_for_rbr | NO    |
+----------------------------+-------+
1 row in set (0.00 sec)

MariaDB [(none)]> 

```

後は実際にテーブル用意して、TRIGGERを実装すれば、対象テーブルにスレーブトリガーが実行されるようになります。


# おまけ
## スレーブトリガーの挙動

| | マスタ側にトリガーあり|マスタ側にトリガーなし |
|:-----------|------------:|------------:|
|スレーブ側にトリガーあり(マスタと同名同じ内容)|マスタ側内容優先|スレーブトリガー発動|
|スレーブ側にトリガーあり(マスタと同名別内容)|マスタ側内容優先|スレーブトリガー発動|
|スレーブトリガーなし|マスタ側の内容が反映|-|

具体的な使い方の考案については、また後日。