GA

2017/12/19

MySQLジャンキーにngx_mrubyを与えた結果

この記事は mod_mruby ngx_mruby Advent Calendar 2017 の18日目の記事です。
時間オーバーしてますごめんなさい。
本題に入る前に、この記事をご覧の方の中に “MySQL HTTP Plugin” をご存知の方はいらっしゃるでしょうか? (MySQL Casualな方々はこの辺でオチの予想がついたはず)
MySQL HTTP Pluginは2014年ころに MySQL Labs で公開されていた「実験室版」として配布されていて、 MySQLがHTTPをしゃべるようになるプラグイン です。
何言ってるのかよくわからないとか、誰得? とか思うかも知れませんが、そんな細かいことを気にしてはいけません。とにかく、MySQL(mysqld)がHTTPをしゃべったんです。
かつての面影(?)はこのあたりの記事とか資料に見て取ることができます。
MySQL Labsは「α前のステータスのプロダクトを取り敢えず出してみる場」らしいので(要出典)、 GAになってから1度もメジャーバージョンアップできずに最短ライフタイムサイクルで消えた ナントカ とは違い、まあそういうものだし当時は俺も「誰得wwww」とか言ってたんですが、
俺が遊び始めて「あー面白いかも」と思った途端に消える
という
いつもの流れになって寂しく思っていたところです。
「そこで ngx_mruby ですよ」
誰かの声が聞こえた気がしたので試してみました。 やってること自体は単なるHello, Worldです。

ngx_mrubyのインストールには nginxにngx_mrubyをインストールする - Qiita を大変参考にさせていただきました。 2014年のアドベントカレンダーの記事が3年経ってMySQLジャンキーを救う(?)、インターネッツですね。
あとはペパボの中の人にパッケージをビルドするヤーツも教えてもらいました。最終的にはこれで作ったrpmをインストールしています。便利!
ngx_mruby/build_config.rbconf.gem :github => 'mattn/mruby-mysql' だけ追加しました。
MySQLに接続しないソフトウェアに興味が持てなううんなんでもない。
/etc/nginx/conf.d/default.conf によしなにこんな記述を追加。 /query をエンドポイントにして後ろに渡されたクエリーをそのままローカルのmysqldに受け渡してJSONで戻す(えっ)
    location /query {
      mruby_content_handler_code '
        req = Nginx::Request.new
        sql = req.uri.gsub(/\/query\//, "")

        conn = MySQL::Database.new("127.0.0.1", "root", "", "world", 64057)
        ret= []

        conn.execute(sql) do |row, field|
          one_row= []
          for n in 0..field.count - 1 do
            one_row.push({field[n] => row[n]})
          end
          ret.push(one_row)
        end

        req.content_type = "application/json"
        Nginx.rputs JSON::stringify(ret)
      ';
    }
こんな感じ。
たったこれだけのものを書くのに結構長い時間がかかった。プログラム力の衰えを感じる。。
で、出来上がったMySQL HTTP Pluginごっこはこんな感じ。
$ http localhost/query/SELECT%20%2A%20FROM%20city%20LIMIT%203
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 287
Content-Type: application/json
Date: Tue, 19 Dec 2017 06:24:38 GMT
Server: nginx/1.13.7

[
    [
        {
            "ID": 1
        },
        {
            "Name": "Kabul"
        },
        {
            "CountryCode": "AFG"
        },
        {
            "District": "Kabol"
        },
        {
            "Population": 1780000
        }
    ],
    [
        {
            "ID": 2
        },
        {
            "Name": "Qandahar"
        },
        {
            "CountryCode": "AFG"
        },
        {
            "District": "Qandahar"
        },
        {
            "Population": 237500
        }
    ],
    [
        {
            "ID": 3
        },
        {
            "Name": "Herat"
        },
        {
            "CountryCode": "AFG"
        },
        {
            "District": "Herat"
        },
        {
            "Population": 186800
        }
    ]
]
おおなんかMySQL HTTP Pluginっぽい! ちなみに本家MySQL HTTP Pluginの出力結果はこんな感じでした。結構違う。
ってか実データとメタデータが分離されてた。それでよかったのか。。
$ http http://a:b@localhost:8080/sql/world/SELECT+%2A+FROM+city+LIMIT+3
HTTP/1.1 200 OK
Cache-control: must-revalidate
Connection: Keep-Alive
Content-Length: 1078
Content-Type: application/json
Pragma: no-cache
Server: MyHTTP 1.0.0-alpha

[
    {
        "data": [
            [
                "1",
                "Kabul",
                "AFG",
                "Kabol",
                "1780000"
            ],
            [
                "2",
                "Qandahar",
                "AFG",
                "Qandahar",
                "237500"
            ],
            [
                "3",
                "Herat",
                "AFG",
                "Herat",
                "186800"
            ]
        ],
        "meta": [
            {
                "catalog": "def",
                "charset": 63,
                "column": "ID",
                "database": "world",
                "decimals": 0,
                "flags": 16899,
                "length": 11,
                "org_column": "ID",
                "org_table": "city",
                "table": "city",
                "type": 3
            },
            {
                "catalog": "def",
                "charset": 33,
                "column": "Name",
                "database": "world",
                "decimals": 0,
                "flags": 1,
                "length": 105,
                "org_column": "Name",
                "org_table": "city",
                "table": "city",
                "type": 254
            },
            {
                "catalog": "def",
                "charset": 33,
                "column": "CountryCode",
                "database": "world",
                "decimals": 0,
                "flags": 16393,
                "length": 9,
                "org_column": "CountryCode",
                "org_table": "city",
                "table": "city",
                "type": 254
            },
            {
                "catalog": "def",
                "charset": 33,
                "column": "District",
                "database": "world",
                "decimals": 0,
                "flags": 1,
                "length": 60,
                "org_column": "District",
                "org_table": "city",
                "table": "city",
                "type": 254
            },
            {
                "catalog": "def",
                "charset": 63,
                "column": "Population",
                "database": "world",
                "decimals": 0,
                "flags": 1,
                "length": 11,
                "org_column": "Population",
                "org_table": "city",
                "table": "city",
                "type": 3
            }
        ],
        "status": [
            {
                "server_status": 34,
                "warning_count": 0
            }
        ]
    }
]



まあなんかよしなに楽しんでみました。実際のところ(MySQL的な文脈では)何に使えるだろう。。

2017/12/18

InnoDB: Fatal : Cannot initialize AIO sub-system でmysqldが起動しない…だと…

1サーバーにゴツゴツmysqldを詰め込んでいる環境で、ふとこんなエラーでmysqldが起動しなかった。
2017-12-18 17:50:38 12256 [Note] InnoDB: Using Linux native AIO
2017-12-18 17:50:38 12256 [Note] InnoDB: Using CPU crc32 instructions
2017-12-18 17:50:38 7f2b86333740 InnoDB: Warning: io_setup() failed with EAGAIN. Will make 5 attempts before giving up.
InnoDB: Warning: io_setup() attempt 1 failed.
InnoDB: Warning: io_setup() attempt 2 failed.
InnoDB: Warning: io_setup() attempt 3 failed.
InnoDB: Warning: io_setup() attempt 4 failed.
InnoDB: Warning: io_setup() attempt 5 failed.
2017-12-18 17:50:40 7f2b86333740 InnoDB: Error: io_setup() failed with EAGAIN after 5 attempts.
InnoDB: You can disable Linux Native AIO by setting innodb_use_native_aio = 0 in my.cnf
2017-12-18 17:50:40 12256 [ERROR] InnoDB: Fatal : Cannot initialize AIO sub-system
2017-12-18 17:50:40 12256 [ERROR] Plugin 'InnoDB' init function returned error.
2017-12-18 17:50:40 12256 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
2017-12-18 17:50:40 12256 [ERROR] Unknown/unsupported storage engine: InnoDB
2017-12-18 17:50:40 12256 [ERROR] Aborting

2017-12-18 17:50:40 12256 [Note] Binlog end
2017-12-18 17:50:40 12256 [Note] /usr/local/mysql5626/bin/mysqld: Shutdown complete
珍しい。
AIO関連のエラーなんてMySQL 5.5がGAになってしばらくの時代に、 変なファイルシステム(なんだか忘れた)の上にtmpdirを作ろうとして「そのファイルシステムはAIOに対応していない!」と怒られて以来な気がする。
そういえば最近見ないなアレ。CentOS 5.xがいかんかったのか。
取り敢えずファイルシステムを見てみるに、
# grep vg_00-lv_root /proc/mounts
/dev/mapper/vg_00-lv_root / xfs rw,relatime,attr2,inode64,logbsize=256k,sunit=512,swidth=3584,noquota 0 0
xfsであってAIO非対応な変なファイルシステムではない。 というか他のmysqldは元気でゴリゴリ動いているので、この1プロセスだけAIOがどうこう言われるのがそもそもおかしい。
ググると innodb_use_native_aio = 0 にすればいいよ! とか結構出てくる(というかエラーログもそういってる)けれど、Linux AIOが使えないはずはないんだからそれじゃ気持ちが悪い。
結局、ぐるぐる回って @yoheiaさん のところにたどり着いた。
libaio の aio コンテキスト数を調べる - ablog
# cat /proc/sys/fs/aio-max-nr
65536

# cat /proc/sys/fs/aio-nr
63056
うわーい、ぴっちぴち。
というわけで aio-max-nr を増やしたら無事起動するようになりました。
# echo 131072 > /proc/sys/fs/aio-max-nr
# cat /proc/sys/fs/aio-max-nr
131072
ibdファイルかなりオープンされてるのね…。ちょっと意外。
# lsof | grep mysqld | grep -c ibd
75451

2017/12/08

mikasafabric for MySQLのつらいところ

この記事は MySQL Casual Advent Calendar 2017 の8日目の記事です!
1週間前の記事、 日々の覚書: これが多分最後の「MySQL Fabricつらい」 でお焚き上げをしたMySQL Fabricですが、 世の中の物好きな会社 がMySQL Fabricをフォークして mikasafabric for MySQL として使っています。
今日はそのmikasafabric つらい つらくない話をします。ハンカチの用意はよろしいでしょうか。

取り敢えずぶっちゃけた話をするとPythonつらい。
  • どこにクローズ漏れがあるのか ファイルディスクリプターをリーク する
    • max_open_files の値まで突っ込む
    • 監視が Too many open files で転ける
    • フェイルオーバーしようとする
    • フェイルオーバー操作も Too many open files で転ける
    • しかもタイミングによっては open_files に空きができるのでフェイルオーバー操作が 一部だけ成功する という
_人人人人人人人人人人人_
> 控えめに言って地獄 <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^ ̄
接続しているMySQL Routerの数にある程度依存しているような気がしたので、 MySQL Procotolをしゃべっているところ をゴニョゴニョしているものの改善せず…。ボスけて。

↑のバグを踏んだ時、 Too many open files で処理が中途半端に転けたがためにクラスターとして変な状態になっちゃって、「バッキングストアのレコードを直接書き換えることによってフェイルオーバー」させる実績を解除した。つらい。
誰の役にも立たないと思いますが、 servers.modeservers.status をUPDATEするだけでは足りなくて、 groups.master_uuid もUPDATEしてあげないと promote がAssertion Failureで転けます。 しかもバッキングストアに永続化されているので何度再起動しても転けます。これを知らずにこの状態に陥った場合、大した台数でなければ teardown して再登録した方が速いかも知れません。
mysql> SELECT * FROM servers;
+--------------------------------------+-----------------+------+--------+--------+----------+
| server_uuid                          | server_address  | mode | status | weight | group_id |
+--------------------------------------+-----------------+------+--------+--------+----------+
| a95d3771-d667-11e7-acc6-0242ac110002 | 172.17.0.2:3306 |    3 |      3 |      1 | myfabric |
| ab07f0b9-d667-11e7-abd0-0242ac110003 | 172.17.0.3:3306 |    1 |      2 |      1 | myfabric |
| ae8c0955-d667-11e7-ad65-0242ac110004 | 172.17.0.4:3306 |    1 |      2 |      1 | myfabric |
+--------------------------------------+-----------------+------+--------+--------+----------+
3 rows in set (0.00 sec)

mysql> SELECT * FROM groups;
+----------+-------------+--------------------------------------+----------------------------+--------+
| group_id | description | master_uuid                          | master_defined             | status |
+----------+-------------+--------------------------------------+----------------------------+--------+
| myfabric | NULL        | a95d3771-d667-11e7-acc6-0242ac110002 | 2017-12-01 07:17:18.000000 |       |
+----------+-------------+--------------------------------------+----------------------------+--------+
1 row in set (0.01 sec)
あと、 groups.status は実はBIT型なので↑では NULL でもないのに表示がおかしいとか
mysql> desc groups;
+----------------+--------------+------+-----+---------+-------+
| Field          | Type         | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+-------+
| group_id       | varchar(64)  | NO   | PRI | NULL    |       |
| description    | varchar(256) | YES  |     | NULL    |       |
| master_uuid    | varchar(40)  | YES  | MUL | NULL    |       |
| master_defined | timestamp(6) | YES  |     | NULL    |       |
| status         | bit(1)       | NO   |     | NULL    |       |
+----------------+--------------+------+-----+---------+-------+
5 rows in set (0.00 sec)

mysql> SELECT CAST(status AS signed) FROM groups;
+------------------------+
| CAST(status AS signed) |
+------------------------+
|                      1 |
+------------------------+
1 row in set (0.00 sec)
暗黙のキャストに期待して UPDATE groups SET status = '0' とかやると
mysql> UPDATE groups SET status = '0' WHERE group_id = 'myfabric';
ERROR 1406 (22001): Data too long for column 'status' at row 1

mysql> UPDATE groups SET status = 0 WHERE group_id = 'myfabric';
Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> UPDATE groups SET status = b'1' WHERE group_id = 'myfabric';
Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> UPDATE groups SET status = 0b0 WHERE group_id = 'myfabric';
Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0
「あーINTからBITのキャストは出来るけど文字列だと直接BITにキャストできないのかー」とか「そういえば b'010111' みたいな記法あったよね」とか知ることができて新鮮です。

あとはMySQL Routerさんが
MySQL Fabric support was removed.
サポートやめちゃったので、今後MySQL Router 2.1以降に追随していくためにはこっちにもパッチを当てないといけない。 ( そもそもコンフィグパーサーから fabric+cache:// のハンドルが削り取られているので、シンタックスエラーとして扱われる。かなしい)
あー、課題は山積みだわー、つらいわー、mikasafabricほんとつらいわー(棒)
明日は @atsuizoさん で 「SELECT文をタイムアウト強制終了させる「MAX_EXECUTION_TIME」使ってる?」です!

2017/12/04

ConoHaの上でひたすらMySQLをビルドする簡単なお仕事

この記事は ConoHa Advent Calendar 2017 の4日目の記事です。
「ConoHaの上で」と銘打ってはいますが、俺の普段使いのLinux環境がConoHaだからというだけで、VirtualBoxだろうとEC2だろうとCentOS 7.4なら全部似たような結果になると思います
というわけでまずは吊るしのConoHaのVPSインスタンスを作ります。
最近のMySQLはビルドに結構メモリーを食うのでメモリーは1GBのものを選びました(512MBだと、途中でOOM Killerに殺されるかまたは永遠にビルドが終わらないと思います。5.7とそれ以降)
WEBからポチポチしてSSHでログインできたら、さっさとビルドを開始します。
まずは 5.0からいきましょう。
2017/12/04現在、サポートが継続されているMySQLは5.5, 5.6, 5.7の3系統です。
サポートが切れているMySQLのソースコードも MySQL :: MySQL Product Archives から手に入れることができます。
(が、ここでもMySQL Fabricは存在しません。 泣かない
というわけでMySQL 5.0系の最終バージョンである5.0.96を取ってきてさっくりビルドしてみます。

$ wget https://downloads.mysql.com/archives/get/file/mysql-5.0.96.tar.gz
$ tar xf mysql-5.0.96.tar.gz 
$ cd mysql-5.0.96/
$ ll
なんかパーミッションがスゴいことになっていて、時代のせいなのかパッケージングが出鱈目だったのか気になります。
MySQL 5.1とそれ以前のバージョンでは configure スクリプトを使って下準備をします。

$ ./configure --prefix=/opt/mysql/5.0.96
..
configure: error: in `/root/mysql-5.0.96':
configure: error: no acceptable C compiler found in $PATH
See `config.log' for more details.
あ、エラった。流石に gcc とかデフォで入っていない様子。
$ sudo yum install -y gcc
$ ./configure --prefix=/opt/mysql/5.0.96
..
checking for termcap functions library... configure: error: No curses/termcap library found
今度は別のエラー。cursesライブラリーがないって言われるけれどこれ ncurses-libs のことではなくて ncurses-devel のことなので注意(数年前にハマったなあ)
$ sudo yum install -y ncurses-devel
$ ./configure --prefix=/opt/mysql/5.0.96

..
Thank you for choosing MySQL!

Remember to check the platform specific part of the reference manual
for hints about installing MySQL on your platform.
Also have a look at the files in the Docs directory.
無事に終わったぽいので make
$ make
..
DEPDIR=.deps depmode=none /bin/sh ../depcomp \
g++ -DDEFAULT_BASEDIR=\"/opt/mysql/5.0.96\" -DMYSQL_DATADIR="\"/opt/mysql/5.0.96/var\"" -DDEFAULT_CHARSET_HOME="\"/opt/mysql/5.0.96\"" -DSHAREDIR="\"/opt/mysql/5.0.96/share/mysql\"" -DDEFAULT_HOME_ENV=MYSQL_HOME -DDEFAULT_GROUP_SUFFIX_ENV=MYSQL_GROUP_SUFFIX -DDEFAULT_SYSCONFDIR="\"/opt/mysql/5.0.96/etc\"" -DHAVE_CONFIG_H -I. -I../include -I../zlib -I../include -I../include -I.    -O -DDBUG_OFF    -fno-implicit-templates -fno-exceptions -fno-rtti -c -o my_new.o my_new.cc
../depcomp: line 571: exec: g++: not found
make[2]: *** [my_new.o] Error 127
make[2]: Leaving directory `/root/mysql-5.0.96/mysys'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/root/mysql-5.0.96'
make: *** [all] Error 2
C++コンパイラーの g++ が要るって(´・ω・`) だったら configure の段階で言ってよ!
$ sudo yum install -y gcc-c++
$ ./configure --prefix=/opt/mysql/5.0.96

$ make
gcc-c++を入れたら再 configure して(しないと make が通らなかった)もっかい makemake が終わったら make install--prefix で指定したパスにファイルをコピー。
$ sudo make install
はい5.0終わり。次5.1。
MySQL 5.1は5.0とそんなに変わらないので、同じくアーカイブのページから5.1系の最終バージョンである5.1.73を…あれ?
「いや、そのりくつはおかしい」と言いたくなるけれども取り敢えずアーカイブページには5.1.72までしかない。 特に切羽詰まっている(?)わけでもないので、今回は5.1.72でビルドすることにしよう。
$ wget https://downloads.mysql.com/archives/get/file/mysql-5.1.72.tar.gz
$ tar xf mysql-5.1.72.tar.gz
$ cd mysql-5.1.72
$ ./configure --prefix=/opt/mysql/5.1.72
$ make
$ sudo make install
特に詰まることもなく(5.0から追加で何か入れることもなく)5.1も終了。はい次5.5。
ここから現在サポートされているバージョンになるので、最新のマイナーバージョンであれば MySQL :: Download MySQL Community Server から、それ以前のマイナーバージョンであればまたアーカイブから取ってくることになる。
ダウンロードページでは5.7が全面に押し出されているけれども、「Looking for previous GA versions?」とか書いてあるのを探すと5.5と5.6へのリンクがあるのでそれを選んでダウンロード。
$ wget https://dev.mysql.com/get/Downloads/MySQL-5.5/mysql-5.5.58.tar.gz
$ tar xf mysql-5.5.58.tar.gz 
$ cd mysql-5.5.58/
$ cmake -DCMAKE_INSTALL_PREFIX=/usopt/mysql/5.5.58
-bash: cmake: command not found
MySQL 5.5とそれ以降では cmake を使って下準備をする。入ってなかったのでインストール。
$ sudo yum install -y cmake
$ cmake -DCMAKE_INSTALL_PREFIX=/usopt/mysql/5.5.58
..
-- Configuring done
-- Generating done
-- Build files have been written to: /root/mysql-5.5.58

$ make
$ sudo make install
あれ、意外とさっくり通ってしまった。まあいいや、5.5終わったので5.6。
$ wget https://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.38.tar.gz
$ tar xf mysql-5.6.38.tar.gz
$ cd mysql-5.6.38/
$ cmake -DCMAKE_INSTALL_PREFIX=/opt/mysql/5.6.38
$ make
$ sudo make install
このへんからビルドに時間がかかるようになってくる(´・ω・`)
が、特にエラーもなく終わったので次5.7。
MySQL 5.7から先は、同じようにダウンロードページからソースの.tar.gzを探すと「Compressed TAR Archive」と「Compressed TAR Archive, Includes Boost Headers」というのが見つかる。
これは MySQLは5.7.5からBoostを使うようになった からで、別で自分でBoostを入れているような人はBoost同梱版を選ぶ必要は特にない(けれど、バージョン決め打ちでBoostを欲しがるようなので、同梱版の方が絶対に楽だと思う)
$ wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-boost-5.7.20.tar.gz
$ tar xf mysql-boost-5.7.20.tar.gz
$ cd mysql-5.7.20
$ cmake -DCMAKE_INSTALL_PREFIX=/opt/mysql/5.7.20 -DWITH_BOOST=./boost
$ make
$ sudo make install
さて、5.7も案外何事もなく終わったので開発中の最新版8.0に行きましょう。
MySQL 8.0(2017/12/04現在、8.0.3-rc)も MySQL :: Download MySQL Community Server のページの中で「Development Releases」を探すと出てきます。
$ wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-8.0.3-rc.tar.gz
$ tar xf mysql-boost-8.0.3-rc.tar.gz
$ cd mysql-8.0.3-rc
$ cmake -DCMAKE_INSTALL_PREFIX=/opt/mysql/8.0.3 -DWITH_BOOST=./boost
$ make
$ sudo make install
:(;゙゚’ω゚’): あらフツーに通った…
もうちょっとなんかライブラリー要求されるかと思いましたが、意外とオプションなしなら通るものですね。
ちなみに、
$ du -sh /opt/mysql/*
66M     /opt/mysql/5.0.96
228M    /opt/mysql/5.1.72
342M    /opt/mysql/5.5.58
998M    /opt/mysql/5.6.38
1.9G    /opt/mysql/5.7.20
1.5G    /opt/mysql/8.0.3
5シリーズビルドするのに大体6時間くらいでした!
それでは楽しい MySQL on ConoHa ライフを!




2017/12/03

ytkit - Yoku-san no ToolKITの紹介

このエントリーは OSS紹介 Advent Calendar 2017 の3日目の記事です。
ytkit はMySQLの運用に使いそうなちょっとしたスクリプト群です。
2017/12/03現在、ytkitには2つのスクリプトが存在しています。

yt-binlog-groupby

mysqlbinlog の出力結果をパイプで受け取って、テーブルや時間単位でGROUP BYするためのスクリプトです。
前身は mysqlbinlog_lister.pl というスクリプトで、これをテスタブルに書き直して機能を追加したものが yt-binlog-groupby になります。
↑2年前のブログ記事から使い方は特に変わっていないですが、「バイナリーログから更新のホットスポットを探す」ために使います。
最近、 --verboseexec_time の中央値と最大値を出す機能を追加しました。スレーブ側のバイナリーログ( log_slave_updates が指定されている時)では exec_time が「マスターで実行された時刻」と「スレーブで実行された時刻」の差になるので、スレーブ遅延の時などにどの辺に問題があったのかを切り分けるのに使えるんじゃないかと期待しています。
$ mysqlbinlog -vv /path/to/binary-log | yt-binlog-groupby --cell=10m --group-by=time,table --verbose
binlog entries between 171018 14:40 and 171130 19:30
171018 14:40    healthcheckdb.test3     13071   mid:0   max:1
171020 19:00    d1.t1   1       mid:0   max:0
171020 19:20    mysqlslap.t1    3976    mid:0   max:1
171020 19:30    d1.t1   1       mid:0   max:0
171023 14:10    d1.t2   1       mid:0   max:0
171023 14:10    d1.t3   1       mid:0   max:0
171025 19:20    d1.t1   1       mid:0   max:0
171116 18:00    mysql.time_zone 1       mid:0   max:0
171117 20:20    d1.t2   2       mid:0   max:0
171117 20:20    d1.t3   2       mid:0   max:0
171121 19:10    d1.t1   1       mid:0   max:0
171124 17:00    d1.t1   1       mid:0   max:0
171128 12:40    test.t1 16      mid:0   max:0

yt-healthcheck

Nagiosの check_mysql を置き換えるために書いたスクリプトです。
MySQLを割と一人で300台管理する技術 の時に紹介した監視テクニックが実装されています(あ、生ログをダンプする部分移植してないことに気付いた…)
「パラメーターのチューニングをしなくてもある程度動く」「マスターとスレーブを入れ替えてもパラメーターを変更する必要はない」「案外忘れそうなものをワーニングで拾う」あたりを念頭に作られています。
$ yt-healthcheck -h 127.0.0.1 -P 5638 -umsandbox -pmsandbox
WARNING on slave: read_only should be ON but current setting is OFF
どちらも日々のMySQL運用で「ちょっとほしい」ものをまとめているので、どんな環境に持って行ってもある程度は動く気がします。 MySQLと仲良くなるためにご利用いただければ幸いです。
明日は @fujiwaraさん の「alp と Plack::Middleware::QueryCounter を合わせて使う話を書きます」 です!

2017/12/01

これが多分最後の「MySQL Fabricつらい」

やあ (´・ω・`)
ようこそ、MySQL Fabricのお墓へ。
このサキーラはサービスだから、まず飲んで落ち着いて欲しい。
うん、「やっぱり」なんだ。済まない。
地獄の沙汰もって言うしね、謝って許してもらおうとも思っていない。
でも、このスレタイを見たとき、君は、きっと言葉では言い表せない
「めきめき」みたいなものを感じてくれたと思う。
 殺伐とした世の中で、そういう気持ちを忘れないで欲しい
そう思って、この記事を書いたんだ。
じゃあ、注文を聞こうか。

さて本題。
この記事は MySQL Casual Advent Calendar 2017 の1日目の記事です。
全国1.000000人のユーザー(俺調べ)に 愛された MySQL Fabricが、2017/07 ついに(?)、 EOLになりました
つらい(´;ω;`)

MySQL Fabricが何 だったか については、2014年に書かれた 高可用性とデータ・シャーディングを実現できるMySQL Fabricとは? | Think IT(シンクイット) が詳しい。
自動フェイルオーバーによる高可用性と、参照/更新処理に対する負荷分散による拡張性を実現できます。そしてこれらをアプリケーションから意識することなく実現できる、という大きな利点があります。MySQL Fabricを使うと、MySQLサーバーの構成が変わってもアプリケーションからの接続先を変更する必要がありません。
事実、MySQL Fabric + MySQL Routerの構成でマスターのスイッチオーバーやフェイルオーバーはできるし、スレーブを追加しても mysqlfabric group add .. するだけで、アプリケーションはローカルに積み込んだ mysqlrouter に対して接続すればいいだけでコンフィグをいじる必要はない。
とても便利だ。 とても便利なはずだった。
でも流行らなかったので マイエスキューエル先生の次回作 にご期待くださいになってしまった。
 理由はいくつか想像していて、 2015年時点 でこんなことを言っていたようだ。
  1. Fabric対応コネクターが必要
  2. MySQL 5.6以上かつGTIDが必要
  3. バッキングストア(mysqlfabricデーモンが情報をストアするためのmysqld)を自前で冗長化しないといけない
  4. ググったら 「MySQL Fabric つらい」 とかサジェストされる
正直すまんかった。

MySQL Fabricはなんと GitHubのリポジトリーを削除される という憂き目に遭って、わずかに Launchpad にその姿をとどめるのみになっている。
MySQL Proxyのリポジトリーすら残ってるのに。
そこまで黒歴史扱いしなくても。。
俺が
夢を見ていて、そもそもリポジトリーなんて存在しなかったんじゃ? とか思ったけれど、バグレポートの中でURLを示しているものがあったので墓標の代わりにメモしておく。

が、しかしまあもう本番に組み込んじゃってるので、MySQL Fabricは死んでも mikasafabric for MySQL は生き続けるんじゃよ。
そしてmikasafabricに関する愚痴は MySQL Casual Advent Calendar 2017 の8日目でするんじゃよ。
それではバイバイ、MySQL Fabric。