ブラックホール触ってみた

# ブラックホールとは
![space_blackhole.png](https://qiita-image-store.s3.amazonaws.com/0/82712/acc3f60f-517d-83f5-98ec-eff391828623.png)
`ブラックホール（black hole）とは、極めて高密度かつ大質量で、強い重力のために物質だけでなく光さえ脱出することができない天体である`@[wikipediaより](https://ja.wikipedia.org/wiki/%E3%83%96%E3%83%A9%E3%83%83%E3%82%AF%E3%83%9B%E3%83%BC%E3%83%AB)

本物のブラックホールはどうでも良く、今回はMySQLストレージエンジンであるBLACKHO
LEを今更、本当に今更触ってみたいと思います。
このストレージエンジンはinsertを流しても実際に記録されることがないのですが、binlogファイルにはデータが吐かれるため、
slave側で受け取ることにより、負荷分散をするというものになります。

それでは実際に触ってみます。

# ローカルでレプリケーション環境構築

適当にdockerを使ってMySQLを動かしてみたいと思います。
docker-compose.yml

```
version: '3'
services:
    db-master:
        image: mysql:5.7.22
        ports:
            - 3306:3306
        volumes:
            - ./master.cnf:/etc/mysql/my.cnf
        environment:
            MYSQL_ROOT_PASSWORD: root
            MYSQL_USER: test
            MYSQL_PASSWORD: test
            MYSQL_DATABASE: test
    db-slave:
        image: mysql:5.7.22
        ports:
            - 3307:3306
        volumes:
            - ./slave.cnf:/etc/mysql/my.cnf
        environment:
            MYSQL_ROOT_PASSWORD: root
            MYSQL_USER: test
            MYSQL_PASSWORD: test
            MYSQL_DATABASE: test
```

master.cnfの中身（slave.cnfは`server-id=1002`に）

```
[mysqld]

log-bin=binlog

server-id=1001
```

起動
`docker-compose up`

### master側 
master status確認

```
mysql> show master status \G
*************************** 1. row ***************************
             File: binlog.000003
         Position: 154
     Binlog_Do_DB: 
 Binlog_Ignore_DB: 
Executed_Gtid_Set: 
```


### slave側
先ほどのmaster statusの情報を適応（ユーザはrootをそのまま使用…

```
change master to
    master_host='db-master',      
    master_user='root',               
    master_password='root', 
    master_log_file='binlog.000003',
    master_log_pos=154;                 
```

レプリケーション開始と確認

```
mysql> start slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> show slave status\G
	         Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
```


## DBとテーブル作成
master側で次のsqlを実行

```
CREATE DATABASE Christmas;

use Christmas;

create table present
(
	name varchar(255) not null,
    address varchar(255) not null,
	create_at timestamp default current_timestamp not null,
	update_at timestamp default current_timestamp not null
) ENGINE=BLACKHOLE CHARSET=utf8mb4;
```


# データを入れ込んで見る
レプリケーション環境が出来上がったので、master側に実際にデータを入れ込んでみようと思います。

```
mysql> INSERT INTO `Christmas`.`present` (`name`, `address`, `create_at`, `update_at`) VALUES ("PS4 Pro", "自宅", DEFAULT, DEFAULT);
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO `Christmas`.`present` (`name`, `address`, `create_at`, `update_at`) VALUES ("SSD 512GB", "自宅", DEFAULT, DEFAULT);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO `Christmas`.`present` (`name`, `address`, `create_at`, `update_at`) VALUES ("iPad Pro", "自宅", DEFAULT, DEFAULT);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO `Christmas`.`present` (`name`, `address`, `create_at`, `update_at`) VALUES ("Apple Pencil", "自宅", DEFAULT, DEFAULT);
Query OK, 1 row affected (0.01 sec)

mysql> select * from present;
Empty set (0.00 sec)
```

空っぽ…ブラックホールに吸い込まれたようです。
これをslave側で救うため、テーブルのエンジンを書き換えてみます。

`alter table present ENGINE=innodb;`

再度master側でinsert文を流し、slave側で確認をしてみます。

```
mysql> select * from present;
+--------------+---------+---------------------+---------------------+
| name         | address | create_at           | update_at           |
+--------------+---------+---------------------+---------------------+
| PS4 Pro      | 自宅    | 2018-12-22 14:46:55 | 2018-12-22 14:46:55 |
| SSD 512GB    | 自宅    | 2018-12-22 14:47:10 | 2018-12-22 14:47:10 |
| iPad Pro     | 自宅    | 2018-12-22 14:47:10 | 2018-12-22 14:47:10 |
| Apple Pencil | 自宅    | 2018-12-22 14:47:10 | 2018-12-22 14:47:10 |
+--------------+---------+---------------------+---------------------+
4 rows in set (0.00 sec)
```
無事データが入っていました！

ちなみにmaster側のidに対してauto_incrementをつけると次のように `Duplicate entry` で怒られるので注意してください。

`Could not execute Write_rows event on table Christmas.present; Duplicate entry '1' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY;`


# まとめ

ユーザのログをGAなどを使わずに自分のサーバに置きたい、メインのmasterDBに書き込み負荷を与えないレベルのログを残したい、といった際には便利かもしれません。
今回インクリメント周りを触りきれてないので、まだまだ検証しなければ行けなさそうです…！

以上、今更ブラックホールを触ってみたでした。
よい夜をお過ごしください。