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


ブラックホールとは


ブラックホール(black hole)とは、極めて高密度かつ大質量で、強い重力のために物質だけでなく光さえ脱出することができない天体である@wikipediaより

本物のブラックホールはどうでも良く、今回は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に書き込み負荷を与えないレベルのログを残したい、といった際には便利かもしれません。
今回インクリメント周りを触りきれてないので、まだまだ検証しなければ行けなさそうです…!

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