[go: up one dir, main page]
More Web Proxy on the site http://driver.im/

GA

2015/12/31

2015年のMySQL 5.7騒動を振り返って

ポエムです。
もう1時間半ちょっとで年も明けますが、今年も色々な方にお世話になりました。ありがとうございました。


2015年は振り返るまでもなくMySQL 5.7漬けでした。
というか、去年はまだMySQL 5.7漬けじゃなかったんですね。そのことにむしろびっくり。もっと長い間 disり 調べ続けていたような気がします。

2015/03のPercona Liveに合わせてリリースされた(と思う) MySQL 5.7 最大のリリース、MySQL 5.7.6-m16 に始まり、あっという間にリリースされた MySQL 5.7.7-rc 、フィーチャーフリーズされずに出てきた MySQL 5.7.8-rc (RC2) 、それどころかフィーチャーフリーズされないまま、RC2からGAで機能追加がされているという MySQL 5.7.9-GA 。。

ちなみにMariaDB 10.0が 10.0.9(RC2) でフィーチャーフリーズせずに新機能を追加した時に「馬鹿なwwww」とか思った記憶があるんですが、見事にMySQLにブーメランになって返ってきましたね。アイタタタタ。

そしてMySQL史上類を見ない膨大な量のリリースノート。htmlタグ込みとはいえ、5.7.6だけじゃなくて他のも十分すごい。


$ curl -s http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-1.html | wc
   2631   13546  158162

$ curl -s http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-2.html | wc
   5028   26154  307853

$ curl -s http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-3.html | wc
   2392   11339  139404

$ curl -s http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-4.html | wc
   3056   14810  184922

$ curl -s http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-5.html | wc
   4322   22095  261145

$ curl -s http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-6.html | wc
   4760   24208  302234

$ curl -s http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-7.html | wc
   1471    6774   91604

$ curl -s http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-8.html | wc
   4178   21629  268333

$ curl -s http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-9.html | wc
   3054   14926  186386

$ curl -s http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-10.html | wc
   1278    5749   78511

こうしてみると確かに5.7.7は確かにRCだけど5.7.6から1か月くらいで出たし、印象薄いな。。
ともあれ、無事(大きな事故もなく?)GAとしてリリースされたMySQL 5.7、2年越しで(節目節目でとはいえ)更新を追っかけ続けて、結構疲れました。しばらくはこの1年間の貯蓄ででつつましく導入&運用していきたい感じ。

slideshare を見ても、4月MyNAのInnoDB FTSを皮切りにMySQL 5.7を(リライトも再演もやったので、結構な回数になった)積極的にやってきたんだなーって感じになりました。

やってきたんだなーっていうか、やりすぎたなーと思っています(二重の意味で)
"MySQL 5.7"で"罠"がサジェストされるとは。正直すまんかった。

「5.7はn倍速い」
「5.7は新機能がいっぱい」
うん、それは知ってる。でも気を付けなきゃユーザーが痛い目見るものもあるよね? それも紹介してよ。

そんなコンセプトでGAまで活動を続けた結果。


MySQL :: 資料ダウンロード > MySQL 最新情報セミナー2015秋 > MySQL 5.7 新旧パラメタ比較

「どこかの誰かさんがMySQL 5.7のパラメーターは罠い罠い言い続けた結果」
「お客様からも"5.7は罠なの?"とお問い合わせをいただくようになり」
「こんなものを用意した」

(∩´∀`)∩ワーイ

これが俺の今年の一番の成果であることは間違いありません。
これを「○racle公式の資料」として掲載するために、某氏とか某氏とか結構骨を折ってもらったんじゃないかという気もします。ありがとうございました。


あ、この資料、2015/12/31 22:16 JST時点の版だとlog_error_verbosityのデフォルト値が間違ってるので注意してくださいね :-P

それではまた来年もよろしくお願いします。
来年は何してるんだろうなー。

2015/12/25

MySQL Routerをlocalhostに置いたらどれくらいの遅延になるかを考えるメモと、MySQL Routerは本当につらくなかったのかのまとめ

この記事は MySQL Fabric&Routerつらくない Advent Calendar 2015 の25日目の記事です。

まずはどうやって遅延を計測しようか考えているメモをだだだと書きなぐる。後半にまとめっぽいものを。

計測環境。サーバーもクライアントもc4.xlarge。サーバーはyumリポジトリーで5.7.10を突っ込んで起動しただけ。


# rpm -i http://dev.mysql.com/get/mysql57-community-release-el6-7.noarch.rpm
# yum install -y mysql-community-server
# service mysqld start
# grep password /var/log/mysqld.log
# mysql -p
mysql> UNINSTALL PLUGIN validate_password;
mysql> CREATE USER yoku0825;

クライアントは接続してSELECT NOW()して切断するだけのもの。


$ cat -n test.cc
     1  #include <unistd.h>
     2  #include "mysql.h"
     3
     4  int main()
     5  {
     6    MYSQL mysql;
     7    int m;
     8
     9    mysql_init(&mysql);
    10
    11    for (m= 0; m <= 10000; m++)
    12    {
    13      mysql_real_connect(&mysql, "172.31.15.74", "yoku0825", "", NULL,
    14                         3306, NULL, 0);
    15      mysql_query(&mysql, "SELECT NOW()");
    16      MYSQL_RES *res= mysql_store_result(&mysql);
    17      mysql_close(&mysql);
    18    }
    19  }
$ gcc -I/usr/include/mysql -L/usr/lib64/mysql -lmysqlclient -g3 -O0 test.cc
$ time ./a.out

real    0m6.865s
user    0m0.248s
sys     0m0.552s

直接接続だと大体700usくらい。
c4.xlargeは4コアあるので4つ起動してみると


$ time (./a.out & ./a.out & ./a.out & ./a.out ; wait)


real    0m22.573s
user    0m0.508s
sys     1m10.168s

これくらい。ダメだ。ほとんどsysにもっていかれてる。まともに並列処理を書けるC力がほしい。
Routerはソースからコンパイル。サーバーホストだけを指定して単にプロキシーするだけの状態にする。


$ wget http://dev.mysql.com/get/Downloads/MySQL-Router/mysql-router-2.0.2.tar.gz
$ tar xf mysql-router-2.0.2.tar.gz
$ cd mysql-router-2.0.2
$ cmake .
$ make
$ sudo make install
$ sudo cp -ip /usr/local/share/doc/mysqlrouter/sample_mysqlrouter.ini /usr/local/etc/mysqlrouter/mysqlrouter.ini
$ sudo vim /usr/local/etc/mysqlrouter/mysqlrouter.ini
..
[routing:basic_failover]
# To be more transparent, use MySQL Server port 3306
bind_port = 7001
mode = read-write
destinations = 172.31.15.74
..

mysql_real_connectの向き先を127.0.0.1:7001に変えて、中央値は大体これくらい。


$ time ./a.out

real    0m8.816s
user    0m0.192s
sys     0m0.916s

$ time (./a.out & ./a.out & ./a.out & ./a.out ; wait)

real    0m9.761s
user    0m1.432s
sys     0m4.192s

コンテキストスイッチが減ってRouter経由の方が快適という結果に。top見てても遥かに良い感じ(mysqlrouterが100%張り付くので、a.outは20%くらいずつになる。これが結果として綺麗にキャップになっていい感じになるという。。)
もっとちゃんとしたクライアントだと、シングルスレッドのmysqlrouterが問題になってくると思う。取り敢えず、10秒で10000コネクション * 4プロセスだから4000connection/sならさばけてる(mysqlrouterの%usrが張り付くけど)

これを超えてくる場合、mysqlrouterのプロセスを複数起動して分散させることになるし、MySQL Routerはどうやら動的に設定を変えることはできないので、gracefulっぽくするためには



tcpdump + pt-query-digestでレイテンシーを見てみると、直接接続の場合はmysql_real_connectの中央値が467usにクエリーの中央値が152us。

# Query 1: 1.40k QPS, 0.70x concurrency, ID 0x5D51E5F01B88B79E at byte 42297981
# This item is included in the report because it matches --limit.
# Scores: V/M = 0.00
# Time range: 2015-12-24 10:33:50.782145 to 10:33:57.922968
# Attribute    pct   total     min     max     avg     95%  stddev  median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count         33   10000
# Exec time     75      5s   431us     1ms   498us   568us    39us   467us
# Rows affecte   0       0       0       0       0       0       0       0
# Query size    43 292.97k      30      30      30      30       0      30
# Warning coun   0       0       0       0       0       0       0       0
# String:
# Databases
# Hosts        172.31.5.70
# Users        yoku0825
# Query_time distribution
#   1us
#  10us
# 100us  ################################################################
#   1ms  #
#  10ms
# 100ms
#    1s
#  10s+
administrator command: Connect\G

# Query 2: 1.40k QPS, 0.22x concurrency, ID 0xF450CBDB69FA3A64 at byte 42299217
# This item is included in the report because it matches --limit.
# Scores: V/M = 0.00
# Time range: 2015-12-24 10:33:50.782371 to 10:33:57.923132
# Attribute    pct   total     min     max     avg     95%  stddev  median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count         33   10000
# Exec time     24      2s   142us   419us   159us   204us    16us   152us
# Rows affecte   0       0       0       0       0       0       0       0
# Query size    17 117.19k      12      12      12      12       0      12
# Warning coun   0       0       0       0       0       0       0       0
# String:
# Databases
# Hosts        172.31.5.70
# Users        yoku0825
# Query_time distribution
#   1us
#  10us
# 100us  ################################################################
#   1ms
#  10ms
# 100ms
#    1s
#  10s+
# EXPLAIN /*!50100 PARTITIONS*/
SELECT NOW()\G


Router経由だと固定でレイテンシーがあがるだけだと思ってたけど、Connectの方がぁゃιぃ。フツーのクエリーを計測するよりも(ルーティング判定のぶん)コストが高そう。もうちょっと別のクエリーも投げるパターンにして計測しないとダメだ。

単純クエリーで10usくらいの差なら、まともなクエリーになるに従って十分問題ないと見ていいはず。あ、でも、往復のパケット量が増えればそれぞれのパケットにレイテンシーが載るから結果セットが転送されきるまでのレイテンシーは無視できないのかも知れない。これも計測パターン増やさないと。


# Query 1: 1.07k QPS, 0.62x concurrency, ID 0x5D51E5F01B88B79E at byte 5655092
# This item is included in the report because it matches --limit.
# Scores: V/M = 0.00
# Time range: 2015-12-24 10:35:26.307560 to 10:35:35.641810
# Attribute    pct   total     min     max     avg     95%  stddev  median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count         33   10000
# Exec time     76      6s   488us     1ms   581us   690us    65us   541us
# Rows affecte   0       0       0       0       0       0       0       0
# Query size    43 292.97k      30      30      30      30       0      30
# Warning coun   0       0       0       0       0       0       0       0
# String:
# Databases
# Hosts        172.31.5.70
# Users        yoku0825
# Query_time distribution
#   1us
#  10us
# 100us  ################################################################
#   1ms  #
#  10ms
# 100ms
#    1s
#  10s+
administrator command: Connect\G

# Query 2: 1.07k QPS, 0.19x concurrency, ID 0xF450CBDB69FA3A64 at byte 45635077
# This item is included in the report because it matches --limit.
# Scores: V/M = 0.00
# Time range: 2015-12-24 10:35:26.307968 to 10:35:35.642044
# Attribute    pct   total     min     max     avg     95%  stddev  median
# ============ === ======= ======= ======= ======= ======= ======= =======
# Count         33   10000
# Exec time     23      2s   145us   577us   174us   214us    28us   159us
# Rows affecte   0       0       0       0       0       0       0       0
# Query size    17 117.19k      12      12      12      12       0      12
# Warning coun   0       0       0       0       0       0       0       0
# String:
# Databases
# Hosts        172.31.5.70
# Users        yoku0825
# Query_time distribution
#   1us
#  10us
# 100us  ################################################################
#   1ms
#  10ms
# 100ms
#    1s
#  10s+
# EXPLAIN /*!50100 PARTITIONS*/
SELECT NOW()\G

MySQL Fabricが載ってくると当然結果は変わるだろうから、次はFabric Cache Pluginバージョンも試す(台数がかさむなぁ。。)

ダラダラ書いたけど、次に測らないといけないところはわかった気がする。


さて、本題(?)

MySQL Routerは本当につらくなかったのか?

残念ながら つらくなかったです。


# 情報量(主にドキュメント)

* 初期のMySQL Fabricはひどかった。
* それよりは、今のMySQL Routerはマシ。
* ただし、今のMySQL Fabricの方がMySQL Routerより情報ある(と思う)
* つまり、結局は今後に期待。
  * ただ、MySQL FabricよりはMySQL Routerの方が流行ると思うので、日本語の情報も充実していくんじゃないかなぁ。

# 安定性

* MySQL Fabricも良くなってるんじゃないか疑惑
  * 去年試してた時 は結構さっくり刺さってハングしてたけど、今年は1回も突き刺さってない
* MySQL Routerは取り敢えず安定。Fabric Cache Plugin使ってる時の動作が若干不安…?
  * 再現しないので、要追試。

# 使いやすさ、使いたさ

## MySQL Fabric

* グラフィカルなCLIでレプリケーションクラスターの管理。したい。
* GTID依存なので、まずGTIDをONにして回るのが大変。
  * バックアップからリストアしたやつをレプリケーションクラスターに追加とかもGTID依存なので、5.6だと苦労しそう(5.7ならきっといける)
  * GTID依存だからこそ色々簡単なんだよなー、と思うとGTIDはやっぱりいいものだったのだな。
  * MariaDBさんがいるとダメ(GTIDの実装が全然違って互換性がない)
* いろんな実装がコネクター依存すぎてブラックボックスが超怖い。Connector/Jでは上手くいくけど他はダメとかフツーにありそう。

## MySQL Router

* 次世代MySQL Proxyとして使い始められる
  * スレーブの分散、Routerに置き換えようかと真面目に検討中。
  * Lua書かなくていい。ただし、MySQL RouterのプラグインはC++な上にドキュメントがまだないぽい。
* Fabric Cache PluginはMySQL Fabricのブラックボックスを解消するものなので、とてもイケていると思う。
  * ただ、アレだけで1章書いてもいいんじゃないかってくらいもっと説明して欲しいところがいっぱいある。。
* MySQL Fabricと連携させないなら、4.0 5.5とかでもイケるんじゃないかな(old_passwordの壁があるか…?)

# デバッグとソースコードリーディング

* MySQL FabricはPythonで、俺のPython力の欠如によりつらかった
  * ゆるぼ: Pythonista
* MySQL RouterはC++でgdbで突き刺すスタイルなのでデバッグが楽
* とはいえこれはMySQLオタク向けの項目なので、ほとんどの人には無縁

というわけで!

つらくないよ!

つらくないから、僕と結託して 地雷 MySQL Router友達になってよ!

お待ちしております :)

ConoHaで自作Billing Alertを使っているはなし

このエントリーは ConoHa Advent Calendar 2015 の25日目のエントリーです。メリークリスマス!

22日目に既に ConoHaちゃんが好きすぎるので、WebAPIを叩くためのGemを(途中まで)作ってみた という記事がありますが、どう見てもカブっています本当にありがとうございました。
(わたしはConoHaちゃんが好きすぎて作ったわけではないですが)

TL;DR

すぐに落とせば大丈夫だと思ってConoHaの一番高いヤーツでベンチマークを流したら、消すのを忘れて痛い目を見た(巷で噂になっているアレほどではない)

ちなみに 論理削除Casual Talks のときの、「tpcc-mysqlを論理削除に魔改造したらどれくらい速く / 遅くなるか」というものすごくどうでもいいベンチマークに使いました。つらい。

使い方

$ git clone https://github.com/yoku0825/p5-conoha-api.git
$ cd p5-conoha-api
$ cpanm --installdeps .
$ ppit set conoha
---
"password": 'your_api_password'
"tenantId": 'your_tenantId'
"username": 'your_api_username'
$ bin/conoha-billing
775

( ゚д゚) あら簡単

自分用なので色々投げやりです。username, password, tenantIdはConfig::Pitに"conoha"で設定されているとハードコードしてあります。きっと車輪の再発明で、どこにでもいくらでもクライアントは転がってそうなんですが、調べるよりはHTTP::Tinyで書いた方が早いなと思って自分に必要なものだけbinに詰めた感じ。

基本的にTokenさえ取ってdefault_headersに詰めた後はどうにでもなるので、使いたいAPIが出てきてから拡張するのは難しくない、はず。

bin/conoha-billingは単に最新のinvoiceを取ってきて数字だけぬるっと返すので、cronに

$ crontab -l
0 10 * * * [ $(/home/yoku0825/git/p5-conoha-api/bin/conoha-billing) -gt 1000 ] && (echo "Billing alert!!" | mail -s "conoha billing alert" yoku0825@gmail.com)

としておくだけで、簡単に事故は防げるわけです。がんばれ、過去の俺。

yoku0825/p5-conoha-api



ちなみに普段、ConoHaのVPSは
* MroongaのDockerイメージをビルドしたりテストしたり
* rpmパッケージをビルドしたり
* MySQLのソースコード読むのに使ってたり
* Slackに定期的にポストを投げ込んでくれるbotがDockerコンテナーで動いてAPIの口を開けてたり
* GitBucketのDockerコンテナーが動いていたり
* MySQLが4つくらい起動していたり
* MySQL Routerがつらくなかったり
します。

グローバルIP持っててお安いのはいいですね(でもDockerとか色々詰め込んでるから、現プランのSSD 50GBより旧プランの100GBの方が良かったかな。。)

ちなみに3次元のこのはちゃんは初代の人がすきです :)


それでは、良いお年を。

2015/12/17

「MySQL 5.8に欲しい機能は?」って中の人がブログ書いてる件を3か月遅れで

Oracle MySQLの中の人、コミュニティーチームの Morgan Tocker のブログに、"MySQL 5.8に欲しい機能は?" とかいう、どストレートな記事がある。このエントリーはこのブログ…に寄せられた主に コメント の紹介。ブログ本文はタイトルがほぼ説明してるので。



記事自体は2015/09/14のものでちょっと古い(MySQL 5.7がRC2になったから、MySQL 5.8のプランを練ってる、みたいな書き方)んだけれど、出揃ったコメントが結構バラエティーに富んでいて、みんな本当に欲しいものが何なのかちょっと気になる。

以下、コメントの意訳。

人気なのは窓関数とWITH句、データディクショナリー (ただしこれは5.8に既にpushされたっぽいのが クローズされたバグレポ から伝わってくる)、CHECK制約あたり。IPv6データ型がちょっと意外。

( ´-`).oO(マテビューって言われないあたりがMySQLぽい

個人的にはCHECK制約とちゃんとしたUnicode実装(あるいはutf8mb4_japanese_ci)は是非欲しい。FULL OUTER JOINも欲しいなー。バイナリーログの有効/無効のオンライン化はされそうな雰囲気がある(ソースは一切ないけど、5.7からの流れ的に)
欲を言うなら Perlで 他の言語でストアドプロシージャ書きたいし、パラレルクエリーは夢があっていい。

個人的には
* ストレージエンジンをまたいだパーティショニング
  * 今はストレージエンジンもROW_FORMATも同一でないといけない
    * パーティション単位でCOMPRESSION= 'zlib'とかしたい
    * パーティション単位で古いのはMyISAMとかしたい
      * MyISAMオワコン言わない
* プライマリーキーに依存しないパーティショニング
  * サロゲートキーとdateの複合プライマリーキーはもううんざりだ。。
* ALTER TABLEでのmyisampack
  * MyISAMオワコン言わない。。
* もっと賢いコマンドラインクライアント、たとえば mycli みたいな。
* information_schema.innodb_buffer_pageの代わりになるようなperformance_schema
が欲しいです。

サンタさん、いい子にしてますのでよろしくお願いします。


よければみなさんの欲しい機能も教えてください :)

2015/12/14

MySQL Routerつらくない(Dockerで誰でも試せるMySQL Fabric Cache Plugin編)

この記事は MySQL Fabric&Routerつらくない Advent Calendar 2015 の14日目のエントリーです。

前回の記事で無事にMySQL Fabric Cache Pluginでマスター/スレーブの構成をMySQL Fabricに管理させつつ、コネクションはMySQL Routerでハンドルさせることができたので、みなさんそろそろ

「MySQL Router つらくない!」
「MySQL Fabirc つらいけど 試してみたい!」

とテンションが上がっているところだと思います。
お願いします、上げてください。

日々の覚書: MySQL Routerつらくない(MySQL Fabricと組み合わせて使ってみる編)


という訳で、このアドベントカレンダーのために用意した一連のDockerイメージ群を紹介します。



さてじゃあ使い方。真っ新なAmazon Linux AMI 2015.09.1のEC2のインスタンスを20GBのEBSで起動したところからなので、他の環境でもほぼ応用が利くはず。
まずはMySQL Fabricサーバー(mysqlfabricのデーモン(いやフォアグラウンドだけど)とバッキングストアのmysqld)を起動。

# yum install docker
# service docker start
# docker run -d --hostname=mysql-fabric --name mysql_fabric_server yoku0825/mysql_fabric_server
..
# docker inspect -f "{{.Config.Hostname}}, {{.NetworkSettings.IPAddress}}" mysql_fabric_server
mysql-fabric, 172.17.0.1

次にMySQL Fabricにすぐ組み込める状態になっているMySQLサーバーを3台起動。


# docker run -d --hostname=mysql-server1 --name mysql_server1 yoku0825/mysql_fabric_aware
..
# docker run -d --hostname=mysql-server2 --name mysql_server2 yoku0825/mysql_fabric_aware
..
# docker run -d --hostname=mysql-server3 --name mysql_server3 yoku0825/mysql_fabric_aware
..
# docker inspect -f "{{.Config.Hostname}}, {{.NetworkSettings.IPAddress}}" $(docker ps | awk '/mysql_fabric_aware/{print $1}')
mysql-server3, 172.17.0.4
mysql-server2, 172.17.0.3
mysql-server1, 172.17.0.2

コマンドラインクライアントとしてのmysqlfabricも`docker run`で起動。MySQL Utilitiesをインストールしなくても試せる! つらくない!
`mysqlfabric group create`でmy_new_fabricというグループを作成。


# docker run --rm yoku0825/mysql_fabric_command --param=protocol.xmlrpc.address=172.17.0.1:32274 group create my_new_fabric
..
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                                uuid finished success result
------------------------------------ -------- ------- ------
69700c6c-bbd2-4371-9940-1c4e1e0c259a        1       1      1

state success          when                                                   description
----- ------- ------------- -------------------------------------------------------------
    3       2   1.45008e+09 Triggered by <mysql.fabric.events.Event object at 0x25af890>.
    4       2   1.45008e+09                             Executing action (_create_group).
    5       2   1.45008e+09                              Executed action (_create_group).


MySQL Fabricサーバーにグループが作成できたら、Fabric-awareなMySQL(MySQL Fabricで管理される側のサーバーをそんな風に呼ぶらしい。正しくないかも知れない)を1つずつ3つ追加。


# docker run --rm yoku0825/mysql_fabric_command --param=protocol.xmlrpc.address=172.17.0.1:32274 group lookup_groups
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

     group_id description failure_detector master_uuid
------------- ----------- ---------------- -----------
my_new_fabric        None                0        None


# docker run --rm yoku0825/mysql_fabric_command --param=protocol.xmlrpc.address=172.17.0.1:32274 group add my_new_fabric 172.17.0.2
..
# docker run --rm yoku0825/mysql_fabric_command --param=protocol.xmlrpc.address=172.17.0.1:32274 group add my_new_fabric 172.17.0.3
..
# docker run --rm yoku0825/mysql_fabric_command --param=protocol.xmlrpc.address=172.17.0.1:32274 group add my_new_fabric 172.17.0.4
..

# docker run --rm yoku0825/mysql_fabric_command --param=protocol.xmlrpc.address=172.17.0.1:32274 group lookup_servers my_new_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address    status      mode weight
------------------------------------ --------------- --------- --------- ------
14f81155-a23b-11e5-aa7e-0242ac110002 172.17.0.2:3306 SECONDARY READ_ONLY    1.0
15548339-a23b-11e5-aa35-0242ac110003 172.17.0.3:3306 SECONDARY READ_ONLY    1.0
1591026a-a23b-11e5-aa28-0242ac110004 172.17.0.4:3306 SECONDARY READ_ONLY    1.0

登録できたら、1台をマスターに昇格させる。`mysqlfabric group promote`してやると、1台をマスターに、それ以外をそのマスターのスレーブにするように構成してくれるので、


# docker run --rm yoku0825/mysql_fabric_command --param=protocol.xmlrpc.address=172.17.0.1:32274 group promote my_new_fabric
..

docker run --rm yoku0825/mysql_fabric_command --param=protocol.xmlrpc.address=172.17.0.1:32274 group lookup_servers my_new_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address    status       mode weight
------------------------------------ --------------- --------- ---------- ------
14f81155-a23b-11e5-aa7e-0242ac110002 172.17.0.2:3306 SECONDARY  READ_ONLY    1.0
15548339-a23b-11e5-aa35-0242ac110003 172.17.0.3:3306 SECONDARY  READ_ONLY    1.0
1591026a-a23b-11e5-aa28-0242ac110004 172.17.0.4:3306   PRIMARY READ_WRITE    1.0

はい、これでMySQL Fabric側完成。


# cat mysqlrouter.ini
[fabric_cache:docker_demo]
address     = 172.17.0.1
user        = admin

[routing:master]
bind_address= 0.0.0.0:13306
mode        = read-write
destinations= fabric+cache://docker_demo/group/my_new_fabric

[routing:slave]
bind_address= 0.0.0.0:23306
mode        = read-only
destinations= fabric+cache://docker_demo/group/my_new_fabric

mysqlrouter.iniはルーティング部分がDockerイメージに組み込まれてない(docker build時に指定すると固定になっちゃう && パラメーターではなくiniファイルで指定しないといけないぽい)ので、iniファイルを適当に作ってやって
日々の覚書: MySQL Routerつらくない(MySQL Fabricと組み合わせて使ってみる編)


# docker run -d -v /root/mysqlrouter.ini:/tmp/setup/router.ini yoku0825/mysql_router
..

# docker inspect -f "{{.Config.Hostname}}, {{.NetworkSettings.IPAddress}}" mysql-router
mysql-router, 172.17.0.17

あとはMySQL Routerの指定したポート(↑の場合は13306がマスター用のread-writeモード、23306がスレーブ用のread-onlyモード)を叩いてやれば


# mysql -h 172.17.0.17 -P 13306 -u ap

mysql> SELECT @@hostname;
+---------------+
| @@hostname    |
+---------------+
| mysql-server3 |
+---------------+
1 row in set (0.00 sec)

# docker run --rm yoku0825/mysql_fabric_command --param=protocol.xmlrpc.address=172.17.0.1:32274 group lookup_servers my_new_fabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid         address    status       mode weight
------------------------------------ --------------- --------- ---------- ------
14f81155-a23b-11e5-aa7e-0242ac110002 172.17.0.2:3306 SECONDARY  READ_ONLY    1.0
15548339-a23b-11e5-aa35-0242ac110003 172.17.0.3:3306 SECONDARY  READ_ONLY    1.0
1591026a-a23b-11e5-aa28-0242ac110004 172.17.0.4:3306   PRIMARY READ_WRITE    1.0

ちゃんと一致してますね! (mysql-server$nとIPアドレスの末尾1バイトが微妙にズレてるので見にくかった。。)

これで誰でもMySQL Routerで遊べる! つらくない!


このへんとかも合わせてご利用ください。 https://github.com/yoku0825/docker_for_mysqlfabric/blob/master/start_3container_fabric.sh

2015/12/11

MySQL Routerつらくない(MySQL Fabricと組み合わせて使ってみる編)

この記事は MySQL Fabric&Routerつらくない Advent Calendar 2015 の10日目のはずだったけれど日付が変わっちゃった残念な記事です(´・ω・`)


$ mysqlfabric --param=protocol.xmlrpc.address=172.17.3.202:32274 group lookup_servers myfabric
Fabric UUID:  5ca1ab1e-a007-feed-f00d-cab3fe13249e
Time-To-Live: 1

                         server_uuid           address    status       mode weight
------------------------------------ ----------------- --------- ---------- ------
7dbe3da8-9f4f-11e5-ad3e-0242ac1103ce 172.17.3.206:3306 SECONDARY  READ_ONLY    1.0
81392c70-9f4f-11e5-ad15-0242ac1103d0 172.17.3.208:3306 SECONDARY  READ_ONLY    1.0
84d6578f-9f4f-11e5-ad3b-0242ac1103d2 172.17.3.210:3306   PRIMARY READ_WRITE    1.0

まずはこんなレプリケーションを組んでMySQL Fabricに登録させておく。
MySQL FabricのIPアドレスは172.17.3.202。MySQL RouterのIPアドレスは172.17.3.218。
MySQL Fabric上のグループ名はmyfabric。


[fabric_cache:dummy]
address     = 172.17.3.202
user        = admin

[routing:master]
bind_address= 0.0.0.0:13306
mode        = read-write
destinations= fabric+cache://dummy/group/myfabric

[routing:slave]
bind_address= 0.0.0.0:23306
mode        = read-only
destinations= fabric+cache://dummy/group/myfabric

MySQL Routerに追加したコンフィグはこんな感じ。
日々の覚書: MySQL Routerつらくない(yumでインストールして動かしてみた編) の時にはIPアドレスを直書きしていたdestinationsに、 "fabric+cache://.."でFabric Cacheプラグインを指定できる。

まずはfabric_cache:* セクションでMySQL Fabricサーバーの情報を定義する。コロンのあとはMySQL Fabricを一意に識別する識別子になる。今回はdummyにしてみた。
addressはMySQL FabricサーバーのIPアドレス。特別指定してない場合はポート32275(MySQL FabricがMySQLプロトコルを喋る方のポート)に接続しに行く。
userはMySQLサーバー側のユーザーではなく、MySQL Fabricのユーザー(`mysqlfabric manage setup`した時に聞かれるやつ)

routing:*セクションで前回と変わってるのはdestinationsのところだけ。"fabric+cache://"は決め打ち、"dummy"の部分がfabric_cache:*セクションで命名した名前、"group"は今のところ決め打ち(たぶん、`mysqlfabric group lookup_servers myfabric` のgroupだと思う)、最後がMySQL Fabric上のグループ名。今回はmyfabric。


$ mysql -h 172.17.3.218 -P 13306 -u ap

mysql> SELECT current_user();
+----------------+
| current_user() |
+----------------+
| ap@%           |
+----------------+
1 row in set (0.00 sec)

mysql> SELECT @@hostname;
+--------------+
| @@hostname   |
+--------------+
| a714ddbc4a72 |
+--------------+
1 row in set (0.00 sec)

MySQL Fabricの向こう側、実際のMySQLサーバーに接続するためのユーザー名はクライアント側が指定する。


$ mysql -h 172.17.3.218 -P 23306 -u ap -e "SELECT @@hostname"
+--------------+
| @@hostname   |
+--------------+
| 3a72ab61519c |
+--------------+

$ mysql -h 172.17.3.218 -P 23306 -u ap -e "SELECT @@hostname"
+--------------+
| @@hostname   |
+--------------+
| 548859aa0c72 |
+--------------+

$ mysql -h 172.17.3.218 -P 23306 -u ap -e "SELECT @@hostname"
+--------------+
| @@hostname   |
+--------------+
| 3a72ab61519c |
+--------------+

$ mysql -h 172.17.3.218 -P 23306 -u ap -e "SELECT @@hostname"
+--------------+
| @@hostname   |
+--------------+
| 548859aa0c72 |
+--------------+

スレーブ側に割り当てたポート23306にアクセスすれば、ラウンドロビン。

え、なんかこれホントにつらくなくない…?


MySQL :: MySQL Router :: 5.2 Fabric Cache Plug-in

2015/12/10

sqlplusのお供、rlwrapのオプションについて調べてみた

この記事は JPOUG Advent Calendar 2015 の10日目の記事です。

残念ながら私は全くOracleというDBMSが使えません。どれくらい使えないかというと、

SQL> SHOW DATABASES;
SP2-0158: unknown SHOW option "DATABASES"

( ゚д゚)ノ せんせー、このDBMSダメなやつです!

というくらい使えません。PostgreSQLだったらまだコマンドラインクライアントをゴニョって`SHOW DATABASES`で一覧を出すくらいのことは出来たんですが、sqlplusだとそういう訳にも行きませんね、このクローズドソース野郎!!1

という訳で、sqlplus使い御用達(と聞いている) rlwrap の話をしようと思います。わたしは groonga (コマンドラインクライアントの方)でrlwrapをよく使いますが、初めてオプションを調べてみたので記録しておきます。

有名な話だったらごめんなさい。


まずは単に起動。

$ rlwrap sqlplus

SQL*Plus: Release 11.2.0.4.0 Production on Mon Dec 7 18:52:56 2015

Copyright (c) 1982, 2013, Oracle.  All rights reserved.

Enter user-name: supersuper
Enter password: **********


とまあこの通りパスワード部分はreadlineを通らず、"*"でマークされました。
Enter叩いた瞬間に"*"も消えました。sqlplus、こんな動作なのか。

そしてそこで有名なやつとして-aオプションを足してみると

$ rlwrap -a sqlplus

SQL*Plus: Release 11.2.0.4.0 Production on Mon Dec 7 18:59:45 2015

Copyright (c) 1982, 2013, Oracle.  All rights reserved.

Enter user-name: supersuper
Enter password: top_s3cret


如何にもありそうな感じで、剥き出しでパスワードが表示される。本来、パスワードっぽいものを遠慮してreadlineに流さずにやってるのを、全部readlineに通してそのあとNL契機でsqlplusに渡してるんですね、たぶん。"*"の時と同じくエンター叩いた瞬間に消えますが、SQLのプロンプトで↑キーを押すと


SQL> top_s3cret

履歴に出た━━━━(゚∀゚)━━━━!!
readlineに渡るとhistory_fileにも書くからか。そうか、確かにそうだけど面白い。


$ rlwrap -a"Enter password:" sqlplus

SQL*Plus: Release 11.2.0.4.0 Production on Mon Dec 7 19:02:19 2015

Copyright (c) 1982, 2013, Oracle.  All rights reserved.

Enter user-name: supersuper
Enter password: **********

-aオプションの直後(スペース文字を入れると、「スペース入れるな!」って怒られた)に指定した文字列が来た時は、パスワードだと見做してreadlineを通さなくなる、様子。
ちなみに"Enter password:"の状態で-aオプション *無し* の時でも *↑↓キーによる履歴呼び出しが可能* なので、一度パスワードが記録されると何となく雰囲気でログインできるかも知れない。


$ rlwrap -p"YELLOW" sqlplus

SQL*Plus: Release 11.2.0.4.0 Production on Mon Dec 7 19:15:38 2015

Copyright (c) 1982, 2013, Oracle.  All rights reserved.

Enter user-name: supersuper
Enter password:

う、テキストべた張りだと感動が伝わらないと思いますが、プロンプトが全て黄色太文字になってます。
"yellow"だと太文字ではない様子。"RED"だと赤太文字、"red"だと赤細文字でした。へーすごい。MySQLでいうところの--pagerにカラーコード仕込む感じですね。でもこっちの方が英語で指定できていいなぁ。ってかmysqlコマンドラインクライアントもrlwrap経由で起動させてやれば 日々の覚書: MySQL 5.6以降のmysqlコマンドラインクライアントでプロンプトに色を付けるcmakeオプション なんてのも必要なくなりそう。うむ。


$ rlwrap -z"pipeto" sqlplus
..
SQL> SELECT * FROM ..; | less -S -r

そして極め付け。SQLの結果をそのまま別のプロセスにパイプで渡せるpipetoフィルター。mysqlにはpagerコマンドがあるので気楽にlessに食わせられるけれど、sqlplusにはお手軽なのがないらしい。

`-z"pipeto"`オプションを付けると、出力をパイプに向けられる。
( *出力を* 向けるので、パイプの手前までで出力が開始されてないとダメ。つまりSQLなら *セミコロンまで打ち込んでからパイプを付ける* 

ところでこれ、MySQLは文字列結合に"||"演算子を使わないから良いとして、Oracleはよく使いそう(偏見)なので、上手くやってくれ…

SQL> SELECT 'a' || 'b'; | wc

sh: -c: line 0: 期待してない token `|' のあたりにシンタックスエラー
sh: -c: line 0: `| 'b'; | wc'

  2

る訳がなかった。そりゃ別にsqlplus用のユーティリティーってわけじゃあるまいし。
幸いにしてフィルターの類はPerlで書かれているらしいので、ちょっと探してみる。


$ rpm -ql rlwrap
/usr/bin/rlwrap
/usr/share/doc/rlwrap-0.41
/usr/share/doc/rlwrap-0.41/AUTHORS
/usr/share/doc/rlwrap-0.41/COPYING
/usr/share/doc/rlwrap-0.41/NEWS
/usr/share/doc/rlwrap-0.41/README
/usr/share/man/man1/rlwrap.1.gz
/usr/share/man/man3/RlwrapFilter.3pm.gz
/usr/share/rlwrap
/usr/share/rlwrap/completions
/usr/share/rlwrap/completions/coqtop
/usr/share/rlwrap/completions/testclient
/usr/share/rlwrap/filters
/usr/share/rlwrap/filters/README
/usr/share/rlwrap/filters/RlwrapFilter.3pm
/usr/share/rlwrap/filters/RlwrapFilter.pm
/usr/share/rlwrap/filters/censor_passwords
/usr/share/rlwrap/filters/count_in_prompt
/usr/share/rlwrap/filters/ftp_filter
/usr/share/rlwrap/filters/history_format
/usr/share/rlwrap/filters/listing
/usr/share/rlwrap/filters/logger
/usr/share/rlwrap/filters/null
/usr/share/rlwrap/filters/paint_prompt
/usr/share/rlwrap/filters/pipeline
/usr/share/rlwrap/filters/pipeto
/usr/share/rlwrap/filters/scrub_prompt
/usr/share/rlwrap/filters/simple_macro
/usr/share/rlwrap/filters/template
/usr/share/rlwrap/filters/unbackspace

$ vim /usr/share/rlwrap/filters/pipeto
..
 50 sub input {
 51   my $input;
 52   $raw_input = $_;
 53   ($input, undef, $pipeline) =  /([^|]*)(\|(.*))?/;
 54   return $input;
 55 }
..

ここで切り分けているぽい。最初のパイプの手前までが元のコマンド、パイプの後ろがフィルターになってる。
そこでこんなパッチにしてみました。


*** /usr/share/rlwrap/filters/pipeto.orig       2010-01-03 21:42:16.000000000 +0900
--- /usr/share/rlwrap/filters/pipeto    2015-12-08 10:58:54.817411488 +0900
***************
*** 53 ****
!   ($input, undef, $pipeline) =  /([^|]*)(\|(.*))?/;
--- 53,54 ----
!   ($input, $pipeline) =  /(.+)?\s+\|\s+(.*)?/;
!   $input= $_ unless $input;

" | "(空白、パイプ、空白。空白は1つ以上の任意の個数でOK)をパイプと認識させるように変更。


SQL> SELECT 'a' || 'b' FROM dual /* パイプを通る */; | less
'A
--
ab

SQL> SELECT 'a' || 'b' FROM dual /* パイプを通らない */; |less
  2 

パイプを通らない場合、"|less"までをsqlplusが解釈しようとするのでちゃんと出力されませんね(これは-z"pipeto"を取ってもそんな動きだった)


ざっとマニュアルを読んで面白そうだったものの紹介でした!
(個人的にはパスワードプロンプトで↑↓使えたのが面白かった)

2015/12/09

pt-online-schema-changeと5.6 InnoDBのオンラインALTER TABLE使い分け

この記事は MySQL Casual Advent Calendar 2015 の9日目です。

MySQL 5.6から InnoDBのオンラインDDL が導入されて久しいですが、一方で pt-online-schema-change (以下pt-osc)もまだまだ元気です。MySQL 5.5とそれより前ではpt-osc一択になりますが、MySQL 5.6とそれ以上の場合はInnoDBさんに任せるかpt-oscを使うかを選択することができます。

MySQL 5.6でもpt-osc一択にしても構わないといえば構わないんですが、いくつかのケースではInnoDBさんに任せた方が速くなったり安定したりするので、そのあたり解説していきます。


TL;DR

ウチの使い分け。
  • 原則 pt-osc
  • スレーブの台数が多すぎない かつ
    • データ容量が馬鹿でかくてストレージ食いつぶしそう または
    • INSERT大杉で2度のメタデータロックが馬鹿にならない または
    • デッドロック大杉 なら
    • InnoDB Online DDLでRSU(Rolling Schema Upgrade)

When pt-osc?

  • pt-oscの仕組みをざっくり
    • 元テーブルから新しいテーブル(空っぽ)を作って
    • 空っぽのテーブルにALTER TABLEをかけて
    • 元テーブルへの更新をトリガーでフックしながら古いデータをコピーする
    • コピーが終わったらRENAME TABLEで新旧テーブルを入れ替える
  • 古いデータをコピーする処理を細切れにしてくれるので、レプリケーションスレーブを詰まらせることが少ない
    • あと、スレーブの遅延監視のための --recursion-methodが結構柔軟に設定できる ので、「MySQL 5.6だからオンラインALTER TABLEいけるじゃん?」「ざんねん! SQLスレッドは同時に1つのクエリーしかさばけない!」ということはない
  • 古いデータをコピーする処理が細切れなので、
    • デッドロックがボコボコ出たりする
    • binlogを抱いて溺死
  • まるまるテーブルをコピーするので
    • 容量に十分な余裕が必要
    • バッファプールもそれなりに圧迫する
    • binlogを抱いて(ry
  • トリガーを張る時、RENAME TABLEのタイミングでメタデータロックを取る
    • 同時アクセス(メタデータロックなのでSELECTも含む)が多い環境だと割と簡単に詰まる
    • 先行トランザクションが終了するまでメタデータロック待ちするので、その更に後から来たクエリーはメタデータロックが取れるまで待たされる
      • trx1> SELECT .. -- コイツが終わらないとき
      • trx2> RENAME TABLE .. -- コイツが"Waiting for table metadata lock"になり
      • trx3> SELECT .. -- コイツも"Waiting for table metadata lock"になる
    • メタデータロックとHandlerSocket Pluginの相性が最悪
    • pt-osc開始時のメタデータロックはまだ「様子を見ながら開始する」「引っかかったら即中断」することができるけど、終了直前のは祈るしかない(;-人-)
      • 中断した場合、一時テーブルとトリガーのお片付けは自分でやる必要がある
        • 先にDROP TABLEするとトリガーが転け続けるので必ずDROP TRIGGERから先にやること
  • 入れ替えたあとに要らなくなった方のDROP TABLEが走るので、 lazy drop table を食らったことがある
    • lazy drop tableは直ったことになってるんだっけ?
  • テーブルがまるまる再作成されるので、ついでにOPTIMIZEがかかったようなもの

When InnoDB Online DDL?

  • InnoDBオンラインDDLの仕組みをざっくり
    • ALTER TABLEで追加するインデックス, カラムなどを先に.ibdの外側に作っておくイメージ
      • ソートやもろもろ終わってから、.ibdファイルにマージする感じ
    • 追加するインデックスやカラムに対するALTER TABLE中の更新はtmpdirに書き出しておいて後からマージ
  • マスターで1時間かかったALTER TABLEがスレーブでも1時間かかるのはブロッキングなALTER TABLEと同じ
    • スレーブの更新クエリーはSQL_threadからしか入ってこないので、SQL_threadがALTER TABLEを掴みっぱなしになって結局レプリケーションが遅れる
    • マスターとスレーブで *レプリケーションを通さずに* それぞれオンラインALTER TABLEをかけることで回避する
      • この手間が惜しい場合はこっちは使えない
      • Rolling Schema Upgrade(RSU)って言うらしい
  • テーブル全体のコピーが発生しないのでI/O量がpt-oscに比べて少ない
    • とはいえそれなり(もとのFast Index Creation相当)のI/Oは発生する
    • binlogにやさしい
  • カラムのデータを読み取る処理はロックを取らないのでデッドロックは起こらない
  • メタデータロックに関しては開始時と終了時らしい
    • 開始時のメタデータロックに関する注意事項はpt-oscと同じ。長時間トランザクションが来てないタイミングを見計らって開始
    • 終了時に.ibdファイルにもろもろマージするタイミングでもメタデータロックを取るらしいけれど、pt-oscと違って目に見えた範囲で問題になったことはない
      • pt-oscはステートメントでロックを取るステートメントを実行するのに対し、内部のAPIでロックを取るからなのかしらん?
  • オペレーションを選ぶ。たとえばALTER TABLE .. MODIFYでデータ型が変わるものはブロッキングなALTER TABLEになる
  • ポイントインタイムリカバリー(PITR)ととても相性が悪い
    • RSUでない場合、単純にmysqlbinlogの結果を食わせる場合に結局そのスレッドを占有してしまう。
    • *RSUでbinlogに書き出させない場合、このALTER TABLEだけPITRできなくなってしまう。*

という訳で、InnoDBのオンラインALTER TABLEでRSUするやり方。


master> SET SESSION sql_log_bin= 0;
master> ALTER TABLE ..;

slave1> SET SESSION sql_log_bin= 0; -- binlog吐いてるなら。中間マスターでない限り必須ではない。好み。
slave1> ALTER TABLE ..;

slave2> SET SESSION sql_log_bin= 0; -- 同上
slave2> ALTER TABLE ..;

「やり方」も何もとても簡単。そのALTER TABLEだけbinlogに出力させないようにして、 *マスターとスレーブ全てのサーバーで* ALTER TABLEを実行する。

この方法だとbinlogに一切合財ALTER TABLEの情報が載らなくなるので、このALTER TABLEをまたぐ期間のPITRができなくなる。RSU後にフルバックアップ推奨。
(インデックス追加くらいなら後から来たクエリーも特に問題ないけど、カラム追加だとアプリのリリースかけた後のクエリーが全部詰まって死ぬ)
なので運用上は *原則pt-osc* としています。何回かやってもpt-oscに失敗する(あるいは容量不足でpt-oscができないことが明白)な場合だけRSU。


用法、用量を守って使い分けると便利です。

2015/12/08

MySQL 5.5とそれ以前のマスターにMySQL 5.7のスレーブはぶら下げられない(5.7.13で修正)

出来ないのは仕様だそうです。ステータスは"Not a Bug"

MySQL Bugs: #79272: MySQl 5.5 master fails to replicate to MySQL 5.7.9


【2016/07/08 12:04】
MySQL Bugs: #80962: Replication does not work when @@GLOBAL.SERVER_UUID is missing on the master で改めてFIXされました。 5.7.13から5.5系のマスターにつなげるようになっています。


これはレプリケーションの開始時にI/Oスレッドがマスターのserver_uuidサーバー変数を参照しに行くんだけど、その値が取れなくてエラーになる。

…あれ、これどこかで聞いたことある気がする。と思ったら5.6の時に軽く調べてた。
日々の覚書: MySQL 5.6より前のマスターにMySQL 5.6のスレーブをぶら下げるとワーニングが出る(Err: 1193)

MySQL 5.6からMySQL 5.5は同じくserver_uuid変数を参照するものの、I/Oスレッドはアボートせずワーニング止まりだった。それがMySQL 5.7では止まる。

試しにMySQL::Sandboxで5.5.46, 5.6.27, 5.7.9を浮かしてみると

mysql [localhost] {msandbox} ((none)) > CHANGE MASTER TO master_host= '127.0.0.1', master_port= 5627, master_user= 'rsandbox', master_password= 'rsandbox', master_log_file= 'bin.000001', master_log_pos= 1 FOR CHANNEL 'mysql56';
Query OK, 0 rows affected, 2 warnings (0.01 sec)

mysql [localhost] {msandbox} ((none)) > CHANGE MASTER TO master_host= '127.0.0.1', master_port= 5546, master_user= 'rsandbox', master_password= 'rsandbox', master_log_file= 'bin.000001', master_log_pos= 1 FOR CHANNEL 'mysql55';
Query OK, 0 rows affected, 2 warnings (0.01 sec)

mysql [localhost] {msandbox} ((none)) > START SLAVE;
Query OK, 0 rows affected (0.01 sec)

mysql [localhost] {msandbox} (performance_schema) > SELECT * FROM performance_schema.replication_connection_status;
+--------------+------------+--------------------------------------+-----------+---------------+---------------------------+--------------------------+--------------------------+-------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+
| CHANNEL_NAME | GROUP_NAME | SOURCE_UUID                          | THREAD_ID | SERVICE_STATE | COUNT_RECEIVED_HEARTBEATS | LAST_HEARTBEAT_TIMESTAMP | RECEIVED_TRANSACTION_SET | LAST_ERROR_NUMBER | LAST_ERROR_MESSAGE                                                                                                                               | LAST_ERROR_TIMESTAMP |
+--------------+------------+--------------------------------------+-----------+---------------+---------------------------+--------------------------+--------------------------+-------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+
| mysql55      |            |                                      |      NULL | OFF           |                         0 | 0000-00-00 00:00:00      |                          |              1593 | Fatal error: The slave I/O thread stops because a fatal error is encountered when it tries to get the value of SERVER_UUID variable from master. | 2015-12-08 15:54:40  |
| mysql56      |            | 9b2a8e7a-9d57-11e5-8f87-02018582356a |        42 | ON            |                         2 | 2015-12-08 15:55:40      |                          |                 0 |                                                                                                                                                  | 0000-00-00 00:00:00  |
+--------------+------------+--------------------------------------+-----------+---------------+---------------------------+--------------------------+--------------------------+-------------------+--------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+
2 rows in set (0.00 sec)


5.7と5.5は確かにエラった。

5.6から5.5だと

mysql [localhost] {msandbox} ((none)) > CHANGE MASTER TO master_host= '127.0.0.1', master_port= 5546, master_user= 'rsandbox', master_password= 'rsandbox', master_log_file= 'bin.000001', master_log_pos= 1;
Query OK, 0 rows affected, 2 warnings (0.02 sec)

mysql [localhost] {msandbox} ((none)) > START SLAVE;
Query OK, 0 rows affected (0.02 sec)

mysql [localhost] {msandbox} ((none)) > SHOW SLAVE STATUS\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 127.0.0.1
                  Master_User: rsandbox
                  Master_Port: 5546
                Connect_Retry: 60
              Master_Log_File: bin.000001
          Read_Master_Log_Pos: 107
               Relay_Log_File: mysql_sandbox5627-relay-bin.000002
                Relay_Log_Pos: 264
        Relay_Master_Log_File: bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
..

エラーにはならない。コードを眺めてみると、5.6では "SHOW VARIABLES LIKE 'SERVER_UUID'"して、ちゃんとserver_uuidが返ってくる(server_uuidをサポートしている5.6以上)かエラーになる(予期しない想定外の事態なんだと思う)か空の結果セットが返ってくる(5.5とそれより前の、server_uuidをサポートしていないバージョン)かの3択で切り分けていた。

https://github.com/mysql/mysql-server/blob/12ec343846f2c1ed9f0454ccca8997afc4a0bb5f/sql/rpl_slave.cc#L1877-L1880


それが5.7だと"SELECT @@GLOBAL.SERVER_UUID"で取ろうとするので、server_uuidをサポートしていないバージョンだと"Unknown system variable"で一発エラーになってFatalでI/Oスレッドが止まる。

mysql [localhost] {msandbox} ((none)) > SELECT @@GLOBAL.SERVER_UUID;
ERROR 1193 (HY000): Unknown system variable 'SERVER_UUID'

https://github.com/mysql/mysql-server/blob/ef4fcf760a2d3b098a475323e289a6cab57020ab/sql/rpl_slave.cc#L2356-L2358


という訳で、MySQL 5.7のmysql_upgradeでイケるにしてもレプリケーションに属するサーバーを全部いっぺんに上げない限りは5.5から5.7へはジャンプできないのでした(´・ω・`)


【2016/07/08 12:04】

5.7.13で5.5とそれ以前のマスターのスレーブになれるようになりました。

MySQL Bugs: #80962: Replication does not work when @@GLOBAL.SERVER_UUID is missing on the master

> Replication: Slaves running MySQL 5.7 could not connect to a MySQL 5.5 master due to an error retrieving the server_uuid, which is not part of MySQL 5.5. This was caused by changes in the method of retrieving the server_uuid. (Bug #22748612)

http://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-13.html

とはいえそもそも2世代またいだレプリケーションはサポート対象外ではある。

しかし、 MySQL Bugs: #79272: MySQl 5.5 master fails to replicate to MySQL 5.7.9 の "Not a Bug" は何だったのか。

2015/12/04

MySQL Routerつらくない(CentOS 6.6でもビルドがしたい編)

この記事は MySQL Fabric&Routerつらくない Advent Calendar 2015 の4日目です。

昨日 の時点で、CentOS 7.1のコンテナーなら問題なくyumでインストールして動作確認ができることはわかりました。しかしまあ、勤め先の本番環境はほとんどがCentOS 6.xなので、どうせならそっちで動く形式にしておきたい(特に、MySQL RouterのスタイルからしてAPサーバーに載せるのが具合がいい気がするので)

SPECファイルの.in を見ている限り、systemdがない環境でもちゃんと選んでビルドしてくれそうではあったので頑張ってみることにした。

TL;DR


という訳で色々試してるんですが、rpmのビルドには失敗します。しょんぼり。誰か判ったら教えてください。バイナリー.tar.gzっぽいのはできたのでそろそろ諦めます。


CentOS 7.1ではビルドに成功する


$ rpm -i mysql-router-2.0.2-1.el7.src.rpm
$ cd rpmbuild/SPECS/
$ rpmbuild -bb mysql-router.spec
..
Checking for unpackaged file(s): /usr/lib/rpm/check-files /root/rpmbuild/BUILDROOT/mysql-router-2.0.2-1.el7.centos.x86_64
Wrote: /root/rpmbuild/RPMS/x86_64/mysql-router-2.0.2-1.el7.centos.x86_64.rpm
Wrote: /root/rpmbuild/RPMS/x86_64/mysql-router-debuginfo-2.0.2-1.el7.centos.x86_64.rpm
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.cku59B
+ umask 022
+ cd /root/rpmbuild/BUILD
+ cd mysql-router-2.0.2
+ rm -rf /root/rpmbuild/BUILDROOT/mysql-router-2.0.2-1.el7.centos.x86_64
+ exit 0

まあ、当然ですが上手くいきました。


CentOS 6.6だとダメ


$ rpm -i mysql-router-2.0.2-1.el7.src.rpm
$ cd rpmbuild/SPECS/
$ scl enable devtoolset-2 "rpmbuild -ba mysql-router.spec"
..
Processing files: mysql-router-2.0.2-1.el6.x86_64
error: File not found: /root/rpmbuild/BUILDROOT/mysql-router-2.0.2-1.el6.x86_64/etc/init.d/mysqlrouter
Executing(%doc): /bin/sh -e /var/tmp/rpm-tmp.q5xdpa
+ umask 022
+ cd /root/rpmbuild/BUILD
+ cd mysql-router-2.0.2
+ DOCDIR=/root/rpmbuild/BUILDROOT/mysql-router-2.0.2-1.el6.x86_64/usr/share/doc/mysql-router-2.0.2
+ export DOCDIR
+ rm -rf /root/rpmbuild/BUILDROOT/mysql-router-2.0.2-1.el6.x86_64/usr/share/doc/mysql-router-2.0.2
+ /bin/mkdir -p /root/rpmbuild/BUILDROOT/mysql-router-2.0.2-1.el6.x86_64/usr/share/doc/mysql-router-2.0.2
+ cp -pr License.txt README.txt /root/rpmbuild/BUILDROOT/mysql-router-2.0.2-1.el6.x86_64/usr/share/doc/mysql-router-2.0.2
+ exit 0


RPM build errors:
    File not found: /root/rpmbuild/BUILDROOT/mysql-router-2.0.2-1.el6.x86_64/etc/init.d/mysqlrouter

明らかにsystemdを使わない判定の方に転がって、sysvinitスタイルのものが見付からないとかなんとか言ってる。
ソースを落としてみるとpackagingディレクトリーにbuild_rpm.shとかいうのもあってそっちも試してみたけれど、なんかこっちは最終的にmysql-router-commercial-*.tar.gzを要求されてビルドが転ける。


仕方がないのでバイナリー.tar.gz版ぽいものをビルド


$ scl enable devtoolset-2 "cmake -DINSTALL_LAYOUT=STANDALONE -DCMAKE_INSTALL_PREFIX=/usr/local/mysql-router"
$ make
$ VERBOSE=1 sudo make install
..
Install the project...
/usr/bin/cmake -P cmake_install.cmake
-- Install configuration: ""
-- Up-to-date: /usr/local/mysql-router/include/mysql/mysqlrouter/config_parser.h
-- Up-to-date: /usr/local/mysql-router/include/mysql/mysqlrouter/plugin.h
-- Up-to-date: /usr/local/mysql-router/include/mysql/mysqlrouter/filesystem.h
-- Up-to-date: /usr/local/mysql-router/include/mysql/mysqlrouter/loader.h
-- Up-to-date: /usr/local/mysql-router/lib/libmysqlharness.a
-- Installing: /usr/local/mysql-router/lib/libmysqlharness.so.0
-- Up-to-date: /usr/local/mysql-router/lib/libmysqlharness.so
-- Installing: /usr/local/mysql-router/lib/mysqlrouter/logger.so
-- Up-to-date: /usr/local/mysql-router/include/mysql/mysqlrouter/logger.h
-- Installing: /usr/local/mysql-router/lib/mysqlrouter/keepalive.so
-- Installing: /usr/local/mysql-router/lib/mysqlrouter/fabric_cache.so
-- Up-to-date: /usr/local/mysql-router/include/mysql/mysqlrouter/fabric_cache.h
-- Installing: /usr/local/mysql-router/lib/mysqlrouter/routing.so
-- Up-to-date: /usr/local/mysql-router/include/mysql/mysqlrouter/routing.h
-- Installing: /usr/local/mysql-router/docs/README.txt
-- Installing: /usr/local/mysql-router/docs/License.txt
-- Installing: /usr/local/mysql-router/docs/sample_mysqlrouter.ini
-- Up-to-date: /usr/local/mysql-router/include/mysql/mysqlrouter/datatypes.h
-- Up-to-date: /usr/local/mysql-router/include/mysql/mysqlrouter/utils.h
-- Up-to-date: /usr/local/mysql-router/include/mysql/mysqlrouter/plugin_config.h
-- Installing: /usr/local/mysql-router/bin/mysqlrouter
-- Installing: /usr/local/mysql-router/lib/libmysqlrouter.so.1
-- Up-to-date: /usr/local/mysql-router/lib/libmysqlrouter.so

これで/usr/lcoal/mysql-routerの下に全部押し込められた気がする。
他のコンテナーにコピーして展開してみる。


$ tar -C /usr/local -cf mysql-router-2.0.2.glibc12.tar.gz mysql-router/
$ docker cp build:/root/mysql-router-2.0.2.glibc12.tar.gz ./
$ docker run -v /home/yoku0825/mysql-router-2.0.2.glibc12.tar.gz:/root/mysql-router-2.0.2.glibc12.tar.gz -it centos:centos6.6 bash
# /usr/local/mysql-router/bin/mysqlrouter
bin/mysqlrouter: error while loading shared libraries: libmysqlrouter.so.1: cannot open shared object file: No such file or directory
# LD_LIBRARY_PATH=/usr/local/mysql-router/lib /usr/local/mysql-router/bin/mysqlrouter --help
Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Start MySQL Router.

Configuration read from the following files in the given order (enclosed
in parentheses means not available for reading):
  (./mysqlrouter.ini)
  (/root/.mysqlrouter.ini)

Usage: mysqlrouter [-v|--version] [-h|--help]
                   [-c|--config=]
                   [-a|--extra-config=]

Options:
  -v, --version
        Display version information and exit.
  -h, --help
        Display this help and exit.
  -c , --config 
        Only read configuration from given file.
  -a , --extra-config 
        Read this file after configuration files are read from either
        default locations or from files specified by the --config
        option.

ライブラリーパスさえ通せば動きそうだった。つらくない!

2015/12/03

MySQL Routerつらくない(yumでインストールして動かしてみた編)

この記事は MySQL Fabric&Routerつらくない Advent Calendar 2015 の3日目です。

昨日 の時点で、CentOS 6.6でMySQL Routerを試すには自前ビルドしないといけないことが判明しました。つらい だが俺にはDockerがある。CentOS 6.6の上でCentOS 7.1のコンテナー動かせばいいじゃん。systemdとか動かなそうだけど取り敢えず試すだけだからこういう時に便利ですよね! つらくない!


$ sudo docker run -it centos:centos7 bash
# yum install -y http://dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpm
# yum install -y mysql-router
..
Installed:
  mysql-router.x86_64 0:2.0.2-1.el7

Complete!

お手軽! …って、mysql-routerの依存関係で引きずられてmysql-community-libsとか入るかと思ったけど入ってない。いいのかな。。


# rpm -ql mysql-router
/etc/mysqlrouter
/etc/mysqlrouter/mysqlrouter.ini
/usr/lib/systemd/system/mysqlrouter.service
/usr/lib/tmpfiles.d/mysqlrouter.conf
/usr/lib64/libmysqlharness.so
/usr/lib64/libmysqlharness.so.0
/usr/lib64/libmysqlrouter.so
/usr/lib64/libmysqlrouter.so.1
/usr/lib64/mysqlrouter
/usr/lib64/mysqlrouter/fabric_cache.so
/usr/lib64/mysqlrouter/keepalive.so
/usr/lib64/mysqlrouter/logger.so
/usr/lib64/mysqlrouter/routing.so
/usr/sbin/mysqlrouter
/usr/share/doc/mysql-router-2.0.2
/usr/share/doc/mysql-router-2.0.2/License.txt
/usr/share/doc/mysql-router-2.0.2/README.txt
/var/log/mysqlrouter
/var/run/mysqlrouter

# cat /usr/lib/systemd/system/mysqlrouter.service
[Unit]
Description=MySQL Router
After=syslog.target
After=network.target

[Service]
Type=simple
User=mysql
Group=mysql

PIDFile=/var/run/mysqlrouter/mysqlrouter.pid

ExecStart=/usr/sbin/mysqlrouter

PrivateTmp=true

[Install]
WantedBy=multi-user.target

rpmファイルの構成としては至極フツーな感じ。systemdもただ/usr/sbin/mysqlrouterしてるだけみたいだから取り敢えずやってみようかしら。


# mysqlrouter &
Logging to /var/log/mysqlrouter/mysqlrouter.log

# less /var/log/mysqlrouter/mysqlrouter.log
2015-12-02 05:13:52 INFO    [7f9173b46700] keepalive started with interval 60
2015-12-02 05:13:52 INFO    [7f9173b46700] keepalive
2015-12-02 05:14:52 INFO    [7f9173b46700] keepalive
2015-12-02 05:15:52 INFO    [7f9173b46700] keepalive

# ss -ltpn
State      Recv-Q Send-Q                               Local Address:Port                                 Peer Address:Port

あれ、どこのポートもLISTENしてない。
ドキュメント をナナメ読みしてみた感じ、どうも[routing:xxx]セクションに設定をしたぶんだけポートをLISTENするシロモノであるっぽい。


# vim /etc/mysqlrouter/mysqlrouter.ini
..
[routing:sakila_blue]
bind_port= 7001
mode= read-write
destinations= 127.0.0.1:3306

# mysqlrouter &
Logging to /var/log/mysqlrouter/mysqlrouter.log

# ss -ltpn
State      Recv-Q Send-Q                               Local Address:Port                                 Peer Address:Port
LISTEN     0      0                                        127.0.0.1:7001                                            *:*      users:(("mysqlrouter",40,4))

# less /var/log/mysqlrouter/mysqlrouter.log
2015-12-02 15:23:48 INFO    [7fae2cb46700] routing:sakila_blue started: listening on 127.0.0.1:7001; read-write
2015-12-02 15:23:48 INFO    [7fae2d547700] keepalive started with interval 60
2015-12-02 15:23:48 INFO    [7fae2d547700] keepalive

# vim /etc/mysqlrouter/mysqlrouter.ini
..
[routing:master]
bind_port= 7001
mode= read-write
destinations= 127.0.0.1:13454

[routing:slave]
bind_port= 7002
mode= read-only
destinations= 127.0.0.1:13455,127.0.0.1:13456

# pkill mysqlrouter
# mysqlrouter &
Logging to /var/log/mysqlrouter/mysqlrouter.log

# ss -ltpn
State      Recv-Q Send-Q                               Local Address:Port                                 Peer Address:Port
LISTEN     0      0                                        127.0.0.1:7001                                            *:*      users:(("mysqlrouter",49,6))
LISTEN     0      0                                        127.0.0.1:7002                                            *:*      users:(("mysqlrouter",49,4))

# less /var/log/mysqlrouter/mysqlrouter.log
2015-12-02 15:25:28 INFO    [7f0b81e2b700] keepalive started with interval 60
2015-12-02 15:25:28 INFO    [7f0b81e2b700] keepalive
2015-12-02 15:25:28 INFO    [7f0b8142a700] routing:slave started: listening on 127.0.0.1:7002; read-only
2015-12-02 15:25:28 INFO    [7f0b80a29700] routing:master started: listening on 127.0.0.1:7001; read-write

ふむふむ。
MySQL Proxyは1対多のプロキシしか構成できなかったけど、MySQL Routerだと多対多のプロキシが構成できるのね。


このコンフィグは組み込みでサポートしてる「Connection Routing」に当たるもので、MySQL Fabricは取り敢えず今日は関係なさげ。。見た目、Connector/Jのfailover記法みたいな感じで転けたら次のホストに行くって動作をさせられる様子。

MySQL :: MySQL Router :: 1.1.1 Connection Routing


* read-writeのポート

$ mysql -umsandbox -pmsandbox --protocol=tcp -P 7001 -e "SELECT @@port"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------+
| @@port |
+--------+
|  13454 |
+--------+

$ mysql -umsandbox -pmsandbox --protocol=tcp -P 7001 -e "SELECT @@port"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------+
| @@port |
+--------+
|  13454 |
+--------+

$ mysql -umsandbox -pmsandbox --protocol=tcp -P 7001 -e "SELECT @@port"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------+
| @@port |
+--------+
|  13454 |
+--------+

$ mysql -umsandbox -pmsandbox --protocol=tcp -P 7001 -e "SELECT @@port"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------+
| @@port |
+--------+
|  13454 |
+--------+


* read-onlyのポート

$ mysql -umsandbox -pmsandbox --protocol=tcp -P 7002 -e "SELECT @@port"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------+
| @@port |
+--------+
|  13455 |
+--------+

$ mysql -umsandbox -pmsandbox --protocol=tcp -P 7002 -e "SELECT @@port"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------+
| @@port |
+--------+
|  13456 |
+--------+

$ mysql -umsandbox -pmsandbox --protocol=tcp -P 7002 -e "SELECT @@port"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------+
| @@port |
+--------+
|  13455 |
+--------+

$ mysql -umsandbox -pmsandbox --protocol=tcp -P 7002 -e "SELECT @@port"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------+
| @@port |
+--------+
|  13456 |
+--------+

$ mysql -umsandbox -pmsandbox --protocol=tcp -P 7002 -e "SELECT @@port"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------+
| @@port |
+--------+
|  13455 |
+--------+

「read-writeは先頭のホストが失敗したら次のホストへ」
「read-onlyはラウンドロビン」
って書いてあった。ちゃんとドキュメントに書いてあるなんてつらくない!

MySQL :: MySQL Router :: 3.2.2 Connection Routing (Standalone)


マスターを落とすとこの通りフローティングしてくれて

$ ./master/stop

$ mysql -umsandbox -pmsandbox --protocol=tcp -P 7001 -e "SELECT @@port"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------+
| @@port |
+--------+
|  13455 |
+--------+

$ ./master/start

$ mysql -umsandbox -pmsandbox --protocol=tcp -P 7001 -e "SELECT @@port"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------+
| @@port |
+--------+
|  13455 |
+--------+

あれ、上げても勝手に戻るわけではないのか。

取り敢えず動いたので楽しい。つらくない!

2015/12/02

MySQL Routerつらくない(自前ビルド時のcmakeエラー編)

この記事は MySQL Fabric&Routerつらくない Advent Calendar 2015 の2日目です。

昨日 はしゃらっと流したcmakeした時のエラーについていくつか。


Could not find MySQL librariesと言われるけど、mysql-community-libsだけじゃなくてmysql-community-develも要求してくる


$ rpm -q mysql-community-libs
mysql-community-libs-5.7.9-1.el6.x86_64

$ cmake .
..
CMake Error at cmake/FindMySQL.cmake:105 (message):
  Could not find MySQL libraries; used
  /root/mysql-router-2.0.2/../mysql-server/lib;/usr/local/mysql/lib;/usr/local/mysql/lib;/usr/local/lib;/usr/lib/x86_64-linux-gnu;/usr/lib/i386-linux-gnu;/usr/lib64;/usr/lib
..

$ sudo yum install -y mysql-community-devel
$ cmake .
..
-- Found MySQL Libraries 5.7.9; using /usr/lib64/mysql/libmysqlclient.so
..

しかもエラーメッセージに含んでるディレクトリー群がlib系のディレクトリーだから 憎い つらくない。


Doxygenはなくても動く


$ cmake .
..
CMake Warning at mysql_harness/cmake/Docs.cmake:27 (message):
  Doxygen not found, no documentation target will be created
..

コールスタック出すから必須なのかと思ったけど、よく見たら"CMake Warning"だった。


デフォルトではインストールされるディレクトリがMySQLっぽくない


$ sudo make install
..
-- Install configuration: ""
-- Up-to-date: /usr/local/include/mysql/mysqlrouter/config_parser.h
-- Up-to-date: /usr/local/include/mysql/mysqlrouter/plugin.h
-- Up-to-date: /usr/local/include/mysql/mysqlrouter/filesystem.h
-- Up-to-date: /usr/local/include/mysql/mysqlrouter/loader.h
-- Up-to-date: /usr/local/lib/libmysqlharness.a
-- Up-to-date: /usr/local/lib/libmysqlharness.so.0
-- Up-to-date: /usr/local/lib/libmysqlharness.so
-- Up-to-date: /usr/local/lib/mysqlrouter/logger.so
-- Up-to-date: /usr/local/include/mysql/mysqlrouter/logger.h
-- Up-to-date: /usr/local/lib/mysqlrouter/keepalive.so
-- Up-to-date: /usr/local/lib/mysqlrouter/fabric_cache.so
-- Up-to-date: /usr/local/include/mysql/mysqlrouter/fabric_cache.h
-- Up-to-date: /usr/local/lib/mysqlrouter/routing.so
-- Up-to-date: /usr/local/include/mysql/mysqlrouter/routing.h
-- Up-to-date: /usr/local/share/doc/mysqlrouter/README.txt
-- Up-to-date: /usr/local/share/doc/mysqlrouter/License.txt
-- Up-to-date: /usr/local/share/doc/mysqlrouter/sample_mysqlrouter.ini
-- Up-to-date: /usr/local/share/doc/mysqlrouter/sample_mysqlrouter.init
-- Up-to-date: /usr/local/include/mysql/mysqlrouter/datatypes.h
-- Up-to-date: /usr/local/include/mysql/mysqlrouter/utils.h
-- Up-to-date: /usr/local/include/mysql/mysqlrouter/plugin_config.h
-- Installing: //var
-- Installing: //var/local
-- Installing: //var/local/mysqlrouter
-- Installing: //var/local/mysqlrouter/log
-- Installing: //var
-- Installing: //var/local
-- Installing: //var/local/mysqlrouter
-- Installing: //var/local/mysqlrouter/run
-- Installing: /usr/local/etc
-- Installing: /usr/local/etc/mysqlrouter
-- Up-to-date: /usr/local/bin/mysqlrouter
-- Up-to-date: /usr/local/lib/libmysqlrouter.so.1
-- Up-to-date: /usr/local/lib/libmysqlrouter.so

MySQL Community Serverは/usr/local/mysqlが全てのベースになってたけど、フツーのアプリケーションっぽく配置される。

* ライブラリー: /usr/local/lib
* ヘッダーファイル: /usr/local/include
* コンフィグ: /usr/local/etc
* ログとか: /var/local/mysqlrouter

うーん、/var/local/mysqlrouterは新しい。rpmだとどうなってるんだろ。


基本的にCentOS(なり、RHEL系は)7向け


MySQL :: Download MySQL Router

* まず、rpmは"Red Hat Enterprise Linux 7 / Oracle Linux 7"向けしかない。
* バイナリーの.tar.gzも"Linux - Generic (glibc 2.17)"なので、CentOS 6.xで動かすにはglibcを更新しないといけない。
* というか、RHEL 7系用のMySQL Toolsリポジトリー(Workbenchとか入ってるとこ)の中にはmysql-routerがある。6系用のリポジトリーにはない。

$ curl -s http://repo.mysql.com/yum/mysql-tools-community/el/7/x86_64 | grep router
[FILE] mysql-router-2.0.2-1.el7.x86_6..> 23-Oct-2015 06:36   1.0M
[FILE] mysql-router-debuginfo-2.0.2-1..> 23-Oct-2015 06:36   2.4M

$ curl -s http://repo.mysql.com/yum/mysql-tools-community/el/6/x86_64 | grep router


ビルドしたやつはちゃんと動くけど、.tar.gzを解凍したやつはもちろん動かない。

$ wget http://dev.mysql.com/get/Downloads/MySQL-Router/mysql-router-2.0.2-linux-glibc2.17-x86-64bit.tar.gz
$ tar xf mysql-router-2.0.2-linux-glibc2.17-x86-64bit.tar.gz
$ cd mysql-router-2.0.2-linux-glibc2.17-x86-64bit
$ bin/mysqlrouter
bin/mysqlrouter: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by /root/mysql-router-2.0.2-linux-glibc2.17-x86-64bit/bin/../lib/libmysqlrouter.so.1)
bin/mysqlrouter: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.14' not found (required by /root/mysql-router-2.0.2-linux-glibc2.17-x86-64bit/bin/../lib/libmysqlrouter.so.1)
bin/mysqlrouter: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.15' not found (required by /root/mysql-router-2.0.2-linux-glibc2.17-x86-64bit/bin/../lib/libmysqlrouter.so.1)
bin/mysqlrouter: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by /root/mysql-router-2.0.2-linux-glibc2.17-x86-64bit/bin/../lib/libmysqlharness.so.0)
bin/mysqlrouter: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.15' not found (required by /root/mysql-router-2.0.2-linux-glibc2.17-x86-64bit/bin/../lib/libmysqlharness.so.0)

うう、CentOS 7なマシンが欲しいよう。

2015/12/01

MySQL Routerはつらくない。何故ならまだ触っていないからだ。

この記事は MySQL Casual Advent Calendar 2015 の1日目です。
MySQL Fabric&Routerつらくない Advent Calendar 2015 の1日目でもあります。

さて…昨年あんなにも MySQL Fabric関連のブログ を書いたのに、少なくとも2015/12/1現在、MySQL Fabricがちっとも流行ってないのは何故だろうとか考えてみました。

  1. Fabric対応コネクターが必要
  2. MySQL 5.6以上かつGTIDが必要
  3. バッキングストア(mysqlfabricデーモンが情報をストアするためのmysqld)を自前で冗長化しないといけない
  4. ググったら 「MySQL Fabric つらい」 とかサジェストされる
やっぱり1ですかね。いや、あるにはあるんですが、俺(と、俺の勤めている会社)の利用可能な範囲になくて、Connecto/J, Connector/Python がサポートされてるし…おや、 去年からずっと思ってた んですが相変わらずConnector/.NETがサポートしてるはずなのに書いてないぞ。。

肝心のConnector/C (DBD::mysqlはコイツ依存)はまだLabsにいるし、mysqlndのMySQL Fabricも2015/12/1現在でまだ"pre-alpha"ってことになってる(シャード機能には対応してるけどHA機能には対応してない…とか1年前には書いてあったけど、HA機能に対応した素振りもなければ対応してないとも書いてなくなった。。)


でも。2015年10月。
MySQL 5.7のGA と同時にMySQL Router のGAも発表されました(されたんですよ!)
このMySQL Router、ちょっと話を聞いてみた限りだと、

  • MySQL ProxyみたいにmysqlrouterがポートをLISTENして、実際の処理はバックエンドのMySQL Serverに投げる
  • MySQL Fabricのクライアントになれる(MySQL RouterがFabric対応Connectorの代わりにマスターやシャードの在り処の問い合わせをしてキャッシュしてくれる。アプリからはMySQL Routerにクエリーを投げればそれだけでMySQL Fabric無双)
  • プラグインを書けば他にもゴニョれる

MySQL Fabricのクライアントになって、MySQL Fabric非対応コネクターのクエリーもルーティングしてくれるということで、これで 自分でゴニョったDBD::mysql を使わなくてもMySQL Fabricが試せると。つらくない!


という訳でまずは試しなのでソースからビルドしてみることにしましょう。ダウンロードページは ここ


$ wget http://dev.mysql.com/get/Downloads/MySQL-Router/mysql-router-2.0.2.tar.gz
$ tar xf mysql-router-2.0.2.tar.gz
$ cd mysql-router-2.0.2
$ cmake -i
..
Variable Name: ROUTER_CONFIGDIR
Description: Location of configuration file(s) (config_folder)
Current Value: /usr/local/etc/mysqlrouter
New Value (Enter to keep current value):

Variable Name: ROUTER_LOGDIR
Description: Location of log files; empty is console (logging_folder)
Current Value: /var/local/mysqlrouter/log
New Value (Enter to keep current value):

Variable Name: ROUTER_PLUGINDIR
Description: Location MySQL Router plugins (plugin_folder)
Current Value: /usr/local/lib/mysqlrouter
New Value (Enter to keep current value):

Variable Name: ROUTER_RUNTIMEDIR
Description: Location runtime files such as PID file (runtime_folder)
Current Value: /var/local/mysqlrouter/run
New Value (Enter to keep current value):
..

取り敢えずcmakeしてみて思うことは、ちょっとあっちこっち散らばり過ぎじゃないですかねディレクトリ。
あとはいつもビルドに使うようなモジュールの他にDoxygenが必要だよって言われてみたりする。
Doxygenを入れたらCMakeCache.txtを消してからもう一度cmakeして、さあいざ


$ make
[  2%] Building CXX object harness/harness/CMakeFiles/harness-archive.dir/src/loader.cc.o
cc1plus: error: unrecognized command line option "-Wpedantic"
make[2]: *** [harness/harness/CMakeFiles/harness-archive.dir/src/loader.cc.o] Error 1
make[1]: *** [harness/harness/CMakeFiles/harness-archive.dir/all] Error 2
make: *** [all] Error 2

あっ! これ確かLabsの時にも引っかかったやつだ! つらくない!



メッセージはちょっと違ったっぽいけど。


$ gcc --version
gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-16)
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ sudo wget http://people.centos.org/tru/devtools-2/devtools-2.repo -O /etc/yum.repos.d/devtools-2.repo
$ sudo yum install devtoolset-2-gcc devtoolset-2-binutils devtoolset-2-gcc-c++
$ scl enable devtoolset-2 bash

CentOS 6.5にGCC 4.8.2をレポジトリで入れてみた - 以下省略! こちら様を参考にしてgcc-4.8.2を放り込んで、cmakeのオプションに渡してやると

$ rm CMakeCache.txt
$ cmake -DCMAKE_CXX_COMPILER:FILEPATH=/opt/rh/devtoolset-2/root/usr/bin/g++ CMAKE_C_COMPILER:FILEPATH=/opt/rh/devtoolset-2/root/usr/bin/gcc .
$ make
..
Linking CXX executable ../../../stage/bin/mysqlrouter
[100%] Built target mysqlrouter

通ったー! やっと通ったー!

なお、ここまで(前に引っかかったにも関わらず)1時間かかっている。Labsの時にあった `cmake .`でインソースビルドできないやつ も直ってるけど、rpmで入れればよかった。でもrpmという選択肢がある時点でつらくない!



( ´-`).oO(MySQL Fabric&Routerつらくない Advent Calendar 2015 は明日からコメント欄127文字運用になる予定ですが続きます。

2015/11/12

MySQL 5.7のmysql_upgradeは本当にDATETIME型を新しいフォーマットに直してくれるけれど

Upgrading Directly from MySQL 5.0 to 5.7 using an ‘In Place’ Upgrade | MySQL Server Blog を読んでふと思い立ったので。

MySQL 5.7のmysql_upgradeは古いDATETIME, TIME, TIMESTAMPを新しいDATETIME2, TIME2, TIMESTAMP2に変換してくれるからmysqldumpしてからリストアしなくてもいいんだぜ! っていうのが趣旨らしい。それは素敵だ。

↓これの12番目
日々の覚書: あなたのMySQL 5.6トレンド力をチェックする15の質問


ざっと見、確かにやってくれてる。worldデータベースを ダウンロード してきて食わせてみた。
(そういえば、昔はworldはMyISAMで、InnoDB版のworldが別にあったんだけど、今はたぶんInnoDBのだけなんだろうね。1つしかない)

$ cd /usr/mysql/5.5.46/
$ ./scripts/mysql_install_db --datadir=/home/yoku0825/test_55/
$ bin/mysqld_safe --no-defaults --datadir=/home/yoku0825/test_55 &
$ bin/mysql -uroot < ~/world_innodb.sql
$ bin/mysqladmin -uroot shutdown

$ cd /usr/mysql/5.7.9
$ bin/mysqld_safe --no-defaults --datadir=/home/yoku0825/test_55 &
$ bin/mysql_upgrade
Checking if update is needed.
Checking server version.
Running queries to upgrade MySQL server.
Checking system database.
mysql.columns_priv                                 OK
mysql.db                                           OK
mysql.engine_cost                                  OK
mysql.event                                        OK
mysql.func                                         OK
mysql.general_log                                  OK
mysql.gtid_executed                                OK
mysql.help_category                                OK
mysql.help_keyword                                 OK
mysql.help_relation                                OK
mysql.help_topic                                   OK
mysql.host                                         OK
mysql.innodb_index_stats                           OK
mysql.innodb_table_stats                           OK
mysql.ndb_binlog_index                             OK
mysql.plugin                                       OK
mysql.proc                                         OK
mysql.procs_priv                                   OK
mysql.proxies_priv
error    : Table upgrade required. Please do "REPAIR TABLE `proxies_priv`" or dump/reload to fix it!
mysql.server_cost                                  OK
mysql.servers                                      OK
mysql.slave_master_info                            OK
mysql.slave_relay_log_info                         OK
mysql.slave_worker_info                            OK
mysql.slow_log                                     OK
mysql.tables_priv                                  OK
mysql.time_zone                                    OK
mysql.time_zone_leap_second                        OK
mysql.time_zone_name                               OK
mysql.time_zone_transition                         OK
mysql.time_zone_transition_type                    OK
mysql.user                                         OK

Repairing tables
mysql.proxies_priv
Note     : TIME/TIMESTAMP/DATETIME columns of old format have been upgraded to the new format.
status   : OK
Upgrading the sys schema.
Checking databases.
sys.sys_config                                     OK
world.City                                         OK
world.Country                                      OK
world.CountryLanguage                              OK

Repairing tables
mysql.proxies_priv                                 OK
Upgrade process completed successfully.
Checking if update is needed.

mysqlcheck --check-upgrade の後に、引っかかったやつに対してREPAIR TABLEしてくれている様子。


ちなみにデータディレクトリを作り直して5.6だと、

$ cd /usr/mysql/5.6.27
$ bin/mysqld_safe --no-defaults --datadir=/home/yoku0825/test_55 &
$ bin/mysql_upgrade
Looking for 'mysql' as: bin/mysql
Looking for 'mysqlcheck' as: bin/mysqlcheck
Running 'mysqlcheck with default connection arguments
Running 'mysqlcheck with default connection arguments
mysql.columns_priv                                 OK
mysql.db                                           OK
mysql.event                                        OK
mysql.func                                         OK
mysql.general_log                                  OK
mysql.help_category                                OK
mysql.help_keyword                                 OK
mysql.help_relation                                OK
mysql.help_topic                                   OK
mysql.host                                         OK
mysql.ndb_binlog_index                             OK
mysql.plugin                                       OK
mysql.proc                                         OK
mysql.procs_priv                                   OK
mysql.proxies_priv                                 OK
mysql.servers                                      OK
mysql.slow_log                                     OK
mysql.tables_priv                                  OK
mysql.time_zone                                    OK
mysql.time_zone_leap_second                        OK
mysql.time_zone_name                               OK
mysql.time_zone_transition                         OK
mysql.time_zone_transition_type                    OK
mysql.user                                         OK
Running 'mysql_fix_privilege_tables'...
Running 'mysqlcheck with default connection arguments
Running 'mysqlcheck with default connection arguments
world.City                                         OK
world.Country                                      OK
world.CountryLanguage                              OK
OK

mysql_upgrade(というか 中身でやっぱりmysqlcheck --check-upgradeを呼んでる のでどちらかというとmysqlcheck)がそもそも警告すらしてくれない。

でも直すと直る。

mysql> ALTER TABLE mysql.proxies_priv FORCE;
Query OK, 2 rows affected, 1 warning (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 1

mysql> show warnings;
+-------+------+-------------------------------------------------------------------------------------+
| Level | Code | Message                                                                             |
+-------+------+-------------------------------------------------------------------------------------+
| Note  | 1880 | TIME/TIMESTAMP/DATETIME columns of old format have been upgraded to the new format. |
+-------+------+-------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

直るということは、その前までは旧TIMESTAMP型だったんだろうということは想像がつく。

で、取り敢えずはMySQL 5.6でできなかったことをできるようになってて5.7すごい! って言えばいいんだけど、実際に問題になるのはここではなくて、


日々の覚書: MySQL 5.6への移行でmysqldumpを使わなかったらどうなるか

( ´-`).oO(前半部分が盛大に間違っているという残念なエントリーだけどこれの2番目。


===ほぼ引用===
((マスターはmysql_upgradeでアップグレード && スレーブはmysqldumpからリストア) || (マスターはmysqldumpでアップグレード && スレーブはmysql_upgradeでアップグレード)) && (バイナリーログがROWモードで記録された) 場合に、マスターで記録された型情報とスレーブで再生されようとする型情報に不整合が発生するので、

mysql56> SHOW SLAVE STATUS\G
..
    Last_SQL_Errno: 1677
    Last_SQL_Error: Column 0 of table 'd1.t2' cannot be converted from type 'datetime' to type 'datetime'
..

こんな訳のわからない(datetime型からdatetime型への変換に失敗した)エラーでSQLスレッドが転ける。STATEMENTモードでは影響を受けないが、binlog_format= MIXEDでROWモードにフォールバックするようなクエリーが流れているとこれの直撃を食らう。
===ここまで===

なので、マスターが旧DATETIMEでスレーブが旧DATETIMEで、絶対にmysqldumpとかしないと言い切れるなら(非推奨なことを除けば、だけど、10年も前に非推奨になったold_passwordsがこの前まで生きてたんだから、そういう世界線なんだここは)RBRのエラーも起こらないはずなので構わないといえば構わない。

どちらかというと「マスターが5.5でスレーブが5.6以降」だと、CREATE TABLEで新しくテーブルを作った時にもマスターでは旧DATETIME型、スレーブでは新DATETIME型になってこれを踏むことになる。これはmysql_upgradeを使ったインプレースアップグレードだったか、mysqldumpを使ったダンプアップグレードだったかは 関係ない ので、5.5と5.6の間をまたぐレプリケーションはそう長く運用しない方がいい。

スレーブ作り直すの大変だ った と思うよ。

tomcatを再起動せずにlong_query_timeの変更を反映させられないかの思考実験

なんか作ろうと思っていて、その考えてる過程を整理のためにメモ。
取り敢えず目の前にある事案を想定してtomcat, long_query_timeだけど、コネクション永続化しててセッション変数が実効パラメーターなグローバル変数の変更は全部一緒。

どうでもいいですがマークダウンがただのテキストとして書かれてるのは仕様です(このあと社内のドキュメントにコピううんなんでもない)


## 前提

1. `SET GLOBAL long_query_time= n`は@@grobal.long_query_timeの値を書き換える

2. 各スレッドの実効パラメーターは @@session.long_query_time であり、 @@global.long_query_time は @@session.long_query_timeのデフォルト値である

3. よって、既に作成されてしまったスレッド= コネクションに対しては影響を持たない

4. スレッドを再作成するため、tomcatを再起動する必要がある

5. tomcat再起動する(or してもらう)のがめんどい


## 考えたこと

pt-kill を使って、`pt-kill S=/usr/mysql/5.7.9/data/mysql.sock,u=root --idle-time=1 --victims=oldest --wait-after-kill=30s --kill --print --match-command=Sleep` とかやれば古いやつから順番にゆっくり切って再接続をアプリケーションに任せられるかなと思ったけど

  * pt-killを開始した時間以降に接続してきたスレッドは除外対象にしないといけない

    * pt-killを開始した時間以前のスレッドが全滅したら自然に止まってほしい

  * pt-killではクエリーレベルまでしか見てくれないので、トランザクションが走ってるかどうかまでは検知してくれない

    * 迂闊にkillして大量ロールバックされても面倒


## というわけで

* `SELECT MAX(id) FROM information_schema.processlist`で、「開始時点より古いプロセスIDの最大値」を取る

  * プロセスIDは単調増加なので、これよりも大きいプロセスIDを持つスレッドはkillしなくていい

* `SELECT * FROM processlist LEFT JOIN innodb_trx ON processlist.id = innodb_trx.trx_mysql_thread_id WHERE id <= $maxid AND command = 'Sleep' AND time > 3 AND trx_id IS NULL ORDER BY processlist.id LIMIT 1` でスリープしててトランザクション中じゃないいちばん古いプロセスを引いてkill

  * time > 3にしてるのは、0だとMyISAMな複数ステートメント処理(似非トランザクション)のスキマに挟まるかもとか思った

    * いやどんな条件を付けようと、トランザクション非対応な複数ステートメント処理は救えないんだけど一応。。

  * SELECTからkillまでの100ミリ秒くらいの間に開始されたトランザクションはあきらめる(ロールバックが暴走することはないはず)

    * アプリケーションがエラーハンドルしてくれるのが大前提

* ちょっとスリープする

* `SELECT MIN(id) FROM information_schema.processlist WHERE id <= $maxid`がNULLになるまでこれを繰り返す

* なんてことをprogress出しながらやる


どうだろう。
監視のための永続コネクションも検知されたので、user, hostでフィルターはかけるとしてこれじゃダメかしら(そこまでしてtomcatを再起動しちゃダメな理由も見当たらないが)

2015/11/04

日本MySQLユーザ会会15周年記念パーティーがありましたよ

去る 10/30(金)、日本MySQLユーザ会の15周年記念パーティーがありました。



ハッシュタグだけまとめましたが、他にハッシュタグなしで面白いこと言ってた人がいらっしゃいましたら是非ともセルフサービスで更新をお願いします :)



smallpalaceさん のブログ MyNA会20151030にいってきた - smallpalace's blog とだいぶカブるんですけど、つらつらと感想など。



お手伝いとして当日「18時に来てね!」と言われているも、18時に行ったら既に椅子は並んでるわ机は揃ってるわ🍺は置いてあるわオードブルも置いてあるわ。
正直、受付のお手伝いをしていた @dupont_kedama さん *以外* は全く役に立ってなかったんじゃないでしょうかお手伝い陣。コロプラさんありがとうございました。

( ´-`).oO(コロプラさんは エンジーニャ募集中らしいよ ってじっちゃが言ってた(2015/10/30現在)


発表者ーズ

@tmtms さん




"ちなみに日本語EUCのcharset名はujisにしと いたで」 正直、スマンカッタ"


木下さん


このあたりから既に酔っぱらって記憶にないものの(何か木下さんに絡んでいた記憶だけはある。。)



"金曜日はMyNA会だからそれまでに終わらせとかないとなと思って"
"木下さんがMySQL Clusterとか言ってるとなんか新鮮"



木下さん的 ○racleへの就職方法。



InnoDB以外の木下さんの偉業(?)



なんかかっこいい。


かじやまさん




なお 奥野さん は "元Sun => MySQL AB => Sunに買収"の時にさすがにこっぴどく怒られたとかなんとか。



長かった。。どこかに全文掲載されたりしないだろうかw



JPACあたりのCommunity Team ManagerのLenkaさんからビデオレターが来てました。

6.xとか7.xとかMySQL Server 2010とか、ホテル「ドルフィン」とか、黒い人に後ろから刺されないかしら大丈夫かしらという感じのネタが続きました。笑ったー。


わたし

正直しゃべったことよく憶えてないんですが、

* MyNAのMLもYahoo知恵袋の代わりくらいには使えるんじゃないか(我ながらひどい。。)
* 最近の主なお仕事は、ビデオレターもくれたLenkaちゃんにMyNAの開催を知らせる簡単なお仕事
* Category: Japanese Documentationのばぐれぽは梅ッシュ(インド人? だったかな?)がVerifyしてくれて誰かさん(アジア人で日本語が上手い)が修正してくれる MySQL Bugs: #77306: Misprint in example storage engine
* MontyはX-Filesに出てきそうな顔

まいんだーさん






前にまいんだーさんから「詳しい人がカジュアルに難しい話をできる場」と聞いたことがあります。




そのあと堤井さんに連れられて10人弱で飲みに行ったんですけど、夜の赤坂は怖かった。
夜行バスを逃したとみたさんに「じゃあまた5年後に」と言われてお店を後にしました。またMyNA会で会いましょう :)