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

MariaDBが{basedir}/etc/my.cnfを読んでくれないらしい

$
0
0
風邪でぼんやりしてる中、ITOHさんのつぶやきで現実に戻ってみる。



…ん? {basedir}/etc/my.cnf、そもそも読んだっけ?

http://dev.mysql.com/doc/refman/5.5/en/option-files.html

ここを読んでも読む気配はなさげ。
そういえば前に調べたな。。

http://yoku0825.blogspot.jp/2012/11/mycnf.html

うーん、{basedir}/etc/my.cnfってのは/usr/local/mysql/etc/my.cnfのことかな?
cmakeするときにデフォルトをいじらなければ、basedirは/usr/local/mysql, sysconfdirは/usr/local/mysql/etcだから結果としては{basedir}/etc/my.cnfになるけど。

でも違いそうだな。。
MySQL5.5.30, MariaDB5.5.30とも、mysys/default.cはこんな感じ。
 140   - Unix:        /etc/
 141   - Unix:        /etc/mysql/
 142   - Unix:        --sysconfdir=<path> (compile-time option)
 143   - ALL:         getenv("MYSQL_HOME")
 144   - ALL:         --defaults-extra-file=<path> (run-time option)
 145   - Unix:        ~/
..
1225   errors += add_directory(alloc, "/etc/", dirs);
1226   errors += add_directory(alloc, "/etc/mysql/", dirs);
1227
1228 #if defined(DEFAULT_SYSCONFDIR)
1229   if (DEFAULT_SYSCONFDIR[0])
1230     errors += add_directory(alloc, DEFAULT_SYSCONFDIR, dirs);
1231 #endif /* DEFAULT_SYSCONFDIR */
1232
1233 #endif
1234
1235   if ((env= getenv("MYSQL_HOME")))
1236     errors += add_directory(alloc, env, dirs);
1237
1238   /* Placeholder for --defaults-extra-file=<path> */
1239   errors += add_directory(alloc, "", dirs);
1240
1241 #if !defined(__WIN__)
1242   errors += add_directory(alloc, "~/", dirs);
1243 #endif
順番的には/mnt/s3700/mysql-5.6.11/etcは$MYSQL_HOMEに当たりそうな気がする。
$MYSQL_HOMEってmysqld_safeの中であちゃこちゃいじっててよくわかんなくなるんだよな。。

gdbで順番に追ってみる。
まずはMariaDB 5.5.30。

# gdb bin/mysqld
..
(gdb) b add_directory
Breakpoint 1 at 0xa6bc78: file /home/yoku0825/mariadb-5.5.30/mysys/default.c, line 1117.
(gdb) r
Starting program: /usr/maria/5.5.30/bin/mysqld
..
Breakpoint 1, add_directory (alloc=0x7fffffffe340, dir=0xbff585 "/etc/", dirs=0x19c0458)
    at /home/yoku0825/mariadb-5.5.30/mysys/default.c:1117
1117      len= normalize_dirname(buf, dir);

まず/etc/を取った。

(gdb) c
Continuing.

Breakpoint 1, add_directory (alloc=0x7fffffffe340, dir=0xbff58b "/etc/mysql/", dirs=0x19c0458)
    at /home/yoku0825/mariadb-5.5.30/mysys/default.c:1117
1117      len= normalize_dirname(buf, dir);

次に/etc/mysql/、ここまではハードコードされてる通り。

(gdb) c

Breakpoint 1, add_directory (alloc=0x7fffffffe340, dir=0xae3a77 "", dirs=0x19c0458)
    at /home/yoku0825/mariadb-5.5.30/mysys/default.c:1117
1117      len= normalize_dirname(buf, dir);

あ、sysconfdirとMYSQL_HOME飛ばしてdefaults-extra-fileに行ったぽい。
ああ、MYSQL_HOMEが飛んでるのは多分mysqld_safeを通さずに直接mysqldを叩いてるからか。

(gdb) c
Continuing.

Breakpoint 1, add_directory (alloc=0x7fffffffe340, dir=0xbff5a2 "~/", dirs=0x19c0458)
    at /home/yoku0825/mariadb-5.5.30/mysys/default.c:1117
1117      len= normalize_dirname(buf, dir);

でホームディレクトリの.my.cnfを取ると。

(gdb) c
Continuing.
..

ここで起動終了。
sysconfdirって定義されてないのね。。

続いてMySQL 5.5.30。

# gdb bin/mysqld
..
(gdb) b add_directory
Breakpoint 1 at 0x746fa0: file /home/yoku0825/mysql-5.5.30/mysys/default.c, line 1111.
(gdb) r
Starting program: /usr/mysql/5.5.30/bin/mysqld
..
Breakpoint 1, add_directory (alloc=0x7fffffffe2e0, dir=0x9bef03 "/etc/", dirs=0xf68c00)
    at /home/yoku0825/mysql-5.5.30/mysys/default.c:1111
1111    {
(gdb) c
Continuing.

Breakpoint 1, add_directory (alloc=0x7fffffffe2e0, dir=0x9bef09 "/etc/mysql/", dirs=0xf68c00)
    at /home/yoku0825/mysql-5.5.30/mysys/default.c:1111
1111    {
(gdb) c
Continuing.

Breakpoint 1, add_directory (alloc=0x7fffffffe2e0, dir=0x9bef15 "/usr/local/mysql/etc", dirs=0xf68c00)
    at /home/yoku0825/mysql-5.5.30/mysys/default.c:1111
1111    {
(gdb) c
Continuing.

Breakpoint 1, add_directory (alloc=0x7fffffffe2e0, dir=0x90931f "", dirs=0xf68c00)
    at /home/yoku0825/mysql-5.5.30/mysys/default.c:1111
1111    {
(gdb) c
Continuing.

Breakpoint 1, add_directory (alloc=0x7fffffffe2e0, dir=0x9bef35 "~/", dirs=0xf68c00)
    at /home/yoku0825/mysql-5.5.30/mysys/default.c:1111
1111    {
(gdb) c
Continuing.

こっちはsysconfdirが定義されてるぽい。

$ cmake -i mysql-5.5.30/
..
Variable Name: SYSCONFDIR
Description: config directory (for my.cnf)
Current Value: /usr/local/mysql/etc
New Value (Enter to keep current value):
..

$ cmake -i mariadb-5.5.30/
..

やっぱSYSCONFDIRがないね。

いやでもSYSCONFDIRじゃなくてMYSQL_HOMEっぽいんだよな。。

$ diff mysql-5.5.30/scripts/mysqld_safe.sh mariadb-5.5.30/scripts/mysqld_safe.sh
..

ばらばら違い出てくるけど、熱あるしよくわかんない。。
余力があったらまたこんど。。今日はもうだめだ。。


MariaDB5.5.30の--crash-scriptオプションとか

$
0
0
MariaDBの追加オプション。
--crash-script=FILE        Script to call when mysqld crashes
--no-auto-restart          Exit after starting mysqld
--nowatch                  Exit after starting mysqld
--crash-scriptに何かを指定しておくと、mysqldが落ちた時に指定したファイルを実行してくれて
その標準出力と標準エラー出力をmysqld_safeのログファイル(つまりエラーログ)に書き出してくれる。
何か通知スクリプト入れておくと良いかも知れない。

--no-auto-restart, --nowatch(と、usageには出てこないけど--no-watchも)を指定しておくと、
mysqldを起動した後にmysqld_safeがexitするように指定される。
なので、mysqldが落ちても自動で再起動してくれなくなる。


すごく関係なさそうだけど、
MySQLは--datadirだけがdatadir、MariaDBは--data, --datadirがdatadirに格納される。

あと、MariaDBのmysqld_safeはmy_print_defaultsに--mysqldオプションをつけていて、
これはMySQLのmy_print_defaultsには無いオプションなので、
MariaDBのmysqld_safeではMySQLのmysqldは起動できない。

my_print_defaultsの差分は細かいところを除けばそれくらいぽかった。


--crash-scriptでへーと思って調べ始めたらむしろ、MariaDBのmysqld_safeでMySQLのmysqldが起動できないことに吃驚した。

mysqld_safeは如何にしてmysqldのダウンを検知するのか

$
0
0
LinuxとかUnixのMySQL-serverにくっついてくるmysqld_safe、コイツは内部でmysqldを呼ぶ
シェルスクリプトになっていて、環境変数の面倒とかulimitの面倒とかumaskの面倒とか見てくれたりする。

mysqldが落ちるとmysqld_safeがそれを検知して起動してくれるんだけど、
今までコイツがどうやってmysqldダウンを検知してるんだか知らなかった。

で、よくよく読んでみると、なんと

 フ ォ ア グ ラ ウ ン ド で m y s q l d を 起 動 し て る

から、mysqldが落ちた途端にmysqld_safeに制御が戻って、
(mysqldを起動した(=eval_log_error関数)直後にリスタートの処理が書いてある)
ほぼノータイムでmysqldのダウンを検知する。

まさかこんなに当たり前でシンプルな作りだとは。なんかシグナルもらってるんだとずっと思ってたよ。。


あと、mysqld_safeってSIGTERMで落ちないようになってるのね。
そういえばオプション無しのkillで落ちなかった気がする。

MySQL 5.6.12の--connect-expired-passwordオプション

$
0
0
MySQL 5.6.12のChangeLogを読んでいて不思議に思った--connect-expired-passwordオプションのメモ。

オプションの説明を読んでもいまいちピンと来なかった。

どうやらpassword_expiredが'Y'になっている(rpmとかでインストールした時はこうなる)と、
非対話モードでのログインができないらしい。

とりあえずためす。

mysql56> grant all on *.* to test;
Query OK, 0 rows affected (0.05 sec)

mysql56> alter user test password expire;
Query OK, 0 rows affected (0.00 sec)

$ mysql -utest -e "select current_user()"
ERROR 1862 (HY000): Your password has expired. To log in you must change it using a client that supports expired passwords.

# mysql -utest --connect-expired-password -e "select current_user()"
ERROR 1820 (HY000) at line 1: You must SET PASSWORD before executing this statement

おおー、ホントだー。

これがあるからmysql_secure_installation
(Perl、内部でsystem("mysql .. < $command");って呼び方をしてる)
が動かなくて、今回動くようになったっていうBug Fixなのか。。

にしても、mysql_secure_installation使ってる人いるのかな?
個人的には手間がなくて便利なんだけれども、gtid-mode=ONにしてると怒られるから
(MyISAMなmysql.userテーブルを直接叩くので、gitd-mode=ONだとunsafeって言われて転ける)
使わなくなっちゃった感じです。5.5までは常用してた。

Amazon RDSでできないかも知れないことメモ

$
0
0
Amazon RDSのrootユーザーからは
SHUTDOWN, FILE, SUPER, REPLICATION SLAVE, CREATE TABLESPACEが
取り上げられているので、これでできなくなるであろうことのメモ。


Shutdown_priv
 mysqladmin shutdownでmysqldをシャットダウンできない。

File_priv
 LOAD DATA INFILEステートメントが使えない。
 SELECT .. INTO OUTFILEステートメントが使えない。
 LOAD_FILE関数が使えない。
  このページを見ていて知ったんだけれど、mysqldに--secure-file-privというオプションがあって、
  これにディレクトリ名を渡すと、
  そのディレクトリ{から|に}だけ{LOAD DATA|SELECT .. INTO OUTFILE|LOAD_FILE}できる
  というように制限をかけられるんだそうな。
  コンマ区切りとか2行書くとか試してみたけど、複数指定は不可能ぽい。

Super_priv
 レプリケーションスレーブになれない。
  (CHANGE MASTER TO, {START|STOP} SLAVEできない)
 自分のスレッド以外をKILL(ステートメントの方ね), mysqladmin killできない。
  (自分のスレッドはSUPERなしでもできるのか。。
 PURGE MASTER LOGSできない。
 SET GLOBALできない。
 mysqladmin debugできない。
 DEFINER属性を指定できない。
 max_connectionsに到達したときの+1コネクションがない。
 binlogが有効な場合、ストアドファンクションの{CREATE|DROP}ができない。
  (log-bin-trust-function-creators使えば作れる)
 SET @@sql_log_bin, SET @@binlog_formatできない。
 {CREATE|ALTER|DROP} SERVERできない。
  (いや、FEDERATEDエンジン使えるのか知らないけど)
 
Repl_slave_priv
 SHOW BINLOG EVENTSできない。
 SHOW SLAVE HOSTSできない。
 レプリケーションスレーブ作れない(GRANTできないから)

Create_tablespace_priv
 CREATE TABLESPACEできない…けどこれndbclusterのやつだから特に困らないはず。


少なくともこれだけの動作が(自前のMySQL rootに比べて)できなくなると思う。

なんかやたら推し量る系の言い回しなのは、RDSなんか変だから。
DROP USERした瞬間からそのユーザーの権限が無効になったり
 (フツーのMySQLは次にログインしたときかUSEでデータベース変えた時に効くはず)
なんか手を入れてる気がする。
バージョンもSource Distributionだし。。

MySQL 5.7 クライアントの新機能(?)

$
0
0
ちょっと感動したMySQL 5.7.1 クライアント(mysqldではない)の新機能。


まずは取り敢えずこのBugs。

MySQL Bugs: #66583: Ctrl-C behavior violates principle of least astonishment http://bugs.mysql.com/bug.php?id=66583

mysqlコマンドラインクライアントに向かってCtrl+Cを叩くとmysqlコマンドラインクライアントが落ちるという、
ごくごく馴染みの動作に対するFeature Request。

MySQL 4.1.6からは--sigint-ignoreというオプションで(そんな昔からあったのか)
SIGINTそのものを無効化してmysqlコマンドラインクライアントが終了しないようにできるものの、
これだとクエリを止めようと思ってもCtrl+Cで止まらなくなる。

$ mysql56 --sigint-ignore
..
mysql56> SELECT SLEEP(10);
^C^C^C^C^C^C^C^C^C+-----------+
| SLEEP(10) |
+-----------+
|         0 |
+-----------+
1 row in set (10.00 sec)

(´・ω・`) ショボーン

だが、MySQL 5.7.0以降では、SIGINTは無効化せず、
SIGINTでmysqlコマンドラインクライアントが終了する動作だけをハンドルしてくれるようになったのだ!
(何もオプション要らない。デフォルト。むしろ--sigint-ignore使うと↑と同じ動作になる)

$ mysql57 -S/usr/mysql/5.6.12/data/mysql.sock
..
mysql57> SELECT SLEEP(10);
^C^C -- query aborted
+-----------+
| SLEEP(10) |
+-----------+
+-----------+
1 row in set (0.51 sec)

mysql57> ^C
mysql57> ^C

mysqldの機能ではなく、mysqlコマンドラインクライアントの機能です。


ところでMySQL 5.7.1って、もうm11(milestone 11)なのね。
MySQL 5.6.6がm9でその次がMySQL 5.6.7-rc(release candidate)だったので、
結構もりもりやってると期待して良いのかしら。


【2013/06/13 17:44】
くだらないこと書いてやったぜー、と思っていたら、御大が既に書いていらっしゃった。。orz

http://nippondanji.blogspot.jp/2013/05/mysqlmysql-57.html

時間泥棒なMySQL Clusterのmemcached APIを起動してみる

$
0
0
ちょっと触ってみた。
使ったのはMySQL Cluster 7.3.1-m1(開発版)

( ´-`).oO(って書いてる間に、7.3.2がGAってリリースノートを見た。まだDownloadには来てない。


取り敢えずconfig.iniを最小限で作ってみる。

$ vim config.ini
[NDB_MGMD]
NodeId=49
HostName=localhost
DataDir=/home/yoku/mysql/ndb_7.3.1/mgmd
Portnumber=1186

[NDBD]
NodeId=1
HostName=localhost
DataDir=/home/yoku/mysql/ndb_7.3.1/ndbd/1

[NDBD]
NodeId=2
HostName=localhost
DataDir=/home/yoku/mysql/ndb_7.3.1/ndbd/2

[MYSQLD]
NodeId=51
HostName=localhost

[API]
NodeId=52
HostName=localhost

ディレクトリは自動で作ってくれないので自分で作ってから、ndb_mgmd起動。

$ mkdir -p mgmd ndbd/1 ndbd/2
$ bin/ndb_mgmd --initial --ndb-nodeid=49 --config-file=./config.ini

起動すればそれだけでバックグラウンドに回ってくれる。
続いてndbd。2つ。

$ bin/ndbd --initial --ndb-nodeid=1 --ndb-connectstring=localhost
$ bin/ndbd --initial --ndb-nodeid=2 --ndb-connectstring=localhost

おなじみmysqld。

$ vim my.cnf
[mysqld]
loose-ndbcluster
loose-ndb-connectstring= localhost:1186
log-error= error.log
log-bin= bin

$ scripts/mysql_install_db --datadir=./data
$ bin/mysqld_safe --defaults-file=./my.cnf --datadir=./data &

$ bin/ndb_mgm
ndb_mgm> SHOW
Connected to Management Server at: localhost:1186
Cluster Configuration
---------------------
[ndbd(NDB)]     2 node(s)
id=1    @127.0.0.1  (mysql-5.6.10 ndb-7.3.1, Nodegroup: 0, Master)
id=2    @127.0.0.1  (mysql-5.6.10 ndb-7.3.1, Nodegroup: 0)

[ndb_mgmd(MGM)] 1 node(s)
id=49   @127.0.0.1  (mysql-5.6.10 ndb-7.3.1)

[mysqld(API)]   2 node(s)
id=51   @127.0.0.1  (mysql-5.6.10 ndb-7.3.1)
id=52 (not connected, accepting connect from localhost)

ここまではOK。。(このあとかなりハマった。。)

NDB memcached EngineはInnoDB Memcached Pluginと同じく、
予めそれ用のテーブルを作っておく必要があるので、さっくり食わせる。

$ bin/mysql -uroot < share/memcache-api/ndb_memcache_metadata.sql
$ bin/mysql -uroot -e "SELECT * FROM ndbmemcache.containers"
+------------+-------------+------------------+-------------+----------------+-------+------------------+------------+--------------------+-----------------------------+
| name       | db_schema   | db_table         | key_columns | value_columns  | flags | increment_column | cas_column | expire_time_column | large_values_table          |
+------------+-------------+------------------+-------------+----------------+-------+------------------+------------+--------------------+-----------------------------+
| demo_table | ndbmemcache | demo_table       | mkey        | string_value   | flags | math_value       | cas_value  | NULL               | NULL                        |
| demo_tabs  | ndbmemcache | demo_table_tabs  | mkey        | val1,val2,val3 | flags | NULL             | NULL       | expire_time        | NULL                        |
| demo_ext   | ndbmemcache | demo_table_large | mkey        | string_value   | flags | NULL             | cas_value  | NULL               | ndbmemcache.external_values |
+------------+-------------+------------------+-------------+----------------+-------+------------------+------------+--------------------+-----------------------------+

InnoDB Memcached Pluginと同じように、メタデータを放り込むテーブルに色々定義してやる感じ。
InnoDBのアレはINSTALL PLUGINして再起動だけど、こっちはmemcachedが別プロセスになるのでひょっこり起動してやる。

$ bin/memcached -E lib/ndb_engine.so -e "connectstring=localhost:1186" &
18-Jun-2013 14:41:41 JST NDB Memcache 5.6.10-ndb-7.3.1 started [NDB 7.3.1; MySQL 5.6.10]
Contacting primary management server (localhost:1186) ...
Connected to "localhost:1186" as node id 52.
Retrieved 4 key prefixes for server role "default_role".
The default behavior is that:
    GET uses NDB only
    SET uses NDB only
    DELETE uses NDB only.
The 3 explicitly defined key prefixes are "b:" (demo_table_large), "mc:" () and "t:" (demo_table_tabs)
Server started with 4 threads.
Priming the pump ...
   Failed to grow connection pool.
Scheduler: using 1 connection to cluster 0
Scheduler: starting for 1 cluster; c0,f0,g1,t1
done [14.838 sec].

なぜか-dオプションでバックグラウンド起動させると上手くいかない(´・ω・`)

$ bin/ndb_mgm -e "SHOW"
Connected to Management Server at: localhost:1186
Cluster Configuration
---------------------
[ndbd(NDB)]     2 node(s)
id=1    @127.0.0.1  (mysql-5.6.10 ndb-7.3.1, Nodegroup: 0, Master)
id=2    @127.0.0.1  (mysql-5.6.10 ndb-7.3.1, Nodegroup: 0)

[ndb_mgmd(MGM)] 1 node(s)
id=49   @127.0.0.1  (mysql-5.6.10 ndb-7.3.1)

[mysqld(API)]   2 node(s)
id=51   @127.0.0.1  (mysql-5.6.10 ndb-7.3.1)
id=52   @127.0.0.1  (mysql-5.6.10 ndb-7.3.1)


$ less/mgmd/ndb_49_cluster.log
..

2013-06-18 14:41:40 [MgmtSrvr] INFO     -- Node 1: Communication to Node 52 opened
2013-06-18 14:41:41 [MgmtSrvr] INFO     -- Node 2: Communication to Node 52 opened
2013-06-18 14:41:42 [MgmtSrvr] INFO     -- Nodeid 52 allocated for API at 127.0.0.1
2013-06-18 14:41:42 [MgmtSrvr] INFO     -- Node 52: memcached
2013-06-18 14:41:42 [MgmtSrvr] INFO     -- Node 1: Node 52 Connected
2013-06-18 14:41:42 [MgmtSrvr] INFO     -- Node 2: Node 52 Connected
2013-06-18 14:41:42 [MgmtSrvr] INFO     -- Node 2: Node 52: API mysql-5.6.10 ndb-7.3.1
2013-06-18 14:41:42 [MgmtSrvr] INFO     -- Node 1: Node 52: API mysql-5.6.10 ndb-7.3.1
2013-06-18 14:41:45 [MgmtSrvr] WARNING  -- Failed to allocate nodeid for API at 127.0.0.1. Returned eror: 'No free node id found for mysqld(API).'
2013-06-18 14:41:48 [MgmtSrvr] WARNING  -- Failed to allocate nodeid for API at 127.0.0.1. Returned eror: 'No free node id found for mysqld(API).'
2013-06-18 14:41:51 [MgmtSrvr] WARNING  -- Failed to allocate nodeid for API at 127.0.0.1. Returned eror: 'No free node id found for mysqld(API).'
2013-06-18 14:41:54 [MgmtSrvr] WARNING  -- Failed to allocate nodeid for API at 127.0.0.1. Returned eror: 'No free node id found for mysqld(API).'
2013-06-18 14:41:57 [MgmtSrvr] WARNING  -- Failed to allocate nodeid for API at 127.0.0.1. Returned eror: 'No free node id found for mysqld(API).'

コネクションプールが作れないとか行ってたのは、APIノードの定義を2つしか作ってないから、
mysqldで1個、memcachedで1個しか使えなくてこうなってるのかな。


ともあれこれで

$ telnet localhost 11211
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
set name 0 0 8
yoku0825
Pipeline 0 attached to S scheduler.
STORED
get name
VALUE name 0 8
yoku0825
END
^]
telnet> quit
Connection closed.

$ bin/mysql -uroot -e "SELECT * FROM ndbmemcache.demo_table"
+------+------------+-------+---------------+--------------+
| mkey | math_value | flags | cas_value     | string_value |
+------+------------+-------+---------------+--------------+
| name |       NULL |     0 | 6129992073216 | yoku0825     |
+------+------------+-------+---------------+--------------+

イェーイ。

CREATE TEMPORARY TABLEとレプリケーション

$
0
0
マスターでこんな処理をしている時の話。
mysql> CREATE TEMPORARY TABLE this_is_tmp_table (..);
mysql> INSERT INTO this_is_tmp_table SELECT .. FROM this_is_origin_table WHERE ..;
mysql> UPDATE this_is_tmp_table SET ..;
mysql> INSERT INTO this_is_summary_table SELECT .. FROM this_is_tmp_table;
mysql> DROP TEMPORARY TABLE this_is_tmp_table;
テンポラリーテーブルを使ってごにょごにょした後に、
テンポラリーじゃないテーブルにデータを書き出すような処理。

テンポラリーテーブルは
・datadirではなくtmpdirにデータ実体が吐かれる(ibdata1は別として)
・CREATE TEMPORARY TABLEしたスレッド以外からは見えない
・CREATE TEMPORARY TABLEしたスレッドが接続を閉じれば消される
ような特性を持っている関係上、↑のような処理をレプリケーションしていると、
CREATE TEMPORARY TABLEからDROP TEMPORARY TABLEの間で
SQL_Threadが終了(STOP SLAVEやmysqldの再起動を含めて)してしまうと、
ステートメントベースのレプリケーションではそのままレプリケーションが再開できなくなる。

たとえば、↑の3行目の処理中にSTOP SLAVEしたりすると、
次にSTART SLAVEした時に
2013-06-18 21:44:30 8865 [ERROR] Slave SQL: Error 'Table 'd1.this_is_tmp_table' doesn't exist' on query. Default database: 'd1'. Query: 'INSERT INTO this_is_summary_table SELECT * FROM this_is_tmp_table', Error_code: 1146
となる。
この動作はbinlog_format = STATEMENTの時に起こり得る。

binlog_format = MIXEDだと、
$ mysqlbinlog -vv relay.000018
..
### INSERT INTO `d1`.`this_is_tmp_table`
### SET
###   @1=999990 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=NULL /* LONGINT meta=96 nullable=1 is_null=1 */
..
のように、テンポラリーテーブルを使ってる周りはレプリケーションアンセーフだと判定して、
ROWモードでの書き出しになる。
なので、この場合は途中で止めてもなんとかなる。

5.1で推しだったbinlog_format = MIXEDは、5.5からは暗黙のデフォルトでは`ない'ので注意。
(binlog_formatの暗黙のデフォルトはSTATEMENTに戻った。5.1の中盤~後半だけ暗黙のデフォルトがMIXED)

クエリーキャッシュはカレントデータベースやキャラクターセットも区別する

$
0
0
クエリーキャッシュに載ってるかどうかの判定はSQLがパースされる前に比較されるから、SELECTステートメントは一字一句同じでないとクエリキャッシュ利かないよ、というのは有名な話。

http://dev.mysql.com/doc/refman/5.5/en/query-cache-operation.html

取り敢えず↑に答えが書いてあったがメモ。

MariaDBのinformation_schema.QUERY_CACHE_INFOをいじっていて気が付いたんだけど、クエリーキャッシュってカレントデータベースも区別してクエリキャッシュに登録してる。
(↓の出力は、そのプラグインをMySQL5.5向けに書き直したやつだけど)

mysql55> RESET QUERY CACHE;
Query OK, 0 rows affected (0.00 sec)

mysql55> SHOW GLOBAL STATUS LIKE 'Qcache_queries_in_cache';
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| Qcache_queries_in_cache | 0     |
+-------------------------+-------+
1 row in set (0.00 sec)

mysql55> USE d1; SELECT * FROM d1.t1 LIMIT 2;
Database changed
+-----+------+
| num | val  |
+-----+------+
|   1 | NULL |
|   2 | NULL |
+-----+------+
2 rows in set (0.00 sec)

mysql55> USE information_schema; SELECT * FROM d1.t1 LIMIT 2;
Database changed
+-----+------+
| num | val  |
+-----+------+
|   1 | NULL |
|   2 | NULL |
+-----+------+
2 rows in set (0.00 sec)

mysql55> USE mysql; SELECT * FROM d1.t1 LIMIT 2;
Database changed
+-----+------+
| num | val  |
+-----+------+
|   1 | NULL |
|   2 | NULL |
+-----+------+
2 rows in set (0.00 sec)

mysql55> SELECT * FROM information_schema.query_cache_info;
+--------------------+-----------------------------+---------------------+--------------------+-------------------------+
| STATEMENT_SCHEMA   | STATEMENT_TEXT              | RESULT_BLOCKS_COUNT | RESULT_BLOCKS_SIZE | RESULT_BLOCKS_SIZE_USED |
+--------------------+-----------------------------+---------------------+--------------------+-------------------------+
| d1                 | SELECT * FROM d1.t1 LIMIT 2 |                   1 |                512 |                     177 |
| information_schema | SELECT * FROM d1.t1 LIMIT 2 |                   1 |                512 |                     177 |
| mysql              | SELECT * FROM d1.t1 LIMIT 2 |                   1 |                512 |                     177 |
+--------------------+-----------------------------+---------------------+--------------------+-------------------------+
3 rows in set (0.01 sec)

mysql55> SHOW GLOBAL STATUS LIKE 'Qcache_queries_in_cache';
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| Qcache_queries_in_cache | 3     |
+-------------------------+-------+
1 row in set (0.01 sec)


とはいえこれはよく考えれば当たり前で、↑のクエリはたまたまデータベース名まで修飾してるけど、テーブル名だけの場合はカレントデータベースが違えば当然別のクエリだもんね。
SQLステートメントの大文字小文字が違っただけで別のクエリーとしてキャッシュに押し込むsql/cache.ccが、データベース名まで修飾されてるからってよしなにやってくれるとは当然思えないので、これはこれで良い。

でもでも。

さっきのマニュアル、キャラクターセットやプロトコル(MySQLプロトコル)のバージョンも区別するって書いてあるぞ。。。

mysql55> SET NAMES sjis;
Query OK, 0 rows affected (0.00 sec)

mysql55> USE d1; SELECT * FROM d1.t1 LIMIT 2;
Database changed
+-----+------+
| num | val  |
+-----+------+
|   1 | NULL |
|   2 | NULL |
+-----+------+
2 rows in set (0.00 sec)

mysql55> USE information_schema; SELECT * FROM d1.t1 LIMIT 2;
Database changed
+-----+------+
| num | val  |
+-----+------+
|   1 | NULL |
|   2 | NULL |
+-----+------+
2 rows in set (0.00 sec)

mysql55> USE mysql; SELECT * FROM d1.t1 LIMIT 2;
Database changed
+-----+------+
| num | val  |
+-----+------+
|   1 | NULL |
|   2 | NULL |
+-----+------+
2 rows in set (0.00 sec)

mysql55> SELECT * FROM information_schema.query_cache_info;
+--------------------+-----------------------------+---------------------+--------------------+-------------------------+
| STATEMENT_SCHEMA   | STATEMENT_TEXT              | RESULT_BLOCKS_COUNT | RESULT_BLOCKS_SIZE | RESULT_BLOCKS_SIZE_USED |
+--------------------+-----------------------------+---------------------+--------------------+-------------------------+
| d1                 | SELECT * FROM d1.t1 LIMIT 2 |                   1 |                512 |                     177 |
| information_schema | SELECT * FROM d1.t1 LIMIT 2 |                   1 |                512 |                     177 |
| mysql              | SELECT * FROM d1.t1 LIMIT 2 |                   1 |                512 |                     177 |
| information_schema | SELECT * FROM d1.t1 LIMIT 2 |                   1 |                512 |                     177 |
| d1                 | SELECT * FROM d1.t1 LIMIT 2 |                   1 |                512 |                     177 |
| mysql              | SELECT * FROM d1.t1 LIMIT 2 |                   1 |                512 |                     177 |
+--------------------+-----------------------------+---------------------+--------------------+-------------------------+
6 rows in set (0.02 sec)

mysql55> SHOW GLOBAL STATUS LIKE 'Qcache_queries_in_cache';
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| Qcache_queries_in_cache | 6     |
+-------------------------+-------+
1 row in set (0.00 sec)

うええええ、ホントだ。これ知らなかった。
確かにbyte単位でSQLステートメントを比較してるだけなら、キャラクターセットが違ったら一致しないねぇ。

プロトコルバージョンの違いは、どのバージョンで変わってるのかよく判らなくて断念。
取り敢えず4.0.30だとプロトコルバージョン違いそうなんだけど、Authのアレで蹴られるので試せず。

最近クエリーキャッシュ漬け。

いつも忘れるSHOW SLAVE STATUSとかの権限

$
0
0
何度も忘れるのでいい加減メモ。

SHOW {MASTER|SLAVE} STATUSがSUPERまたはREPLICATION CLIENT、
SHOW SLAVE HOSTS, SHOW {BINLOG|RELAYLOG} EVENTSがREPLICATION SLAVE。

mysql55> SHOW MASTER STATUS;
ERROR 1227 (42000): Access denied; you need (at least one of) the SUPER,REPLICATION CLIENT privilege(s) for this operation

mysql55> SHOW SLAVE STATUS;
ERROR 1227 (42000): Access denied; you need (at least one of) the SUPER,REPLICATION CLIENT privilege(s) for this operation

mysql55> SHOW SLAVE HOSTS;
ERROR 1227 (42000): Access denied; you need (at least one of) the REPLICATION SLAVE privilege(s) for this operation

mysql55> SHOW BINLOG EVENTS IN 'bin.000001';
ERROR 1227 (42000): Access denied; you need (at least one of) the REPLICATION SLAVE privilege(s) for this operation

mysql55> SHOW RELAYLOG EVENTS IN 'relay.000001';
ERROR 1227 (42000): Access denied; you need (at least one of) the REPLICATION SLAVE privilege(s) for this operation

mysql55> RESET SLAVE;
ERROR 1227 (42000): Access denied; you need (at least one of) the RELOAD privilege(s) for this operation

mysql55> RESET MASTER;
ERROR 1227 (42000): Access denied; you need (at least one of) the RELOAD privilege(s) for this operation

本気でただのメモ。

手抜きでmysqlコマンドラインクライアントに色をつける

$
0
0
mysqlコマンドラインクライアントの表示に色をつけたくなった。
イメージとしてはこんな感じ。

$ client/mysql -S/usr/mysql/5.6.12/data/mysql.sock
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 11532
Server version: 5.6.12-log Source distribution

Copyright (c) 2000, 2013, 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.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
mysql>
mysql>
mysql> exit

Bye

mysql-5.6.12/client/mysql.ccに手抜きな感じで追加。

$ vim client/mysql.cc
..
1316   put_info("\033[1;31mWelcome to the MySQL monitor.  Commands end with ; or \\g.",
..
1429     put_info(sig ? "\033[0mAborted" : "\033[0mBye", INFO_RESULT);
..

ビバ、手抜き。

もう一度MySQL Utilitiesを試してみる(インストール編)

$
0
0
WEBサーバーが増設されて、MySQLのユーザーを追加しなきゃいけなかった時にCREATE USER .. LIKE ...みたいなのが使えたらなぁとか思っていたら、@RKajiyamaさんにmysqlusercloneがあるよ! と教えてもらったので試してみる。

MySQL Utilitiesはだいぶ前にmysqlfailoverを試したくて入れたっきりで、あの時はまだMySQL Workbenchにしか入っていなかった(いつだったか独立して入れられるようになった)ので、WorkbenchのソースコードからUtilitiesの部分だけインストールしたなぁとか感傷に浸りつつ、お手軽にrpmで突っ込む。

CentOS6.3だから本当は"Oracle & Red Hat Linux 6"じゃないんだけど気にしない。"Linux Generic"がないので。

$ sudo rpm -i http://dev.mysql.com/get/Downloads/MySQLGUITools/mysql-utilities-1.3.2-1.el6.noarch.rpm/from/http://cdn.mysql.com/
エラー: 依存性の欠如:
        mysql-connector-python >= 1.0.9 は mysql-utilities-1.3.2-1.el6.noarch に必要とされています

おやま。
MySQL公式のConnector/Pythonが必要で、MySQL-pythonじゃダメらしい。

$ sudo rpm -i http://dev.mysql.com/get/Downloads/Connector-Python/mysql-connector-python-1.0.10-1.el6.noarch.rpm/fro
m/http://cdn.mysql.com/

$ sudo rpm -i http://dev.mysql.com/get/Downloads/MySQLGUITools/mysql-utilities-1.3.2-1.el6.noarch.rpm/from/http://cdn.mysql.com/

入れたら通った。うん。
取り敢えずmysqluc(MySQL Utilities Client)を起動してみる。

$ mysqluc
Launching console ...
WARNING: mysqlauditadmin failed to read options. This utility will not be shown in 'help utilities' and cannot be accessed from the console.
ERROR: The mysqlauditadmin utility requires Python version 2.7.0 or higher and lower than 3.0.0. The version of Python detected was 2.6.6. You may need to install or redirect the execution of this utility to an environment that includes a compatible Python version.

WARNING: mysqlauditgrep failed to read options. This utility will not be shown in 'help utilities' and cannot be accessed from the console.
ERROR: The mysqlauditgrep utility requires Python version 2.7.0 or higher and lower than 3.0.0. The version of Python detected was 2.6.6. You may need to install or redirect the execution of this utility to an environment that includes a compatible Python version.


Welcome to the MySQL Utilities Client (mysqluc) version 1.3.2
Copyright (c) 2000, 2013, 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.

Type 'help' for a list of commands or press TAB twice for list of utilities.

mysqluc>

(;´д`) Python古い言われた。
sudo yum update pythonしても2.6.6のままだったのでまあいいやAudit Pluginからみのやつだけぽいし。

mysqluc> help
Command Description
---------------------- ---------------------------------------------------
help utilities Display list of all utilities supported.
help <utility> Display help for a specific utility.
help | help commands Show this list.
exit | quit Exit the console.
set <variable>=<value> Store a variable for recall in commands.
show options Display list of options specified by the user on
launch.
show variables Display list of variables.
<ENTER> Press ENTER to execute command.
<ESCAPE> Press ESCAPE to clear the command entry.
<DOWN> Press DOWN to retrieve the previous command.
<UP> Press UP to retrieve the next command in history.
<TAB> Press TAB for type completion of utility, option,
or variable names.
<TAB><TAB> Press TAB twice for list of matching type
completion (context sensitive).
mysqluc> help utilities
Utility Description
---------------- ---------------------------------------------------------
mysqldbcompare compare databases for consistency
mysqldbcopy copy databases from one server to another
mysqldbexport export metadata and data from databases
mysqldbimport import metadata and data from files
mysqldiff compare object definitions among objects where the
difference is how db1.obj1 differs from db2.obj2
mysqldiskusage show disk usage for databases
mysqlfailover automatic replication health monitoring and failover
mysqlfrm show CREATE TABLE from .frm files
mysqlindexcheck check for duplicate or redundant indexes
mysqlmetagrep search metadata
mysqlprocgrep search process information
mysqlreplicate establish replication with a master
mysqlrpladmin administration utility for MySQL replication
mysqlrplcheck check replication
mysqlrplshow show slaves attached to a master
mysqlserverclone start another instance of a running server
mysqlserverinfo show server information
mysqluserclone clone a MySQL user account to one or more new users

mysqluc> help mysqluserclone
Usage: mysqluserclone --source=user:pass@host:port:socket --destination=user:pass@host:port:socket joe@localhost sam:secret1@localhost

mysqluserclone - clone a MySQL user account to one or more new users

Options:
Option Description
--------------------------- ----------------------------------------------
--version show program's version number and exit
--help display a help message and exit
--source=SOURCE connection information for source server in
the form:
<user>[:<password>]@<host>[:<port>][:<socket>]
or <login-path>[:<port>][:<socket>].
--destination=DESTINATION connection information for destination server
in the form:
<user>[:<password>]@<host>[:<port>][:<socket>]
or <login-path>[:<port>][:<socket>].
-d, --dump dump GRANT statements for user - does not
require a destination
--force drop the new user if it exists
--include-global-privileges include privileges that match base_user@% as
well as base_user@host
--list list all users on the source - does not
require a destination
-f, --format=FORMAT display the list of users in either grid
(default), tab, csv, or vertical format -
valid only for --list option
-v, --verbose control how much information is displayed.
e.g., -v = verbose, -vv = more verbose, -vvv =
debug
-q, --quiet turn off all messages for quiet execution.

mysqluc>

このあたりはドキュメントに書いてあることやmysqluserclone --helpと一緒ね。
mysqluc立ち上げた時のバナーに書いてある通り、TABで補完が利く。

mysqluc> mysqluserclone<TAB><TAB>

Option Description
--------------------------- ----------------------------------------------
--version show program's version number and exit
--help display a help message and exit
--source=SOURCE connection information for source server in
the form:
<user>[:<password>]@<host>[:<port>][:<socket>]
or <login-path>[:<port>][:<socket>].
--destination=DESTINATION connection information for destination server
in the form:
<user>[:<password>]@<host>[:<port>][:<socket>]
or <login-path>[:<port>][:<socket>].
-d, --dump dump GRANT statements for user - does not
require a destination
--force drop the new user if it exists
--include-global-privileges include privileges that match base_user@% as
well as base_user@host
--list list all users on the source - does not
require a destination
-f, --format=FORMAT display the list of users in either grid
(default), tab, csv, or vertical format -
valid only for --list option
-v, --verbose control how much information is displayed.
e.g., -v = verbose, -vv = more verbose, -vvv =
debug
-q, --quiet turn off all messages for quiet execution.

mysqluc> mysqluserclone --s<TAB><TAB>

Option Description
--------------- ----------------------------------------------------------
--source=SOURCE connection information for source server in the form:
<user>[:<password>]@<host>[:<port>][:<socket>] or <login-
path>[:<port>][:<socket>].

オプションも補完が利く&ついでにそのオプションのhelpも出してくれた。ちょっとCISCOぽい?
しかしこのmysqluc自体が誰得な感じがしないでもない…。


当初の目的のmysqlusercloneにたどり着いてないけどとりあえずここまで。
しかし、どうにもmysqltuner的な気配がするよねこいつら。。(mysqldiskusageとかmysqlserverinfoとかmysqlprocgrepとか)


【2013/07/02 13:17】
mysqluserclone試してみた。すごくフツー。
http://yoku0825.blogspot.jp/2013/07/mysql-utilitiesmysqluserclone.html

MySQL 5.6のCHANGE MASTER TOで出るようになったワーニング

$
0
0
MySQL 5.5までは何も出なかったけど、MySQL 5.6で追加されたワーニング。

mysql56> CHANGE MASTER TO MASTER_HOST= 'localhost', MASTER_PORT= 64055, MASTER_USER= 'replicatior', MASTER_PASSWORD= 'xxxx', MASTER_LOG_FILE= 'bin.000001', MASTER_LOG_POS= 1;
Query OK, 0 rows affected, 2 warnings (0.06 sec)

mysql56> SHOW WARNINGS;
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                                        |
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1759 | Sending passwords in plain text without SSL/TLS is extremely insecure.                                                                                                                                         |
| Note  | 1760 | Storing MySQL user name or password information in the master.info repository is not secure and is therefore not recommended. Please see the MySQL Manual for more about this issue and possible alternatives. |
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

shell> cat data/master.info
23
bin.000001
4
localhost
replicatior
xxxx
64055
60
0





0
1800.000

0

86400


0

1759は読んだそのまま、パスワードがSSL使わずにマスターに送信されてるぞ、というNote。

1760は、CHANGE MASTER TOでUSER_NAMEとUSER_PASSWORDを指定するとmaster.info(master_info_repository= TABLEならmysql.slave_master_info)に平文で格納されるから危ういぞ、というNote。

どうすればこれが出なくなるかというと、START SLAVEで指定するようにする。

//
mysql56> CHANGE MASTER TO MASTER_HOST= 'localhost', MASTER_PORT= 64055, MASTER_LOG_FILE= 'bin.000001', MASTER_LOG_POS= 1;
Query OK, 0 rows affected (0.04 sec)

mysql56> START SLAVE USER= 'replicator' PASSWORD= 'xxxx'; --コンマ要らなかったり、MASTER_USERじゃなかったり。
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql56> SHOW WARNINGS;
+-------+------+------------------------------------------------------------------------+
| Level | Code | Message |
+-------+------+------------------------------------------------------------------------+
| Note | 1759 | Sending passwords in plain text without SSL/TLS is extremely insecure. |
+-------+------+------------------------------------------------------------------------+
1 row in set (0.00 sec)

shell> cat data/master.info
23
bin.000001
4
localhost


64055
60
0





0
1800.000

0

86400


0

当然、master.infoにUSERとPASSWORDを保存しなくなるので、mysqldを再起動すると

2013-07-01 19:39:46 16508 [ERROR] Slave I/O: Fatal error: Invalid (empty) username when attempting to connect to the master server. Connection attempt terminated. Error_code: 1593
2013-07-01 19:39:46 16508 [Note] Slave I/O thread killed while connecting to master
2013-07-01 19:39:46 16508 [Note] Slave I/O thread exiting, read up to log 'bin.000001', position 4

こうなる。

まあ、好き好きかな。。


【2013/07/01 19:49】
マニュアルへのリンク忘れてた。。
http://dev.mysql.com/doc/refman/5.6/en/start-slave.html

【2013/07/02 10:19】
このNoteわかりにくいから変えようぜ、というBugsはこちら。
http://bugs.mysql.com/bug.php?id=68602

MySQL Utilitiesのmysqlusercloneを試す

$
0
0
先日rpmで突っ込んだMySQL Utilitiesのmysqlusercloneを試してみる。

http://dev.mysql.com/doc/workbench/en/mysqluserclone.html

やってくれることは、既存のユーザー情報をコピーして新しいユーザーを作ってくれる。
CREATE USER .. LIKE ..(こんな構文ないけど、ニュアンスで感じて下さい)みたいな感じ。

取り敢えず、--sourceでユーザーのコピー元MySQLに`ログインするためのDSN'、--destinationでユーザーのコピー先MySQLに`ログインするためのDSN'を指定する。

ドキュメントには特に書いてないけど、--sourceの暗黙のデフォルトはroot@localhost:3306、--destinationを省略すると--sourceと同じコネクションの中でGRANTを叩く。

my.cnfの[client]セクションは読んでる。他のところはよく判らない。

基本的な動作。

$ mysqluserclone --source root@localhost:/usr/mysql/5.6.12/data/mysql.sock tpcc@% tpcc2@localhost
# Source on localhost: ... connected.
# Cloning 1 users...
# Cloning tpcc@% to user tpcc2@localhost
# ...done.

/usr/mysql/5.6.12/data/mysql.sockを使ってroot@localhostでログインして、tpcc@%というユーザーの情報をコピーして、tpcc2@localhostというユーザーを作る。
ジェネラルログはこんな感じ。

$ less general.log
130702 13:00:30    17 Connect   root@localhost on
                   17 Query     SET NAMES 'latin1' COLLATE 'latin1_swedish_ci'
                   17 Query     SET @@session.autocommit = OFF
                   17 Query     SHOW VARIABLES LIKE 'READ_ONLY'
                   17 Query     COMMIT
                   17 Query     SHOW VARIABLES LIKE 'VERSION'
                   17 Query     COMMIT
                   17 Query     SELECT * FROM mysql.user WHERE user = 'tpcc' and host = '%'
                   17 Query     COMMIT
                   17 Query     SELECT * FROM mysql.user WHERE user = 'tpcc2' and host = 'localhost'
                   17 Query     COMMIT
                   17 Query     SELECT * FROM mysql.user WHERE user = 'tpcc2' and host = 'localhost'
                   17 Query     COMMIT
                   17 Query     SELECT CURRENT_USER()
                   17 Query     COMMIT
                   17 Query     SHOW GRANTS FOR 'tpcc'@'%'
                   17 Query     COMMIT
                   17 Query     SELECT * FROM mysql.user WHERE user = 'tpcc2' and host = 'localhost'
                   17 Query     COMMIT
                   17 Query     CREATE USER 'tpcc2'@'localhost'
                   17 Query     GRANT USAGE ON *.* TO 'tpcc2'@'localhost'
                   17 Query     SELECT * FROM mysql.user WHERE user = 'tpcc2' and host = 'localhost'
                   17 Query     COMMIT
                   17 Query     GRANT ALL PRIVILEGES ON `tpcc`.* TO 'tpcc2'@'localhost'

ユーザー情報。

mysql> SHOW GRANTS FOR tpcc@'%';
+-----------------------------------------------------------------------------------------------------+
| Grants for tpcc@%                                                                                   |
+-----------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'tpcc'@'%' IDENTIFIED BY PASSWORD '*94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29' |
| GRANT ALL PRIVILEGES ON `tpcc`.* TO 'tpcc'@'%'                                                      |
+-----------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

mysql> SHOW GRANTS FOR tpcc2@localhost;
+---------------------------------------------------------+
| Grants for tpcc2@localhost                              |
+---------------------------------------------------------+
| GRANT USAGE ON *.* TO 'tpcc2'@'localhost'               |
| GRANT ALL PRIVILEGES ON `tpcc`.* TO 'tpcc2'@'localhost' |
+---------------------------------------------------------+
2 rows in set (0.00 sec)

おっとっと。。パスワードは指定しないとコピーしてくれないのね。
黙って同じものにしてくれて良いのに(´・ω・`)


$ mysqluserclone --source root@127.0.0.1:3306 tpcc@% tpcc3:<password>@'127.0.0.1'
# Source on 127.0.0.1: ... connected.
# Cloning 1 users...
# Cloning tpcc@% to user tpcc3:test@127.0.0.1
# ...done.

$ less general.log
130702 13:05:16    21 Connect   root@localhost on
                   21 Query     SET NAMES 'latin1' COLLATE 'latin1_swedish_ci'
                   21 Query     SET @@session.autocommit = OFF
                   21 Query     SHOW VARIABLES LIKE 'READ_ONLY'
                   21 Query     COMMIT
                   21 Query     SHOW VARIABLES LIKE 'VERSION'
                   21 Query     COMMIT
                   21 Query     SELECT * FROM mysql.user WHERE user = 'tpcc' and host = '%'
                   21 Query     COMMIT
                   21 Query     SELECT * FROM mysql.user WHERE user = 'tpcc3' and host = '127.0.0.1'
                   21 Query     COMMIT
                   21 Query     SELECT * FROM mysql.user WHERE user = 'tpcc3' and host = '127.0.0.1'
                   21 Query     COMMIT
                   21 Query     SELECT CURRENT_USER()
                   21 Query     COMMIT
                   21 Query     SHOW GRANTS FOR 'tpcc'@'%'
                   21 Query     COMMIT
                   21 Query     SELECT * FROM mysql.user WHERE user = 'tpcc3' and host = '127.0.0.1'
                   21 Query     COMMIT
                   21 Query     CREATE USER 'tpcc3'@'127.0.0.1' IDENTIFIED BY PASSWORD '*94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29'
                   21 Query     GRANT USAGE ON *.* TO 'tpcc3'@'127.0.0.1'
                   21 Query     SELECT * FROM mysql.user WHERE user = 'tpcc3' and host = '127.0.0.1'
                   21 Query     COMMIT
                   21 Query     GRANT ALL PRIVILEGES ON `tpcc`.* TO 'tpcc3'@'127.0.0.1'

mysql> SHOW GRANTS FOR tpcc3@127.0.0.1;
+--------------------------------------------------------------------------------------------------------------+
| Grants for tpcc3@127.0.0.1 |
+--------------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'tpcc3'@'127.0.0.1' IDENTIFIED BY PASSWORD '*94BDCEBE19083CE2A1F959FD02F964C7AF4CFC29' |
| GRANT ALL PRIVILEGES ON `tpcc`.* TO 'tpcc3'@'127.0.0.1' |
+--------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

どうせもとのパスワードが分からなくてもIDENTIFIED BY PASSWORD '*..'で同じパスワードはコピーできるんだから、クローン元ユーザーと同じパスワードを設定するようなオプションが欲しいなぁ。
取り敢えずこれを使って、スキーマ名のtypoでサービスを止めかけるという惨事は二度と起こさないで済むようにしたい。。orz

ちなみに量産もできるぽい。

$ mysqluserclone --source root@127.0.0.1:3306 tpcc@% tpcc10@'127.0.0.1' tpcc11@'127.0.1.1' tpcc12@'127.0.2.1'
# Source on 127.0.0.1: ... connected.
# Cloning 3 users...
# Cloning tpcc@% to user tpcc10@127.0.0.1
# Cloning tpcc@% to user tpcc11@127.0.1.1
# Cloning tpcc@% to user tpcc12@127.0.2.1
# ...done.

ますますパスワードのコピーが欲しい。。

好きなスクリプト叩いて情報を持ってくるinformation_schemaプラグイン作った

$
0
0
別にスクリプトじゃなくて何でも動くけど。。

https://github.com/yoku0825/scripting_i_s

scripting_i_s.ccの中のI_S_SCRIPTのマクロを任意の実行ファイルに変えてやれば、そいつを実行した出力を空白セパレートでinformation_schema.scripting_i_sテーブルから参照できるようになっていたり。MySQL 5.5.32では動作確認済み。

取り敢えずこんな感じでいく。

$ cat /tmp/test.pl
#!/bin/bash
/bin/awk '{print $1, $2}' /proc/`pidof mysqld`/io >&2

mysql55> INSTALL PLUGIN scripting_i_s SONAME 'scripting_i_s.so';
Query OK, 0 rows affected (0.01 sec)

mysql55> SELECT * FROM information_schema.scripting_i_s;
+------------------------+---------+
| name                   | value   |
+------------------------+---------+
| rchar:                 | 9806796 |
| wchar:                 | 136035  |
| syscr:                 | 5898    |
| syscw:                 | 429     |
| read_bytes:            | 24576   |
| write_bytes:           | 311296  |
| cancelled_write_bytes: | 233472  |
+------------------------+---------+
7 rows in set (0.02 sec)

test.plの中身がPerlじゃないのは気にしない。

取り敢えずSuper_privが必要なようにはしてあるけど、mysqldの実行ユーザーで叩けるスクリプトは何でも叩くダメ仕様。md5をマクロでハードコードしておいて、実行都度md5判定させようとしたけれど、C力の低さで失敗し続けたので諦めた。

もうちょこちょこいじりたいなー。


【2013/07/10 15:36】
スクリプトから戻ってくる結果が1行64KiBを超えると多分セグフォる(キリ

TokuDBをCentOS 6.3(以降?)で動かしたい方へ

$
0
0
エラーログにこんなんが出て、どうもPluginのInitに失敗していた。

130710 10:24:52 Percona XtraDB (http://www.percona.com) 5.5.30-tokudb-7.0.1-29.3 started; log sequence number 1597945
Transparent huge pages are enabled, according to /sys/kernel/mm/redhat_transparent_hugepage/enabled
130710 10:24:52 [ERROR] Plugin 'TokuDB' init function returned error.
130710 10:24:52 [ERROR] Plugin 'TokuDB' registration as a STORAGE ENGINE failed.
130710 10:24:52 [Warning] /usr/percona/5.5.30_tokudb/bin/mysqld: unknown variable 'loose-innodb-buffer-pool-dump-at-shutdown=1
'
130710 10:24:52 [Warning] /usr/percona/5.5.30_tokudb/bin/mysqld: unknown variable 'loose-innodb-buffer-pool-load-at-startup=1'
130710 10:24:52 [ERROR] Unknown/unsupported storage engine: TokuDB
130710 10:24:52 [ERROR] Aborting

取り敢えず、

# echo never > /sys/kernel/mm/redhat_transparent_hugepage/enabled

で起動するようになった。

https://groups.google.com/forum/#!topic/tokudb-user/d3CujW353_4


transparent hugepageが何であるかは↓を読んでなんとなく心で感じることにした。

http://blog.goo.ne.jp/u1low_cheap/e/72a7c5528858debe4e34df83430c480e


取り敢えず同じところでハマった誰かに届け!

mysqlコマンドラインクライアントの改変と社内LT

$
0
0
社内LT用にmysqlコマンドラインクライアントをネタ改変したものの、たぶん他所でやることもないと思うのでこっちに書いてみる。



やってることはシンプルに単なるネタ。
書き上げたパッチをMySQL 5.6.12に適用してやると、mysqlコマンドラインクライアントに"さん"をつけないと怒る様にできます。

ここから
$ cd mysql-5.6.12

$ wget https://gist.github.com/yoku0825/5932320/raw/d715a496707357a220e5ebde34866cc2af656686/decosuke.patch

$ patch -p0 < decosuke.patch
patching file client/mysql.cc

$ cmake .
..

$ make mysql
..
Scanning dependencies of target mysql
[100%] Building CXX object client/CMakeFiles/mysql.dir/mysql.cc.o
Linking CXX executable mysql
[100%] Built target mysql

使い方。
"さん"をつけずにログインすると(mysqldは何でも良い)「さんをつけろよデコ助野郎!」と言われます。
exitくらいは通すようにしとくべきでしたが、exitですら言われます。

mv, cp, ln(ハードリンクでもシンボリックリンクでも)で"さん"をつけて、実行ファイル名を"mysql-san"にするとまともに動きます。

ただし、"さん"を間違って"mysql-sun"にするとやっぱり怒られます。


$ client/mysql -uroot -p -S /usr/mysql/5.6.12/data/mysql.sock
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 46
Server version: 5.6.12-log Source distribution

Copyright (c) 2000, 2013, 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.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> status
_人人人人人人人人人人人人人人人_
> さんをつけろよデコ助野郎! <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄
mysql>
mysql> ^DBye

$ cp -ip client/mysql client/mysql-sun

$ client/mysql-sun -uroot -p -S /usr/mysql/5.6.12/data/mysql.sock
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 47
Server version: 5.6.12-log Source distribution

Copyright (c) 2000, 2013, 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.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> status
_人人人人人人人人人人人人人人人人人人_
> 黙れ小僧! お前にSunを救えるか! <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄
mysql> ^DBye

$ cp -ip client/mysql client/mysql-san

$ client/mysql-san -uroot -p -S /usr/mysql/5.6.12/data/mysql.sock
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 48
Server version: 5.6.12-log Source distribution

Copyright (c) 2000, 2013, 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.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> status
--------------
client/mysql-san Ver 14.14 Distrib 5.6.12, for Linux (x86_64) using EditLine wrapper

Connection id: 48
Current database:
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.6.12-log Source distribution
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: utf8
Db characterset: utf8
Client characterset: utf8
Conn. characterset: utf8
UNIX socket: /usr/mysql/5.6.12/data/mysql.sock
Uptime: 3 days 5 hours 27 min 13 sec

Threads: 1 Questions: 599170 Slow queries: 0 Opens: 121 Flush tables: 1 Open tables: 72 Queries per second avg: 2.148
--------------

楽しんでください。

MySQL Proxyで認証をフックしようと悪戦苦闘(成功してない)

$
0
0
色々あって、MySQL ProxyでMySQLの認証パケットを書き換えたい。
具体的にはこんな感じ。

  • ユーザー名に"+"が含まれていた場合、"+"とそれ以降の文字列を握りつぶす。
    • mysql -uroot+yoku0825 -p だったら、rootに変換してやる。
  • パスワードやその他のオプションは入力されたものを素通し。
  • クライアントはmysqlコマンドラインクライアントとは限らない。

で、まあ取り敢えずソースコードに付属していたExampleのLuaスクリプトを覗いてみる。

https://github.com/cwarden/mysql-proxy/blob/master/examples/tutorial-scramble.lua

Lua読めないけど感じ的に、「user: replace, password: me」で認証パケットを投げると、「user: root, password: secret」に書き換えてバックエンドに投げてくれるような気配がする。
良いじゃない、素敵。

サンプルスクリプトだと書き換える先はテーブルで持ってるけど、これをユーザー名は正規表現で抽出してやって、パスワードは書き換えない方針にすればきっといける。


…と思ったのが1週間前、で、今まだ出来てない(´・ω・`)

$ /usr/mysql/proxy/bin/mysql-proxy --proxy-address=127.0.0.56:3306 --proxy-backend-addresses=127.0.0.1:64056 --proxy-lua-script=/usr/local/src/mysql-proxy-0.8.3/examples/tutorial-scramble.lua --log-level=debug
2013-07-24 18:38:24: (critical) plugin proxy 0.8.3 started
2013-07-24 18:38:24: (debug) max open file-descriptors = 8192
2013-07-24 18:38:24: (message) proxy listening on port 127.0.0.56:3306
2013-07-24 18:38:24: (message) added read/write backend: 127.0.0.1:64055

起動は問題なく。

$ mysql -h 127.0.0.56 -P 3306 -utpcc -ptest
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 214
Server version: 5.6.12-log Source distribution

Copyright (c) 2000, 2013, 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.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

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

実在するユーザーで認証をかけるのも問題なし。
でも。

$ mysql -h 127.0.0.56 -P 3306 -ureplace -pme
Warning: Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'replace'@'localhost' (using password: YES)

え、ユーザー名すりかえられてない。。

for challenge "l-7mA=KCL7j3]Z,l^q>!\000" the client sent ",wョ。ア3礼P|ェ\
&濘\\m"
2013-07-24 18:45:20: (critical) network_mysqld_proto_password_check: assertion `20 == challenge_len' failed
2013-07-24 18:45:20: (debug) [network-mysqld.c:1134]: error on a connection (fd: -1 event: 0). closing client connection.

しかも認証パケットの長さがおかしいとか言われてる。。
バックエンドが5.6だからかなぁと思って5.5につないでみても同じ。
5.1, 5.0だとエラーメッセージがチャレンジコードの長さ云々じゃなくて.server_capabilities has to be setというのに変わるので云々。。

先は長そうだ。

Wiresharkのプロトコルデコード機能を使ってMySQLのパケットを覗く

$
0
0
port 3306なら余計なことをしなくてもWiresharkが勝手にMySQLプロトコルとしてデコードしてくれるんだけど、残念ながら3306以外の場合は手動で設定してやらんといかん。

取り敢えずキャプチャー。
MySQLが浮いてるのはLinuxで、俺が使ってるのはWindows。

# tcpdump -i any -w /tmp/mysql55.cap port 64055
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
^C21 packets captured
42 packets received by filter
0 packets dropped by kernel

64055番ポートにMySQL 5.5.32が浮いているのでそれをキャプチャーしてみた。

$ mysql55 --protocol=tcp
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.5.32-log Source distribution

Copyright (c) 2000, 2013, 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.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql55>
mysql55>
mysql55>
mysql55> SELECT 'さんをつけろよデコ助野郎!';
+-----------------------------------------+
| さんをつけろよデコ助野郎!              |
+-----------------------------------------+
| さんをつけろよデコ助野郎!              |
+-----------------------------------------+
1 row in set (0.00 sec)

mysql55>
mysql55>
mysql55>
mysql55> exit
Bye

最近知ったんだけど、--protocol=tcp ってすると、わざわざ--host=127.0.0.1ってやらなくてもTCP/IP使うようになる(今更

で、まあ/tmp/mysql55.capを手元に持ってきてWiresharkに食わせる。




デコードされてないのでヘッダ以外は16進でしか表示されていないので、読みにくいことこの上ない。
ので、



テキトーなパケットを右クリックして"Decode As"を選択。




TransportタブでDecodeをMySQLにしてOK押下。




よし素敵。
画像びみょー。。

MySQL Proxyで認証をフックしようと悪戦苦闘(ユーザー名だけ書き換えはOK)

$
0
0
前回 の続き。
要件はこんな感じ。

  • ユーザー名に"+"が含まれていた場合、"+"とそれ以降の文字列を握りつぶす。
    • mysql -uroot+yoku0825 -p だったら、rootに変換してやる。
  • パスワードやその他のオプションは入力されたものを素通し。
  • クライアントはmysqlコマンドラインクライアントとは限らない。

取り敢えず判ったところまででは、
  • MySQL Proxy 0.8.3以降はto_response_packetにserver_capabilitiesの指定が必須になったっぽい。
  • server_capabilitiesに使える値の一覧はinclude/mysql_com.hに書いてある。
  • 取り敢えず ここを参考にCLIENT_PROTOCOL_41(=512)とCLIENT_SECURE_CONNECTION(=32768)を設定したら、ユーザー名の握りつぶしは成功した。
$ cat ./proxy.lua
local password= assert(require("mysql.password"))
local proto= assert(require("mysql.proto"))

function read_auth()
local c = proxy.connection.client
local s = proxy.connection.server

local proxy_user= c.username
local mysql_user= string.match(c.username, "^(%w+)+")
if not mysql_user then mysql_user= proxy_user end

proxy.queries:append(1, proto.to_response_packet(
{
server_capabilities= 33280,
username= mysql_user,
response= c.scrambled_password
}))

return proxy.PROXY_SEND_QUERY
end

$ /usr/mysql/proxy/bin/mysql-proxy --proxy-address=127.0.0.55:3306 --proxy-backend-addresses=127.0.0.1:64055 --proxy-lua-script=/usr/mysql/proxy/proxy.lua --log-level=debug

$ mysql -h 127.0.0.55 -P 3306 -u root+yoku0825 -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 15
Server version: 5.5.32-log Source distribution

Copyright (c) 2000, 2013, 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.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> status
--------------
mysql Ver 14.14 Distrib 5.6.12, for Linux (x86_64) using EditLine wrapper

Connection id: 15
Current database:
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.5.32-log Source distribution
Protocol version: 10
Connection: 127.0.0.55 via TCP/IP
Server characterset: utf8
Db characterset: utf8
Client characterset: utf8
Conn. characterset: utf8
TCP port: 3306
Uptime: 2 days 19 hours 27 min 2 sec

Threads: 3 Questions: 77 Slow queries: 2 Opens: 36 Flush tables: 1 Open tables: 29 Queries per second avg: 0.000
--------------

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

よしよしよしよし。
しかしまあ、相変わらずパスワードとかいじろうとすると(to_response_packetでresponseを書き換えると)assertion `20 == challenge_len' failedになっちゃうんだよなぁ。。
そこはまた追って調べるとして、取り敢えずこれで他に情報をログする部分を書きましょうそうしましょう。
Viewing all 581 articles
Browse latest View live