Quantcast
Channel: 日々の覚書
Viewing all 581 articles
Browse latest View live

吉祥寺.pm 11でMySQLのステータスモニタリングについて話をしてきた

$
0
0
「夏の吉祥寺、夏のpm」ってことで行ってきました。
思い起こせば一昨年の YAPC::Asia Tokyo 2015 2日目のLT、俺のLTの次が magnoliakさんで、「おー吉祥寺かー、いいなーもう少し西側に住んでれば行きたいなー」とかそんなことを考えていました。
(このことをおぼえていて下さったそうで、懇親会でそんな話をできたりしました! ビバYAPC)
それから2年、多摩地域の住人となった今こそ、吉祥寺.pmに参加するのだ!!
というわけで話してきたのは、最近(楽しい方面で)ハマっているステータスモニタリングについてでした。 SQLで引けるからPerlでもPHPでもRubyでもPythonでもGoでもCでもなんでも好きなもので引けばいいんですよ、案外簡単なものです、という話。
あと そーだいさんと久々にキャッキャウフフしてきました。 なお我々、そーだいさんが東京に来てから初めて会ったようです。
今回は事前のリポジトリーの内容がちゃんと整理されていたので(?)、二人でグダグダ言い合うスタイルではなくそーだいさんがテンポよく進めてくれるスタイル。 PostgreSQLのモニタリング周り試してみたいなーと思いつつ、 肝心のモニタリングするPostgreSQLがないあたりどうしようもないなあ。

俺は Chiba.pm生まれMyNA会とCasual育ちなので、.pmにはやっぱり思い入れがあったりします。
次はおじさんとして出張る組じゃなくて、 若い人の初セッションとか聞きに行きたいですね :)
俺も kazeburoさんと仕事したいけど、 lhfukamachiがいるのでまだまだ今の会社にいます :)

MySQL 8.0.2以降ではundoテーブルスペースファイルを勝手に拡張してくれるみたい

$
0
0
MySQL 5.7で InnoDB UNDO Log Truncation が追加されたものの、 innodb_undo_tablespacesmysqld --initializeの時に既に指定されていないといけなくて、一度ibdata1が初期化されてしまうと二度と変更できないという制約がありました。
こんなログが出て起動に失敗したりとか失敗したりとか失敗したりとか
2017-07-19T16:00:43.739980+09:00 0 [ERROR] InnoDB: Expected to open 2 undo tablespaces but was able to find only 0 undo tablespaces. Set the innodb_undo_tablespaces parameter to the correct value and retry. Suggested value is 0
ところで、 MySQL 8.0.2からinnodb_undo_tablespacesはデフォルトで2になるんですが、MySQL 5.7とそれ以前でinnodb_undo_tablespaces=0で初期化したdatadirをアップグレードしようとすると起動しなくなるとか

( ゚д゚) 初心者殺しの罠の気配がする…!

と思ったらなんだか 初期化した後でinnodb_undo_tablespacesが変わってるとUNDOスペースファイルを勝手に再生成してくれるという、とっても親切設計に変わっていたのでした。 5.6とそれ以降だとInnoDBログファイルを自動で再作成してくれるのとよく似たログ。
2017-07-19T07:07:49.402158Z 1 [Note] InnoDB: Expected to open 2 undo tablespaces but found none. Will create 2 new undo tables
paces.
2017-07-19T07:07:49.402171Z 1 [Note] InnoDB: Opened 0 existing undo tablespaces.
2017-07-19T07:07:49.404282Z 1 [Note] InnoDB: Creating UNDO Tablespace ./undo_001
2017-07-19T07:07:49.404306Z 1 [Note] InnoDB: Setting file ./undo_001 size to 10 MB
2017-07-19T07:07:49.404314Z 1 [Note] InnoDB: Physically writing the file full
2017-07-19T07:07:49.427852Z 1 [Note] InnoDB: Creating UNDO Tablespace ./undo_002
2017-07-19T07:07:49.427874Z 1 [Note] InnoDB: Setting file ./undo_002 size to 10 MB
2017-07-19T07:07:49.427879Z 1 [Note] InnoDB: Physically writing the file full
2017-07-19T07:07:49.446756Z 1 [Note] InnoDB: Created 2 undo tablespaces.
2017-07-19T07:07:49.476868Z 1 [Note] InnoDB: Creating shared tablespace for temporary tables
2017-07-19T07:07:49.476924Z 1 [Note] InnoDB: Setting file './ibtmp1' size to 12 MB. Physically writing the file full; Please w
ait ...
2017-07-19T07:07:49.496170Z 1 [Note] InnoDB: File './ibtmp1' size is now 12 MB.
2017-07-19T07:07:49.503862Z 1 [Note] InnoDB: Created 128 and tracked 128 new rollback segment(s) in the temporary tablespace.
128 are now active.
2017-07-19T07:07:49.527640Z 1 [Note] InnoDB: Created 128 and tracked 128 new rollback segment(s) in undo tablespace number 1.
128 are now active.
2017-07-19T07:07:49.551586Z 1 [Note] InnoDB: Created 128 and tracked 128 new rollback segment(s) in undo tablespace number 2.
128 are now active.
しかもなんか innodb_undo_log_truncateもデフォルトでONになったみたい。
これはトランザクションの粒度が細かいところだと(少なくとも5.7.5で俺が試した時は)つらそうだったので、ちゃんとベンチマーク取った方がいいかなー。
俺が楽になるとても良い機能追加だ! ビバ!

GTIDを有効にしているのにレプリケーションのポジションがズレる場合

$
0
0

TL;DR


GTIDを有効にしてレプリケーションを組んでいる( MASTER_AUTO_POSITION=1)場合、実行済みのトランザクションのGTIDは gtid_executedに記録される。
そしてI/Oスレッドは 自分のgtid_executedに含まれていないイベントがあれば寄越せ、というように接続時にマスターに要求するし、仮に自分のgtid_executedに含まれているイベントが寄越されてもSQLスレッドが同じGTIDのイベントの二重適用を防ぐ。
これでレプリケーションのポジションはズレない。ズレるはずがない。
gtid_executedが間違っていなければ
じゃあどこでgtid_executedが間違うのか。
  1. gtid_executedはそもそもサーバー変数で、オンメモリーだ。取り敢えずのところ、mysqldが停止しなければgtid_executedは間違わない(はず。間違うならそれはバグだ)
  2. mysqldが停止した場合、サーバー変数のgtid_executedは当然値が失われる。その場合、バイナリーログ(openしてれば)とmysql.gtid_executedから復元する
  3. mysql.gtid_executedはバイナリーログをopenしている場合はバイナリーログのスイッチ時とmysqldのシャットダウン時、openしていない場合はコミットの都度書き込む。マスターは確実にバイナリーログをopenしているので前者の動きになる
  4. ところで、ここに稼働中のマスターサーバーから取ったXtraBackupがあるじゃろ?
  5. トランザクションで保護するからmysql.gtid_executedテーブルはXtraBackup開始時の値が保管されるじゃろ?
  6. XtraBackupはバイナリーログは取らないじゃろ? (あればbinlogに記録されている分からgtid_executedをリカバってくれる)
  7. リストアして CHANGER MASTER TO .. MASTER_AUTO_POSITION= 1するとサクッとズレる
  8. _| ̄|○
リストアしてから CHANGE MASTER TO ..の前に、 RESET MASTERで gtid_executedの中身を吹っ飛ばし、 SET GLOBAL gtid_purged = '..'で設定するのが正しいと思う。
MySQL 5.7.18とそれ以前のmysqldumpでも同じことが起きる( --all-databaseでmysql.gtid_executedをダンプしてしまう)し、事実 去年隣にいた人はmysqldumpで踏んでた。これは最近リリースされたMySQL 5.7.19のmysqldumpでは直っているそうだけれども。
まあ何にせよ注意。。

数秒おきに ERROR: 2006 MySQL server has gone away でmysqlコマンドラインクライアントの接続が切れる

$
0
0
はじまりは @uessy_akrさんのツイート。






“MySQL Server has gone away” はクライアント側のエラー CR_SERVER_GONE_ERRORで、「クライアントは接続張りっぱなしのつもりなのに次のクエリーを投げたら実はサーバー側から接続を切られていた」時に出るエラー。
よって原因になり得るのは
  • タイムアウトが非常に短く設定されていて、クエリーの間隔がサーバー側タイムアウトに引っかかっている
  • 非常に短い間隔でmysqldがダウンしている
    • サーバープロセスがクラッシュすれば当然、接続していたコネクションは破棄されるから。
      • で、mysqld_safeがすぐにmysqldを再起動するので直後の接続は成功して、またクラッシュするやーつ。
    • 地雷erにはこっちの方が馴染みがある。。
    • SHOW STATUS LIKE 'uptime'psでmysqldの起動時刻を見たり、エラーログを見たりするのもいい。
  • ネットワークなどに問題があり、しょっちゅう接続が(中間のどこかで)プチプチ切れている
    • 体験したことないけど可能性としては一応
あたり。
で、なんかどうもどうやら






mysqldが毎回クラッシュしている方のケースだったらしい。。
signal 6SIGABRTで、MySQL内部のAssertに引っかかるとこれで落ちる。 ちなみに This could be because you hit a bug.は単なる(?)決まり文句で必ず言われるのであんまり関係ない。 体感で一番起きやすいのはInnoDBのページ破損でAssertに引っかかって食らうことが多い印象。
どうやら大正解だったっぽい。




バックアップがある場合はそこから切り戻すのが一番手っ取り早いし、それができない(最新の状態が壊れたところにしかないとか)場合は innodb_force_recoveryを駆使して無理矢理データを引っこ抜くしかない。
この手順はここが丁寧(クラッシュしてるわけじゃないからちょっと状況は違うけど、「解決策 - I. InnoDB の修復」が修復方法に当たる)
( ´-`).oO(あれ、他所へのリンクを貼りまくってるだけの記事になってしまった…

Test::More::Colorが息してなくてつらい

$
0
0
TL;DR
最近 Test::More::Colorで上手く色がつかない(´・ω・`)

古いのを引っ張り出してきて試してみるけれど、残っているもののうち Test::Simple-1.001014だとOK(色が付く)で、Test::Simpe-1.302086 だとNG(色が付かない)
Test2を使うようにしたこのコミットで、 _printが削除されてるので、v1.302013_001 以降のバージョンではTest::More::Colorが息をしなくなってる。
割と色んなものをTest::More::Color使ってバシバシ色を付けていたので、どうしようかなぐぬぬ。
個人的にはもうどこをフックさせればいいのか全然わからないので仕方なくTest::Simple-1.001014をインストールしてつかっています(´・ω・`)

Test::More::Colorでtoku_bassさんに助けてもらったはなし

$
0
0

TL;DR

@toku_bass さんありがとうございます!!!!1

今から24時間ほど前に 日々の覚書: Test::More::Colorが息してなくてつらいというエントリーを書いた。
そして24時間後の今、

tokubass/p5-Test-More-Color-SupportTest2

あなたが!!!! 神か!!!!
$ perl -MTest::More -M"Test::More::Color qw{foreground}" -E 'say $Test::More::VERSION; ok(1)'
1.302096
ok 1
# Tests were run but no plan was declared and done_testing() was not seen.





( ´-`).oO(あっテキストだとこの感動が伝わらない



「困ったなあ(自分では直せないけど)」から誰かに助けてもらえるのって本当に嬉しい。

ありがとうございます!
@toku_bass ++ !!

ファイルを吐かないtarコマンドの進捗を確認する

$
0
0
ファイルを吐かないというのは、MySQLのdatadirをtarボールに固めながら圧縮してS3にアップロードするようなケース(なんて限定的)
$ tar -C /var/lib -c mysql | pzstd -qc | aws s3 cp - s3://...
S3さん、アップロード終わるまで状況が見えないので、保管先のファイルサイズから全体をざっくり見積もることができなかった。俺のやり方が悪いだけかも知れない。
取り敢えず lsofで今掴んでいるファイルを見ることくらいまではぱっと思い付いた。
$ ps auxww | grep tar
root 1181 0.0 0.4 289208 4800 ? Ssl 23:15 0:00 /usr/bin/docker-containerd-current -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --shim docker-containerd-shim --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --runtime docker-runc --runtime-args --systemd-cgroup=true
yoku0825 3259 0.3 0.1 123344 1232 pts/0 S+ 23:22 0:00 tar c data
yoku0825 3263 0.0 0.0 112644 968 pts/1 R+ 23:22 0:00 grep --color=auto tar

$ lsof -p 3259
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
..
tar 3259 yoku0825 0u CHR 136,0 0t0 3 /dev/pts/0
tar 3259 yoku0825 1w FIFO 0,8 0t0 28213 pipe
tar 3259 yoku0825 2u CHR 136,0 0t0 3 /dev/pts/0
tar 3259 yoku0825 3r DIR 253,0 4096 71088914 /usr/mysql/5.7.19/data
tar 3259 yoku0825 4r REG 253,0 21091934 68051378 /usr/mysql/5.7.19/data/bin.000011
たとえば今は bin.000011を掴んでる、というところまではわかる。
が、 tarコマンドってファイルをどういう順番で掴むのかがわからず、bin.000011が全体で何番目のファイルなのかよくわからない。 経験則として、 tar cvfとか tar xvfでファイル名だだーっと流している時でも、少なくともファイルパスでソートされているようには見えない。
困った時のソースコード。
ディレクトリーをターゲットにtarボールを作る時には create_archivedump_filedump_file0dump_dirget_directory_entriesと来て、その中からgnulibstreamsavedirを呼び出している。
streamsavedirがやってることは単に readdirしているだけで、この時の並び順は特に決まった規則がある訳ではないらしい。
ところで readdirしたものをそのままといえば、lsのソート無しオプションである -fな訳で、
$ ls -fl 
total 239212
drwxr-x--- 9 yoku0825 yoku0825 4096 Oct 3 23:10 .
drwxrwxr-x 11 yoku0825 yoku0825 148 Jul 18 15:13 ..
-rw-r----- 1 yoku0825 yoku0825 79691776 Oct 3 23:10 ibdata1
-rw-r----- 1 yoku0825 yoku0825 56 Jul 18 15:12 auto.cnf
drwxr-x--- 2 yoku0825 yoku0825 4096 Aug 22 18:29 mysql
...
drwxr-x--- 2 yoku0825 yoku0825 4096 Aug 10 15:10 i_s
drwxr-x--- 2 yoku0825 yoku0825 8192 Aug 10 15:10 p_s
-rw-r----- 1 yoku0825 yoku0825 3818805 Aug 18 18:52 bin.000006
-rw-r----- 1 yoku0825 yoku0825 21091934 Aug 24 18:41 bin.000011
-rw-r----- 1 yoku0825 yoku0825 48221936 Sep 6 12:44 bin.000012
-rw-r----- 1 yoku0825 yoku0825 86553 Sep 15 15:47 bin.000017
-rw-r----- 1 yoku0825 yoku0825 10626 Sep 20 16:30 bin.000024
-rw-r----- 1 yoku0825 yoku0825 169 Aug 22 14:26 relay.000001
-rw-r----- 1 yoku0825 yoku0825 209 Sep 12 13:16 bin.000015
-rw-r----- 1 yoku0825 yoku0825 227 Sep 19 20:49 bin.000022
大体残り50MBくらいかなあと。ディレクトリー階層があるところなら親ディレクトリーがどの場所に並んでて、そのディレクトリーの中でファイルが何番目に位置しているか…とか丁寧に調べれば大体今何%のところにあるかは出せるような気がする。
とはいえまあ pipe viewer使えばいいよねとは思う。
$ tar -C /var/lib -c mysql | pv | pzstd -qc | aws s3 cp - s3://...
247MiB 0:00:04 [50.2MiB/s] [ <=>
pv使うの忘れた時とかcronからキックされた時用かな。

MySQL 8.0.0で予約語だったROLEが8.0.1ではキーワードになっていたはなし

$
0
0

TL;DR

  • hmatsu47さんに MySQLのキーワードと予約語の中で「ROLEは予約語じゃなくてキーワード」と教えてもらった
  • 予約語とキーワードの違いは、 role_or_ident_keywordにリストされているかどうか? (ちなみに5.7だと単に keywordってリストになってる)

シンボルのリスト

ラベルのリスト

ほげってみる

$ diff -c1 sql/sql_yacc.yy.orig sql/sql_yacc.yy
*** sql/sql_yacc.yy.orig 2017-09-19 20:33:50.000000000 +0900
--- sql/sql_yacc.yy 2017-10-30 16:23:04.657625949 +0900
***************
*** 13343,13345 ****
| RESTORE_SYM {}
- | ROLE_SYM {}
| ROLLBACK_SYM {}
--- 13343,13344 ----

$ make && make install

mysql80 8> SELECT @@version;
+--------------------+
| @@version |
+--------------------+
| 8.0.3-rc-debug-log |
+--------------------+
1 row in set (0.00 sec)

mysql80 8> CREATE TABLE t1 (role int);
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'role int)' at line 1
転けるようになった。

なんというか

予約語のキーワードと非予約語のキーワードの境目って案外大したことなかった…。 これを機に色々ゴニョって遊んでみ(ない

mysqlbinlog: [ERROR] unknown variable 'default-character-set=utf8mb4'と言われないためのTIPS

$
0
0
前にいつかどこかでメモした気がしなくもないけれど見つからなかったので。  ⇒ 書き上げてから思い出した、 第33回 MySQLのオプションファイル my.cnfの豆知識[その2]:MySQL道普請便りだ。。

default-character-setmysqlコマンドラインクライアントとか mysqldumpあたりで使う、クライアントの文字コードを指定するためのオプション。
MySQL 5.0以前ではサーバー側のデフォルトの文字コードを指定するオプションも同じ名前だったけど、現在ではそっちは character-set-serverに名前が変わっている。 MySQL 5.0では互換性のためにどちらの名前も使えたけれど、5.1で猶予期間が終わって大量の秘伝のタレを死に追いやったのはもはや懐かしい話。。
で、タイトルのエラーが出るような my.cnf
[client]
default-character-set=utf8mb4
と書いてあるケースがほとんどだと思う( [mysqlbinlog]セクションにわざわざ自分で default-character-setを書いたりしないだろうから)
[client]セクションは割と便利で、コマンドラインクライアントのほとんどがコンフィグファイルからそのセクションを読んでくれる。逆を言うと、 [client]セクションを読んでしまうプログラムが対応していないオプションを [client]セクションに書いてしまうと、タイトルのようなエラーが出ることになる。
どのプログラムがどのセクションを読むかは、ソースコードから load_default_groupsでgrepするとぽこぽこ出てきたりする。 [client]セクションを読むやつだけだっと抜粋。
./client/check/mysqlcheck.cc:static const char *load_default_groups[] = { "mysqlcheck", "client", 0 };
./client/dump/program.cc:const char *load_default_groups[]=
{
"client", /* Read settings how to connect to server. */
"mysql_dump", /* Read special settings for mysql_dump. */
0
};

./client/mysql.cc:static const char *load_default_groups[]= { "mysql","client",0 };
./client/mysql_secure_installation.cc:static const char *load_default_groups[]= { "mysql_secure_installation", "mysql", "client", 0 };
./client/mysqladmin.cc:static const char *load_default_groups[]= { "mysqladmin","client",0 };
./client/mysqlbinlog.cc:static const char *load_default_groups[]= { "mysqlbinlog","client",0 };
./client/mysqldump.c:static const char *load_default_groups[]= { "mysqldump","client",0 };
./client/mysqlimport.c:static const char *load_default_groups[]= { "mysqlimport","client",0 };
./client/mysqlshow.c:static const char *load_default_groups[]= { "mysqlshow","client",0 };
./client/mysqlslap.cc:static const char *load_default_groups[]= { "mysqlslap","client",0 };
./client/mysqltest.cc:static const char *load_default_groups[]= { "mysqltest", "client", 0 };
./client/upgrade/program.cc:const char *load_default_groups[]=
{
"client", /* Read settings how to connect to server */
"mysql_upgrade", /* Read special settings for mysql_upgrade*/
0
};

./extra/resolveip.c:/*static char * load_default_groups[]= { "resolveip","client",0 }; */
結構色々出てくる。 ほとんどのものはそう滅多に使わないし、正直これを全部考慮するのは無理ゲーなので、ワーニングを許容するなら loose接頭辞と組み合わせて設定するのがオススメだ。
[client]
loose-default-character-set=utf8mb4
このように loose接頭辞をつけておくと、 default-character-setを理解しない mysqlbinlogmysqlslapでもエラーでアボートせずにワーニングだけ出力して勘弁してくれる。
$ mysqlslap
mysqlslap: [Warning] unknown variable 'loose-default-character-set=utf8mb4'
参考までにウチのmy.cnfからクライアント用のセクションだけ引っこ抜いたのはこんな感じだった。
[client]
port= __port__ #<<
socket= __datadir__/mysql.sock #<<
loose-default-character-set= utf8mb4

[mysqldump]
quick
max_allowed_packet= 1G
single-transaction
#lock-all-tables
events
routines
triggers
master-data=2
#dump-slave=2

[mysql]
no-auto-rehash
show-warnings
prompt= "__hostname__ [\d]> " #<<
#safe-updates
syslog

今日のネタ提供は @purple_jwlさんでした。ごちそうさまでした。






MySQLから大量のレコードをちまちま削除するメモ

$
0
0
想定ケースとしては1億行くらいのテーブルから7000万行くらい消すクエリーを、レプリケーションが遅れずバッファプールも食い切らない程度にちまちま消すようにする。
DELETE FROM t1 WHERE hoge = 1 AND last_update < '2017-11-28'
「ちまちま削除する」なので、トランザクションでAll or Nothingを保証したい場合は使えない。 idをプライマリーキー(ただしサロゲートキーかどうかは問わない)、 hoge, last_updateが本来消し込みに使いたいカラムだとする。 プライマリーキー(またはユニークキー)がないテーブルのことは考えない。

KEY(hoge, last_update) がある場合

  • ターゲットのプライマリーキーを取り出して DELETE .. WHERE id IN ..の形に落とし込む
  • 行ロックに落とし込める
  • idの型を選ばない(varcharだろうと使える)
  • 自前でINリストを作るのが面倒ならGROUP_CONCATという手もあるけどその場合は group_concat_max_lenに注意
  • DELETEの方でもとの条件をANDしておくのを忘れると事故ることがある。。
  • プライマリーキーに対するWHEREがあるので実行計画で暴発しにくい…?
    • けどあんまりINのリストを長くするとテーブルスキャン選びやがった on 5.7
SELECT id FROM t1 WHERE hoge = 1 AND last_update < '2017-11-28' ORDER BY id LIMIT 1000;
DELETE FROM t1 WHERE id IN (.., ..) AND hoge = 1 AND last_update < '2017-11-28';

SELECT id FROM t1 WHERE hoge = 1 AND last_update < '2017-11-28' ORDER BY id LIMIT 1000;
DELETE FROM t1 WHERE id IN (.., ..) AND hoge = 1 AND last_update < '2017-11-28';

..

(KEY(hoge) のみがある、または削除に使えるキーがない) && idが数値型の場合

  • idのレンジを細かく区切ってループさせる
  • 最終的には全レコードにアクセスしないといけないので一度にやるとバッファプールが荒れる。適度にsleepを入れること
  • ネクストキーロックなので、DELETEしてる範囲(+α)にINSERTやUPDATEが来るとブロックされる
DELETE FROM t1 WHERE hoge = 1 AND last_update < '2017-11-28' AND id BETWEEN 1 AND 1000;
DELETE FROM t1 WHERE hoge = 1 AND last_update < '2017-11-28' AND id BETWEEN 1001 AND 2000;
DELETE FROM t1 WHERE hoge = 1 AND last_update < '2017-11-28' AND id BETWEEN 2001 AND 3000;
..

KEY(hoge) のみがある && idが文字列型の場合

  • idの最小値を取ってORDER BY id LIMITで少しずつ行く
  • 最終的には全レコードにアクセスしないといけないので一度にやるとバッファプールが荒れる。適度にsleepを入れること
  • ネクストキーロックなので、DELETEしてる範囲(+α)にINSERTやUPDATEが来るとブロックされる
  • 実行計画が暴発すると地獄が見えるのでDELETEの方はUSE INDEXした方が良さげ。DELETEでUSE INDEXするには テーブルリファレンス構文の方を使う
  • 正直この辺まで来るとtsvにでも吐き出させて WHERE id IN (..)の形にした方が良いような気がする
SELECT MIN(id) AS min_id FROM t1 WHERE hoge = 1 AND last_update < '2017-11-28' ;
DELETE t1 FROM t1 USE INDEX(PRIMARY) WHERE id >= $min_id AND hoge = 1 AND last_update < '2017-11-28' ORDER BY id LIMIT 1000;

SELECT MIN(id) AS min_id FROM t1 WHERE hoge = 1 AND last_update < '2017-11-28' ;
DELETE t1 FROM t1 USE INDEX(PRIMARY) WHERE id >= $min_id AND hoge = 1 AND last_update < '2017-11-28' ORDER BY id LIMIT 1000;
..

削除に使えるキーがなくてidが文字列型の場合

  • 悔い改めなさい
  • 一度tsvにでも吐き出させて WHERE id IN (..)の形に落とし込む
  • SELECTで1回テーブルスキャン、これでバッファプールが荒れそう。ぶん回しても良いバックアップとかバッチ用とかのMySQLがあればここが無視できるからこのやり方でも安定しそう
SELECT id FROM t1 WHERE hoge = 1 AND last_update < '2017-11-28'  INTO OUTFILE '/tmp/target.txt; /* これが時間かかるはずなのでたっぷり後悔できる */

DELETE FROM t1 WHERE id IN (.., ..) AND hoge = 1 AND last_update < '2017-11-28'; /* お好みの言語でファイルを処理してINリストを作る */
DELETE FROM t1 WHERE id IN (.., ..) AND hoge = 1 AND last_update < '2017-11-28';
..
どうでしょう。

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

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

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

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

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

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

ytkit - Yoku-san no ToolKITの紹介

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

yt-binlog-groupby

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

yt-healthcheck

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

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

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

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

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

..
Thank you for choosing MySQL!

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

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

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




mikasafabric for MySQLのつらいところ

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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



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

pfs_example_plugin_employee.so is 何

$
0
0
プラグインディレクトリーを覗いてたら pfs_example_plugin_employee.soなるファイルがあって知らないものなので調べてみた。
知らないプラグインを見つけた時の身元調査用に使えるかも知れないのでメモ。

まずはビルドしたディレクトリーの中で find、MySQL(に限らないのかもだけど)ではコンパイルした時にソースコードのすぐとなりにバイナリーが出来上がるので、変に名前の一部からディレクトリーの名前を類推するよりもこっちの方が楽だったりする。
$ find -name "pfs_example_plugin_employee.so"
./plugin/pfs_table_plugin/CMakeFiles/CMakeRelink.dir/pfs_example_plugin_employee.so
./plugin_output_directory/pfs_example_plugin_employee.so
という訳でソースは plugin/pfs_table_pluginの近くにありそう。
$ ll plugin/pfs_table_plugin/
total 124
drwxrwxr-x 4 yoku0825 yoku0825 125 Jan 9 13:47 CMakeFiles
-rw-rw-r-- 1 yoku0825 yoku0825 2274 Jan 9 13:47 cmake_install.cmake
-rw-r--r-- 1 yoku0825 yoku0825 1175 Sep 19 20:33 CMakeLists.txt
-rw-rw-r-- 1 yoku0825 yoku0825 319 Sep 21 22:29 CTestTestfile.cmake
-rw-rw-r-- 1 yoku0825 yoku0825 15021 Sep 21 22:29 Makefile
-rw-r--r-- 1 yoku0825 yoku0825 13276 Sep 19 20:33 pfs_example_employee_name.cc
-rw-r--r-- 1 yoku0825 yoku0825 5220 Sep 19 20:33 pfs_example_employee_name.h
-rw-r--r-- 1 yoku0825 yoku0825 10242 Sep 19 20:33 pfs_example_employee_salary.cc
-rw-r--r-- 1 yoku0825 yoku0825 4404 Sep 19 20:33 pfs_example_employee_salary.h
-rw-r--r-- 1 yoku0825 yoku0825 10271 Sep 19 20:33 pfs_example_machine.cc
-rw-r--r-- 1 yoku0825 yoku0825 4482 Sep 19 20:33 pfs_example_machine.h
-rw-r--r-- 1 yoku0825 yoku0825 8236 Sep 19 20:33 pfs_example_machines_by_emp_by_mtype.cc
-rw-r--r-- 1 yoku0825 yoku0825 5235 Sep 19 20:33 pfs_example_machines_by_emp_by_mtype.h
-rw-r--r-- 1 yoku0825 yoku0825 11821 Sep 19 20:33 pfs_example_plugin_employee.cc
本体はきっと pfs_example_plugin_employee.ccだなあと思いつつ中身を覗く。
MySQLのプラグインのソースを読むときは mysql_declare_pluginを探すと良い気がしていて、そこに SHOW PLUGINSで表示される情報や INSTALL PLUGIN, UNINSTALL PLUGINの時に走る関数が指定されている。ちなみに INSTALL PLUGINで指定するプラグインの名前は mysql_declare_pluginの引数になっている。これ豆。
…限りなく情報はゼロに近かった。 そんなに長くもないコードなのでゆっくり読むけれど、何をどう考えてもPerformance Schemaプラグインのサンプルコード。そもそも名前からそう。しかし MYSQL_DAEMON_PLUGINなのか。RCだから取り敢えずなのかどうかわからないけれど。
取り敢えず有効化してみようか。
mysql80 7> INSTALL PLUGIN pfs_example_plugin_employee SONAME 'pfs_example_plugin_employee.so';
Query OK, 0 rows affected (0.01 sec)

mysql80 7> SHOW PLUGINS\G
..
*************************** 42. row ***************************
Name: pfs_example_plugin_employee
Status: ACTIVE
Type: DAEMON
Library: pfs_example_plugin_employee.so
License: GPL
できた。 これできっとp_sのテーブルができているはず。
mysql80 7> use performance_schema
Database changed

mysql80 7> SHOW TABLES LIKE '%example%';
+------------------------------------------+
| Tables_in_performance_schema (%example%) |
+------------------------------------------+
| pfs_example_employee_name |
| pfs_example_employee_salary |
| pfs_example_machine |
| pfs_example_machine_by_employee_by_type |
+------------------------------------------+
4 rows in set (0.00 sec)

mysql80 7> SHOW CREATE TABLE pfs_example_employee_name\G
*************************** 1. row ***************************
Table: pfs_example_employee_name
Create Table: CREATE TABLE `pfs_example_employee_name` (
`EMPLOYEE_NUMBER` int(11) NOT NULL,
`FIRST_NAME` char(20) DEFAULT NULL,
`LAST_NAME` varchar(20) DEFAULT NULL,
PRIMARY KEY (`EMPLOYEE_NUMBER`),
KEY `FIRST_NAME` (`FIRST_NAME`)
) ENGINE=PERFORMANCE_SCHEMA DEFAULT CHARSET=utf8
1 row in set (0.01 sec)
☆―(ノ゚Д゚)八(゚Д゚ )ノイエ―イ
しかしこれ
mysql80 7> SELECT * FROM pfs_example_employee_name;
Empty set (0.00 sec)

mysql80 7> SELECT * FROM pfs_example_employee_salary;
Empty set (0.00 sec)

mysql80 7> SELECT * FROM pfs_example_machine;
Empty set (0.00 sec)

mysql80 7> SELECT * FROM pfs_example_machine_by_employee_by_type;
Empty set (0.00 sec)
中身が軒並み空なのは、想定した通りなんだろうか…( INSTALL PLUGINした時に いかにも固定値で値を詰め込むような処理を通るんだけれども…)
取り敢えずまあ、information_schemaプラグインのようにPerformance Schemaプラグインを書ける時代が来る鴨ってことですね。
取り敢えずPerformance Schemaプラグインに関する記述は(Daemonプラグインのところにも)まだ記述がない。
リリースノートにはなんか、8.0.2でその辺のインターフェイスが作られたようなことが書いてあった。
To support dynamic Performance Schema table manipulation, a new component service named pfs_table_service is now available.
MySQL :: MySQL 8.0 Release Notes :: Changes in MySQL 8.0.2 (2017-07-17, Development Milestone)

【2018/01/10 18:07】
rpmで mysql-community-test を入れるとこの pfs_example_plugin_employee プラグインが入っているわけですが、こっちで試すとちゃんとレコードが入ってた。


$ yum install --enablerepo="mysql80-community" mysql-community-test
$ mysqld --initialize-insecure --user=mysql
$ /etc/init.d/mysqld start

mysql> INSTALL PLUGIN pfs_example_plugin_employee SONAME 'pfs_example_plugin_employee.so';
Query OK, 0 rows affected (0.09 sec)

mysql> SELECT * FROM pfs_example_employee_name;
+-----------------+------------+-----------+
| EMPLOYEE_NUMBER | FIRST_NAME | LAST_NAME |
+-----------------+------------+-----------+
|               1 | foo1       | bar1      |
|               2 | foo2       | bar2      |
|               3 | foo3       | bar3      |
+-----------------+------------+-----------+
3 rows in set (0.01 sec)

mysql> SELECT * FROM pfs_example_employee_salary;
+-----------------+-----------------+---------------+---------------+
| EMPLOYEE_NUMBER | EMPLOYEE_SALARY | DATE_OF_BIRTH | TIME_OF_BIRTH |
+-----------------+-----------------+---------------+---------------+
|               1 |            1000 | 2013-11-12    | 12:02:34      |
|               2 |            2000 | 2016-02-29    | 12:12:30      |
|               3 |            3000 | 2017-03-24    | 11:12:50      |
+-----------------+-----------------+---------------+---------------+
3 rows in set (0.07 sec)

mysql> SELECT * FROM pfs_example_machine;
+-------------------+--------------+--------------+-----------------+
| MACHINE_SL_NUMBER | MACHINE_TYPE | MACHINE_MADE | EMPLOYEE_NUMBER |
+-------------------+--------------+--------------+-----------------+
|                 1 | DESKTOP      | Lenovo       |               1 |
|                 2 | LAPTOP       | Dell         |               2 |
|                 3 | MOBILE       | Apple        |               1 |
|                 4 | MOBILE       | Samsung      |               1 |
|                 5 | LAPTOP       | Lenovo       |               2 |
|                 6 | MOBILE       | Nokia        |               2 |
|                 7 | LAPTOP       | Apple        |               1 |
|                 8 | LAPTOP       | HP           |               3 |
|                 9 | DESKTOP      | Apple        |               3 |
+-------------------+--------------+--------------+-----------------+
9 rows in set (0.00 sec)

mysql> SELECT * FROM pfs_example_machine_by_employee_by_type;
+------------+-----------+--------------+-------+
| FIRST_NAME | LAST_NAME | MACHINE_TYPE | COUNT |
+------------+-----------+--------------+-------+
| foo1       | bar1      | LAPTOP       |     1 |
| foo1       | bar1      | DESKTOP      |     1 |
| foo1       | bar1      | MOBILE       |     2 |
| foo2       | bar2      | LAPTOP       |     2 |
| foo2       | bar2      | MOBILE       |     1 |
| foo3       | bar3      | LAPTOP       |     1 |
| foo3       | bar3      | DESKTOP      |     1 |
+------------+-----------+--------------+-------+
7 rows in set (0.00 sec)




MySQLのVALUES関数の(今のところ)唯一の使い道

$
0
0

TL;DR

PostgreSQLの VALUESは引数の表リテラル(行リテラルや列リテラルを含む)をテーブルリファレンスにして返してくれる関数だけれど、MySQLの VALUESは残念ながらそんなことはない。

MySQLのINSERTにおけるVALUESはただのキーワードでVALUES関数ではない。
なのでPostgreSQLみたいに表リテラルからテーブルリファレンスを組み立てる用途には使えない(´・ω・`) < よく言われるやーつだ
ところがどっこい、そのVALUESキーワードとは に、VALUES関数があって、コイツがまたフツーのVALUES関数ではなくて
INSERT … ON DUPLICATE KEY UPDATE ステートメントでは、UPDATE 句の VALUES(col_name) 関数を使用すると、ステートメントの INSERT 部分からカラム値を参照できます。
というニッチな関数になっている。
つまり、
INSERT INTO t1 (num, val, dt) VALUES (1, 'one', '2018-01-18 12:40:00') ON DUPLICATE KEY UPDATE dt = '2018-01-18 12:40:00';
INSERT INTO t1 (num, val, dt) VALUES (1, 'one', '2018-01-18 12:40:00') ON DUPLICATE KEY UPDATE dt = VALUES(dt);
が等価として扱えるというだけの関数である。
もうちょっと他の名前はなかったのか…。

MySQL 8.0.4におけるデフォルト認証形式の変更

$
0
0

Incompatible Change: The caching_sha2_password and sha256_password authentication plugins provide more secure password encryption than the mysql_native_password plugin, and caching_sha2_password provides better performance than sha256_password. Due to these superior security and performance characteristics of caching_sha2_password, it is now the preferred authentication plugin, and is also the default authentication plugin rather than mysql_native_password. This change affects both the server and the libmysqlclient client library:

MySQLはそれぞれのアカウントが「どうやって認証されるべきか」をアカウント情報の中に持っている(5.6とそれ以降) mysql.userテーブルには pluginというカラムがあって、
mysql80 10> SELECT user, host, plugin FROM user;
+------------------+-----------+-----------------------+
| user | host | plugin |
+------------------+-----------+-----------------------+
| mysql.infoschema | localhost | mysql_native_password |
| mysql.session | localhost | mysql_native_password |
| mysql.sys | localhost | mysql_native_password |
| root | localhost | caching_sha2_password |
+------------------+-----------+-----------------------+
4 rows in set (0.00 sec)
この場合、 mysql.infoschema@localhost, mysql.session@localhost, mysql.sys@localhostmysql_native_passwordプラグイン、 root@localhostcaching_sha2_passwordで認証される、という設定になっている。
MySQLの認証はチャレンジ・レスポンス認証なので、クライアントとサーバーで同じ認証形式をサポートしている必要がある。
root@localhostでログインしようとする場合、クライアント側も caching_sha2_passwordプラグインをサポートしていないといけないが、MySQL 5.7(少なくとも5.7.21)とそれ以前のバージョンには存在しないので転ける。
$ /usr/mysql/5.7.21/bin/mysql -S /usr/mysql/8.0.4/data/mysql.sock -u root
ERROR 2059 (HY000): Authentication plugin 'caching_sha2_password' cannot be loaded: /usr/mysql/5.7.21/lib/plugin/caching_sha2_password.so: cannot open shared object file: No such file or directory
それに対して mysql.sys@localhostなどはそもそも今までの mysql_native_passwordプラグインを使おうとするので、5.7とそれ以前のクライアントから接続しようとしても「パスワードが違う」エラーだけで、認証プラグインがどうこうのエラーにはならない。
$ /usr/mysql/5.7.21/bin/mysql -S /usr/mysql/8.0.4/data/mysql.sock -u mysql.sys
ERROR 1045 (28000): Access denied for user 'mysql.sys'@'localhost' (using password: NO)
MySQL 8.0.4とそれ以降は、認証プラグインを指定しないでユーザーを作成した場合のデフォルトが caching_sha2_passwordになっているので、MySQL 8.0.4とそれ以降にアップグレードしてから(プラグインを指定せずに)新しく作ったユーザーに対して、5.7とそれ以前と caching_sha2_passwordをサポートしていないライブラリーで接続しようとすると炸裂する。
これを避けるにはサーバー側に default_authentication_pluginを設定しておけば良くて、
$ vim my.cnf
[mysqld]
default_authentication_plugin= mysql_native_password
これで認証プラグイン指定しなかった場合のデフォルトが mysql_native_passwordに変更できる。再起動が必要なので(少なくともPHPのmysqlndとかその他libmysqlclient使ってるやつでも8.0に追従するまでは)秘伝のタレに入れておいていいかと。
デフォルトは変えずにユーザー単位で指定する場合は、 WITH mysql_native_passwordを指定すればOK( mysqldumpmysqlpumpにはこの WITH指定が含まれているので、8.0.4とそれ以降に対してこれらをリストアしても大丈夫)

mysql80 13> CREATE USER yoku0825 IDENTIFIED WITH mysql_native_password BY 'hogehoge';
Query OK, 0 rows affected (0.02 sec)
パスワードはハッシュ形式で保管されるので、既に存在していてパスワードを設定してしまったアカウントを ALTER USERで変更してもパスワードハッシュは更新されず…というかそれどころか IDENTIFIED BY ''と同じ扱いになってパスワードがからっぽになる。
mysql80 23> SELECT user, host, plugin, authentication_string FROM user;
+------------------+-----------+-----------------------+-------------------------------------------+
| user | host | plugin | authentication_string |
+------------------+-----------+-----------------------+-------------------------------------------+
| yoku0825 | % | mysql_native_password | *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 |
| mysql.infoschema | localhost | mysql_native_password | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE |
| mysql.session | localhost | mysql_native_password | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE |
| mysql.sys | localhost | mysql_native_password | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE |
| root | localhost | mysql_native_password | |
+------------------+-----------+-----------------------+-------------------------------------------+
5 rows in set (0.00 sec)

mysql80 23> ALTER USER yoku0825 IDENTIFIED WITH caching_sha2_password;
Query OK, 0 rows affected (0.00 sec)

mysql80 23> SELECT user, host, plugin, authentication_string FROM user;
+------------------+-----------+-----------------------+-------------------------------------------+
| user | host | plugin | authentication_string |
+------------------+-----------+-----------------------+-------------------------------------------+
| yoku0825 | % | caching_sha2_password | |
| mysql.infoschema | localhost | mysql_native_password | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE |
| mysql.session | localhost | mysql_native_password | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE |
| mysql.sys | localhost | mysql_native_password | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE |
| root | localhost | mysql_native_password | |
+------------------+-----------+-----------------------+-------------------------------------------+
5 rows in set (0.00 sec)
これちょっと誤発動すると痛いからパーサーでエラーにしてほしいなぁ…。。。

【2018/01/24 17:22】

IDENTIFIED WITH auth_plugin
..
In addition, the password is marked expired. The user must choose a new one when next connecting.

https://dev.mysql.com/doc/refman/8.0/en/alter-user.html

だそうで。


mysql80 25> CREATE USER yoku0825 IDENTIFIED WITH caching_sha2_password BY 'caching_sha2';
Query OK, 0 rows affected (0.01 sec)

mysql80 25> SELECT user, host, plugin, authentication_string, password_expired FROM user WHERE user = 'yoku0825';
+----------+------+-----------------------+------------------------------------------------------------------------+------------------+
| user | host | plugin | authentication_string | password_expired |
+----------+------+-----------------------+------------------------------------------------------------------------+------------------+
| yoku0825 | % | caching_sha2_password | $A$005$feA!*,'z
LvMw1OqJfNOBC0z03D4plWGdAtRsSIxpQg7iDE1yowBB0 | N |
+----------+------+-----------------------+------------------------------------------------------------------------+------------------+
1 row in set (0.00 sec)

mysql80 25> ALTER USER yoku0825 IDENTIFIED WITH mysql_native_password;
Query OK, 0 rows affected (0.01 sec)

mysql80 25> SELECT user, host, plugin, authentication_string, password_expired FROM user WHERE user = 'yoku0825';
+----------+------+-----------------------+-----------------------+------------------+
| user | host | plugin | authentication_string | password_expired |
+----------+------+-----------------------+-----------------------+------------------+
| yoku0825 | % | mysql_native_password | | Y |
+----------+------+-----------------------+-----------------------+------------------+
1 row in set (0.00 sec)

$ mysql80 -uyoku0825
mysql80 26> show databases;
ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.



MySQL 8.0.4でエラーログのフォーマットが微妙に変わった

$
0
0

TL;DR

  • log_error_verbosityのデフォルトが3(Error + Warning + Note) から 2(Error + Warning)に変更されたよ
  • MySQL 8.0.4からエラーログのフィールドに error_idが追加されたよ
  • “Note”, “Warning”, “Error”の3つだった severityに “System”が追加されたよ
    • “System” は “Error” より強いレベルなので log_error_verbosityが1(最小値)でも出力される
  • ↓こんな出力になるよ

2018-01-25T01:22:56.821986Z 0 [System] [MY-010116] /usr/mysql/8.0.4/bin/mysqld (mysqld 8.0.4-rc) starting as process 9206 ...

Messages written to the error log by the log_sink_internal log writer component now contain an error-ID indicator. This ID has a format of [error_id]. It follows the severity indicator and precedes the message text. For more information, see Error Log Message Format.
ということで、エラーログのフィールドがちょっと変わっている。
5.7.21の起動ログはこんな感じで
2018-01-25T01:24:06.510686Z mysqld_safe Logging to '/usr/mysql/5.7.21/data/error.log'.
2018-01-25T01:24:06.555127Z mysqld_safe Starting mysqld daemon with databases from /usr/mysql/5.7.21/data
2018-01-25T01:24:06.566872Z 0 [Warning] Changed limits: max_open_files: 1024 (requested 5000)
2018-01-25T01:24:06.567016Z 0 [Warning] Changed limits: table_open_cache: 431 (requested 2000)
..
2018-01-25T10:24:07.842676+09:00 0 [Warning] 'tables_priv' entry 'user mysql.session@localhost' ignored in --skip-name-resolve mode.
2018-01-25T10:24:07.842747+09:00 0 [Warning] 'tables_priv' entry 'sys_config mysql.sys@localhost' ignored in --skip-name-resolve mode.
2018-01-25T10:24:07.867477+09:00 0 [Note] Event Scheduler: Loaded 0 events
2018-01-25T10:24:07.867745+09:00 0 [Note] /usr/mysql/5.7.21/bin/mysqld: ready for connections.
Version: '5.7.21-log' socket: '/usr/mysql/5.7.21/data/mysql.sock' port: 64057 Source distribution
2018-01-25T10:24:07.906647+09:00 0 [Note] InnoDB: Buffer pool(s) load completed at 180125 10:24:07
8.0.4はこんな感じ。
2018-01-25T01:24:09.351792Z mysqld_safe Logging to '/usr/mysql/8.0.4/data/error.log'.
2018-01-25T01:24:09.415752Z mysqld_safe Starting mysqld daemon with databases from /usr/mysql/8.0.4/data
2018-01-25T01:24:09.596184Z 0 [Warning] [MY-010139] Changed limits: max_open_files: 1024 (requested 8161)
2018-01-25T01:24:09.596340Z 0 [Warning] [MY-010142] Changed limits: table_open_cache: 431 (requested 4000)2018-01-25T01:24:14.383583Z 0 [Warning] [MY-010323] 'db' entry 'sys mysql.sys@localhost' ignored in --skip-name-resolve mode.
..
2018-01-25T01:24:14.412655Z 0 [Warning] [MY-010330] 'tables_priv' entry 'user mysql.session@localhost' ignored in --skip-name-resolve mode.
2018-01-25T01:24:14.412724Z 0 [Warning] [MY-010330] 'tables_priv' entry 'sys_config mysql.sys@localhost' ignored in --skip-name-resolve mode.
2018-01-25T01:24:14.437421Z 0 [System] [MY-010931] /usr/mysql/8.0.4/bin/mysqld: ready for connections. Version: '8.0.4-rc-log' socket: '/usr/mysql/8.0.4/data/mysql.sock' port: 64080 Source distribution.
人間が読む分にはそんなに情報量は変わっていない。エラーIDでのググラビリティが上がるのかなって何この ORA-*的な MY-*はww
Systemで出力されるログにはどんなのがあるかざっと調べてみる。
$ grep -A1 SYSTEM_LEVEL sql/*.cc | grep ER
sql/mysqld.cc: LogErr(SYSTEM_LEVEL, ER_SERVER_SHUTDOWN_COMPLETE, my_progname);
sql/mysqld.cc: LogErr(SYSTEM_LEVEL, ER_STARTING_AS,
sql/mysqld.cc: LogErr(SYSTEM_LEVEL, ER_NORMAL_SHUTDOWN, my_progname);
sql/mysqld.cc- .lookup(ER_SERVER_STARTUP_MSG,
sql/rpl_slave.cc: LogErr(SYSTEM_LEVEL, ER_RPL_SLAVE_DUMP_THREAD_KILLED_BY_MASTER,
sql/rpl_slave.cc- ER_RPL_SLAVE_CONNECTED_TO_MASTER_REPLICATION_STARTED,
sql/rpl_slave.cc- ER_RPL_SLAVE_CONNECTED_TO_MASTER_REPLICATION_RESUMED,
sql/rpl_slave.cc: LogErr(SYSTEM_LEVEL, ER_SLAVE_CHANGE_MASTER_TO_EXECUTED,
sql/sql_parse.cc: LogErr(SYSTEM_LEVEL, ER_PARSER_TRACE,
sql/sql_parse.cc: LogErr(SYSTEM_LEVEL, ER_PARSER_TRACE, thd->query().str);
sql/sql_restart_server.cc: LogErr(SYSTEM_LEVEL, ER_RESTART_RECEIVED_INFO,
sql/sys_vars.cc: LogErr(SYSTEM_LEVEL, ER_CHANGED_GTID_MODE,
sql/sys_vars.cc: LogErr(SYSTEM_LEVEL, ER_GTID_PURGED_WAS_UPDATED,
sql/sys_vars.cc: LogErr(SYSTEM_LEVEL, ER_GTID_EXECUTED_WAS_UPDATED,
sql/xa.cc: LogErr(SYSTEM_LEVEL, ER_XA_STARTING_RECOVERY);
sql/xa.cc: LogErr(SYSTEM_LEVEL, ER_XA_RECOVERY_DONE);
全部は見てないけど、ER_SERVER_SHUTDOWN_COMPLETEとかER_NORMAL_SHUTDOWNとかは5.7とそれ以前ではNoteだった( log_error_verbosity < 3に設定すると見えなくなって焦ったやつ ⇒ 日々の覚書: MySQL 5.7では”[Note] mysqld: ready for connections”がどっかいった? (いってなかった)ので、 log_error_verbosity = 2をデフォルトにしても問題ないように布石を打ったのかしらん。 これは良い感じだ。
なおこの MY-*の数字は perrorで引くことができる。
$ /usr/mysql/8.0.4/bin/perror  010116
MySQL error code 10116 (ER_STARTING_AS): %s (mysqld %s) starting as process %lu ...

$ /usr/mysql/8.0.4/bin/perror 010931
MySQL error code 10931 (ER_SERVER_STARTUP_MSG): %s: ready for connections. Version: '%s' socket: '%s' port: %d %s.
大した話ではないけどなかなか面白かった。
Viewing all 581 articles
Browse latest View live