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"を取ってもそんな動きだった)


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