2013年8月30日金曜日

mysqladmin.ccのコードリーディングのさわり

みんなmysqladminが大好きっぽいのでおいておきますね。

まずはソースコード取ってきて解凍します。全部解凍するの面倒なので、mysqladmin.ccだけ取り出しますかね。

$ wget http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.13.tar.gz/from/http://cdn.mysql.com/
$ tar xzf mysql-5.6.13.tar.gz mysql-5.6.13/client/mysqladmin.cc
$ vim mysql-5.6.13/client/mysqladmin.cc

はい。
頭の方から、GPLv2のライセンス表記(1~16), 各種変数の定義(35~68)くらい眺めておくと良いかも知れません。72~92に関数の定義があるのは、MySQL同梱のクライアントは個別にヘッダーファイルが作られていないからです。
98行目からcommandsとcommand_namesが定義されていて、command_namesが引数から受け取るコマンド、commandsがそれを内部で参照するときのマップです。まあ名前見れば何にマップされてるか判りますね。

124行目からのmy_long_optionsが受け取れるオプションを入れた構造体です。自分でオプション作る時にはここにも追加します。my_option構造体のプロトタイプはinclude/my_getopt.hに入っていますので、パラメータがよく判らない時は見ますが、似ている引数のやつをコピペしてテキトーに直せば動きます。

1つ飛ばして312行目からがmain関数です。322行目~343行目あたりでオプションを解釈してopt_*変数に突っ込み、350行目からmysql_option関数を使ってMySQLへのコネクション構造体(mysql)にオプションとして設定していきます。397行目までそんな感じです。

399行目、sql_connectでついにMySQLに接続しに行きます。400~422行目はMySQLへの接続に失敗した時の処理で、渡されたコマンドがpingだけなら接続エラーであっても0を返すような処理(エラーコードが返ってくる= mysqldは生きている、だから)が入ってます。

434行目からが接続に成功した時の処理で、先日の-iオプションとかついてる時はここをループします。438行目のexecute_commandsが実際に接続してゴニョゴニョしているところです。execute_commands関数は623行目から定義されています。

あとは丁寧に見ていけばいけると思います。
SQLにマッピングされているコマンドはsprintfでbuffにSQLを突っ込んでmysql_queryでクエリーとして投げる、マッピングされてないpingとかshutdownに関しては、libmysql/libmysql.cに定義された関数を呼んで処理しています。

これでみんなmysqladminのforkが作れますね!
Have fun!!

2013年8月29日木曜日

mysqladminの小ネタ

mysqladminなんて基本的にshutdownの時しか使わないんですが、まあ色々SQLでやる時とのマッピングとか。

取り敢えず5.6.13ベースです。
⇒ http://dev.mysql.com/doc/refman/5.6/en/mysqladmin.html

  • mysqladmin create ⇒ CREATE DATABASEに同じ。
  • mysqladmin debug ⇒ SQLではできない。エラーログにデバッグ情報を出力する。
  • mysqladmin drop ⇒ DROP DATABASEに同じ。
  • mysqladmin extended-status ⇒ SHOW GLOBAL STATUSに同じ。
  • mysqladmin flush-hosts ⇒ FLUSH HOSTSに同じ。
  • mysqladmin flush-logs ⇒ FLUSH LOGSに同じ。ログ種別は設定できない。
  • mysqladmin flush-privileges ⇒ FLUSH PRIVILEGESに同じ。
  • mysqladmin flush-status ⇒ FLUSH STATUSに同じ。ただ、FLUSH STATUSって
    セッションスコープのステータス変数はクリアしてくれるけど
    グローバルスコープの扱いが微妙なので、
    使いどころがどれだけあるのかすごく謎。
  • mysqladmin flush-tables ⇒ FLUSH TABLESに同じ。
  • mysqladmin kill ⇒ KILLに同じ。
  • mysqladmin old-password ⇒ SET SESSION old_passwords= 1;
    SET PASSWORD= PASSOWRD('..');
    SET SESSION old_passwords= 0; にほぼ同じ。
  • mysqladmin password ⇒ SET PASSWORD= PASSWORD('..'); に同じ。
    こっちはold_passwordsの設定値に従う。
  • mysqladmin ping ⇒ SQLではできない。COM_PINGを投げて成功するか、
    認証に失敗すると0が返る。
    (認証に失敗しても、接続を拒否られたということは
    mysqldが生きているということ)
  • mysqladmin processlist ⇒ SHOW PROCESSLISTに同じ。
  • mysqladmin --verbose processlist ⇒ SHOW FULL PROCESSLISTに同じ。
  • mysqladmin reload ⇒ FLUSH PRIVILEGESに同じ。
    つまりmysqladmin flush-privilegesに同じ。
  • mysqladmin reflesh ⇒ FLUSH TABLES; FLUSH LOGS; に同じ。
  • mysqladmin shutdown ⇒ 対応するSQLなし。mysqldのシャットダウン。
  • mysqladmin start-slave ⇒ START SLAVEに同じ。
  • mysqladmin status ⇒ STATUSの結果を簡単にしたような感じ。
  • mysqladmin stop-slave ⇒ STOP SLAVEに同じ。
  • mysqladmin variables ⇒ SHOW GLOBAL VARIABLESに同じ。
  • mysqladmin version ⇒ STATUSの結果を簡単にしたような感じ。


ちなみにコマンドは複数指定可能なので、

$ mysqladmin -uroot -pxxx stop-slave create d2 start-slave flush-status

とかやると、

mysql> STOP SLAVE;
mysql> CREATE DATABASE d2;
mysql> START SLAVE;
mysql> FLUSH STATUS;

相当の動作になる。


あと目新しげな使い方としては(いや昔からあるけどこのオプション)、

$ mysqladmin -uroot -pxxx -r -i 10 extended-status

とやると、10秒ごとに(-i 10)前回との差分を(-r)表示してくれる。
-iはどのコマンドでも使えるけど、-rはextended-status専用。それ以外のコマンドにつけても単純に無視される。

$ mysqladmin -uroot -pxxx -i 5 flush-logs

とかやれば5秒おきにFLUSH LOGSできるよ!(しないよ)

2013年8月27日火曜日

MySQL Clusterのmod_ndbが色々残念

本家のNDBCLUSTER関連のセミナー行ったりすると、

 Apacheのmod_ndbで直接NDB APIが叩けるんですよ!

とかよく言われるので試してみたメモ。


NDB memcached Engine の時と違ってNDBCLUSTER本体には同梱されていないので、Google Codeからダウンロード。
⇒ https://code.google.com/p/mod-ndb/downloads/list

最新版のアップロードが2009/11な時点でちょっと危なげな気配がする。


取り敢えずhttpd-develを突っ込んでconfigure。

$ ./configure --mysql=/usr/ndb/7.3.1/bin/mysql_config
Server version: Apache/2.4.6 (Unix)
Server built:   Jul 24 2013 11:06:47
Using Apache 2.0
/usr/bin/apu-1-config

Configuring with
    mysql_config =  /usr/ndb/7.3.1/bin/mysql_config
    apxs         =  /usr/sbin/apxs
    apr-config   =  /usr/bin/apr-1-config
    apu-config   =  /usr/bin/apu-1-config

Linking with -lmysys and -lmystrings

Created Makefile.

Removing out-of-date files.

Hello!

   make            : build mod_ndb
   make install    : install mod_ndb.so
   make configtest : test configuration
   make start      : start a test server on port 3080 (see test.conf)
   make stop       : stop the test server
   make restart    : restart the test server

Thanks for trying mod_ndb!


configureで指定必須なのは--apxs=/path/to/apxsと--mysql=/path/to/mysql_configだけど、パスが通ってれば勝手に拾ってきてくれる。
テストサーバーなんて同梱されてるんだ。すてき。

$ make
g++ -c  -I/usr/include/httpd -I/usr/include/apr-1 -I/usr/ndb/7.3.1/include -I/usr/ndb/7.3.1/include/storage/ndb -I/usr/ndb/7.3.1/include/storage/ndb/ndbapi -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -fPIC -Wall -O3 -o mod_ndb.o mod_ndb_ap20.cc
mod_ndb_ap20.cc: In function ‘int mod_ndb_post_config(apr_pool_t*, apr_pool_t*, apr_pool_t*, server_rec*)’:
mod_ndb_ap20.cc:53: error: ‘aplog_module_index’ was not declared in this scope
mod_ndb_ap20.cc:60: error: ‘aplog_module_index’ was not declared in this scope
mod_ndb_ap20.cc: In function ‘void mod_ndb_child_init(ap_pool*, server_rec*)’:
mod_ndb_ap20.cc:110: error: ‘aplog_module_index’ was not declared in this scope
mod_ndb_ap20.cc:118: error: ‘aplog_module_index’ was not declared in this scope
mod_ndb_ap20.cc: In function ‘apr_status_t mod_ndb_child_exit(void*)’:
mod_ndb_ap20.cc:156: error: ‘aplog_module_index’ was not declared in this scope
mod_ndb_ap20.cc: In function ‘void connect_to_cluster(ndb_connection*, server_rec*, config::srv*, ap_pool*, bool)’:
mod_ndb_ap20.cc:190: error: ‘aplog_module_index’ was not declared in this scope
mod_ndb_ap20.cc:208: error: ‘aplog_module_index’ was not declared in this scope
mod_ndb_ap20.cc:215: error: ‘aplog_module_index’ was not declared in this scope
mod_ndb_ap20.cc: In function ‘Ndb* init_instance(ndb_connection*, ndb_instance*, server_rec*, config::srv*, ap_pool*)’:
mod_ndb_ap20.cc:239: error: ‘aplog_module_index’ was not declared in this scope
mod_ndb_ap20.cc: In function ‘ndb_instance* my_instance(request_rec*)’:
mod_ndb_ap20.cc:283: error: ‘aplog_module_index’ was not declared in this scope
make: *** [mod_ndb.o] エラー 1

いきなり1個目でこけてるすてきじゃなーいorz

aplog_module_indexというのを調べてみるとなんかよく判らないけれどApache 2.2と2.4の間でAPIの呼び出しが変わったあたりに原因がありそうな感じ。
試しにhttpdを一度消して2.2のhttpd, httpd-develを突っ込む。

$ make
g++ -c  -I/usr/include/httpd -I/usr/include/apr-1 -I/usr/ndb/7.3.1/include -I/usr/ndb/7.3.1/include/storage/ndb -I/usr/ndb/7.3.1/include/storage/ndb/ndbapi -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -fPIC -Wall -O3 -o mod_ndb.o mod_ndb_ap20.cc
g++ -c  -I/usr/include/httpd -I/usr/include/apr-1 -I/usr/ndb/7.3.1/include -I/usr/ndb/7.3.1/include/storage/ndb -I/usr/ndb/7.3.1/include/storage/ndb/ndbapi -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -fPIC -Wall -O3 -o Query.o Query.cc 
g++ -c  -I/usr/include/httpd -I/usr/include/apr-1 -I/usr/ndb/7.3.1/include -I/usr/ndb/7.3.1/include/storage/ndb -I/usr/ndb/7.3.1/include/storage/ndb/ndbapi -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -fPIC -Wall -O3 -o Execute.o Execute.cc 
g++ -c  -I/usr/include/httpd -I/usr/include/apr-1 -I/usr/ndb/7.3.1/include -I/usr/ndb/7.3.1/include/storage/ndb -I/usr/ndb/7.3.1/include/storage/ndb/ndbapi -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -fPIC -Wall -O3 -o MySQL_value.o MySQL_value.cc 
..
LD_RUN_PATH=/usr/ndb/7.3.1/lib g++ -shared -o mod_ndb.so mod_ndb.o Query.o Execute.o MySQL_value.o MySQL_result.o config.o request_body.o handlers.o result_buffer.o output_format.o format_compiler.o format_dumper.o query_source.o  JSON_encoding.o NSQL_Parser.o NSQL_Scanner.o JSON_Parser.o JSON_Scanner.o -lndbclient -lmystrings -L/usr/ndb/7.3.1/lib -lmysqlclient -lpthread -lm -lrt -lssl -lcrypto -ldl -lmysys -lstdc++ -lrt
/usr/bin/ld: cannot find -lmystrings
collect2: ld はステータス 1 で終了しました
make: *** [mod_ndb.so] エラー 1


取り敢えずいきなりダメぽだったところは乗り越えたヾ( ´∀`)ノ
が、今度はlibmystringsが無いって怒られてる。

NDB API関連のドキュメントを見てもLDFLAGSに設定しろと言っていて、ソースからコンパイルしているとはいえオプションは粗方有効にしてるんだけどなあ。。

ググってもよく判らないのでソースコードからlibmystringsを探す。


$ grep -r libmystrings *
sql/share/charsets/README:    (libmystrings), and when should it be placed in a charset_name.xml
( ゚д゚) ・・・ 
  
(つд⊂)ゴシゴシ 
  
(;゚д゚) ・・・ 
  
(つд⊂)ゴシゴシゴシ 
  _, ._ 
(;゚ Д゚) …!? 

READMEしか引っかからない。
それに対してNDBCLUSTER 7.1のソースコードで同じことをやるとごっそり引っかかる。
(と、気付くまで7.3と7.2と7.1のバイナリーを順番に落としてconfigureのオプション変えながら何度もやった)

7.1.26のNDBCLUSTERをmakeして、mod_ndbをconfigureしなおして、もっかいmakeしたら通った。


$ make start
/usr/sbin/httpd -f /home/yoku/mod_ndb-1.1-release-r652/httpd.conf
make: *** [start] エラー 1

$ cat logs/ndb_error_log
[Tue Aug 27 15:43:23 2013] [notice] Cannot connect to NDB Cluster (connectstring: "(null)") 1/5
[Tue Aug 27 15:43:26 2013] [notice] Cannot connect to NDB Cluster (connectstring: "(null)") 2/5
[Tue Aug 27 15:43:29 2013] [notice] Cannot connect to NDB Cluster (connectstring: "(null)") 3/5
[Tue Aug 27 15:43:32 2013] [notice] Cannot connect to NDB Cluster (connectstring: "(null)") 4/5
[Tue Aug 27 15:43:35 2013] [notice] Cannot connect to NDB Cluster (connectstring: "(null)") 5/5
[Tue Aug 27 15:43:35 2013] [notice] Connection test failed.  Cannot connect to NDB Cluster.  Apache will exit.
Configuration Failed

ああ、そういえばndbdもndb_mgmdも上げてないや。。(;´д`)
続きはいつかやるかやらないかする。

MySQLをWindowsサービスとして動かしている時のコマンドラインオプションとか

特にMySQL Installerや.msiで突っ込んだとき。

ファイル名を指定して実行

services.msc

名前= MySQL

  • --installで自分で登録した時はそのサービス名
  • MySQL5.6のInstallerからはMySQL56ってサービス名にしようとする?


プロパティ

実行ファイルのパスに実際に渡されている引数が見える


こんなかんじで。


懐かしい。。

2013年8月20日火曜日

mroongaのインデックスサイズをなんとなく

ウチではかつてはTritonn全盛、今はmroonga全盛な「MySQL de FullTextSearch」が大好きな感じでやっています。Sphinxとか誰か手を出さないかなぁと思いつつ、いい加減MySQL de FTSから足を洗って全文検索ライブラリはMySQLとは連携させないでやろうぜ、というのもあったりします。

そこで取り敢えず現状の洗い出し(?)の一環として、mroongaのストレージサイズをぼんやりと考えてみることにします。
というか運用している分にはこれがキツい。
インデックス用のmrnファイルは(tokenBigramなせいもあって)データサイズに対して線形に増えるので、ストレージ容量と、あとそれをキャッシュするだけのメモリ増設がもうままならない。


実際どれくらい食うのかを取り敢えず測ってみる。

サンプルデータはTwitterのツイート履歴。
ただし全文検索が試したいだけだったり、カラムをもろもろ列挙したりするのがものすごく面倒だったのでテーブル構成はすごく手抜きな感じで。

mysql55> CREATE TABLE myisam.tweet ( tweet_id BIGINT UNSIGNED PRIMARY KEY, timestamp TIMESTAMP NOT NULL DEFAULT 0, text TEXT) Engine = MyISAM;
Query OK, 0 rows affected (0.03 sec)

mysql55> CREATE TABLE mroonga_storage.tweet ( tweet_id BIGINT UNSIGNED PRIMARY KEY, timestamp TIMESTAMP NOT NULL DEFAULT 0, text TEXT) Engine = mroonga;
Query OK, 0 rows affected (0.07 sec)

mysql55> CREATE TABLE mroonga_wrapper.tweet ( tweet_id BIGINT UNSIGNED PRIMARY KEY, timestamp TIMESTAMP NOT NULL DEFAULT 0, text TEXT) Engine = mroonga COMMENT = 'Engine "MyISAM"';
Query OK, 0 rows affected (0.09 sec)

MyISAM、ストレージモード、ラッパーモードでそれぞれ作る。
mroongaはデータベース単位でmrnファイルを作ってしまうのでデータベースも分けておく。

mysql55> SHOW TABLE STATUS FROM myisam\G
*************************** 1. row ***************************
           Name: tweet
         Engine: MyISAM
        Version: 10
     Row_format: Dynamic
           Rows: 0
 Avg_row_length: 0
    Data_length: 0
Max_data_length: 281474976710655
   Index_length: 1024
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2013-08-19 19:39:02
    Update_time: 2013-08-19 19:39:02
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.01 sec)

mysql55> SHOW TABLE STATUS FROM mroonga_storage\G
*************************** 1. row ***************************
           Name: tweet
         Engine: mroonga
        Version: 10
     Row_format: Dynamic
           Rows: 0
 Avg_row_length: 0
    Data_length: 4526080
Max_data_length: 0
   Index_length: 0
      Data_free: 0
 Auto_increment: NULL
    Create_time: NULL
    Update_time: NULL
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.01 sec)

mysql55> SHOW TABLE STATUS FROM mroonga_wrapper\G
*************************** 1. row ***************************
           Name: tweet
         Engine: mroonga
        Version: 10
     Row_format: Dynamic
           Rows: 0
 Avg_row_length: 0
    Data_length: 0
Max_data_length: 0
   Index_length: 1024
      Data_free: 0
 Auto_increment: NULL
    Create_time: NULL
    Update_time: 2013-08-19 19:39:09
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment: Engine "MyISAM"
1 row in set (0.01 sec)

$ ls -l myisam/* | tee >(awk '{i+=$5}END{print i}')
-rw-rw---- 1 mysql mysql   61  8月 19 19:38 2013 myisam/db.opt
-rw-rw---- 1 mysql mysql    0  8月 19 19:39 2013 myisam/tweet.MYD
-rw-rw---- 1 mysql mysql 1024  8月 19 19:39 2013 myisam/tweet.MYI
-rw-rw---- 1 mysql mysql 8638  8月 19 19:39 2013 myisam/tweet.frm
9723

$ ls -l mroonga_storage* | tee >(awk '{i+=$5}END{print i}')
-rw-rw---- 1 mysql mysql     4096  8月 19 19:39 2013 mroonga_storage.mrn
-rw-rw---- 1 mysql mysql 12857344  8月 19 19:39 2013 mroonga_storage.mrn.0000000
-rw-rw---- 1 mysql mysql  4243456  8月 19 19:39 2013 mroonga_storage.mrn.0000103
-rw-rw---- 1 mysql mysql     4096  8月 19 19:39 2013 mroonga_storage.mrn.0000104
-rw-rw---- 1 mysql mysql     4096  8月 19 19:39 2013 mroonga_storage.mrn.0000105
-rw-rw---- 1 mysql mysql   274432  8月 19 19:39 2013 mroonga_storage.mrn.0000106
-rw-rw---- 1 mysql mysql  1048576  8月 19 19:39 2013 mroonga_storage.mrn.001

mroonga_storage:
合計 16
-rw-rw---- 1 mysql mysql   61  8月 19 19:38 2013 db.opt
-rw-rw---- 1 mysql mysql 8638  8月 19 19:39 2013 tweet.frm
18444795

$ ls -l mroonga_wrapper* | tee >(awk '{i+=$5}END{print i}')
-rw-rw---- 1 mysql mysql     4096  8月 19 19:39 2013 mroonga_wrapper.mrn
-rw-rw---- 1 mysql mysql 12857344  8月 19 19:39 2013 mroonga_wrapper.mrn.0000000
-rw-rw---- 1 mysql mysql    65536  8月 19 19:39 2013 mroonga_wrapper.mrn.0000103
-rw-rw---- 1 mysql mysql  1048576  8月 19 19:39 2013 mroonga_wrapper.mrn.001

mroonga_wrapper:
合計 20
-rw-rw---- 1 mysql mysql   61  8月 19 19:38 2013 db.opt
-rw-rw---- 1 mysql mysql    0  8月 19 19:39 2013 tweet.MYD
-rw-rw---- 1 mysql mysql 1024  8月 19 19:39 2013 tweet.MYI
-rw-rw---- 1 mysql mysql 8638  8月 19 19:39 2013 tweet.frm
13985275
mroonga_storage, mroonga_wrapperの差とmroonga_storageのSHOW TABLE STATUSの結果から察するに、.mrn.0000103が.MYDファイルみたいな扱いになるんだろうか。

LOAD DATA INFILEで1万ツイートほど流し込んでみる。

mysql55> LOAD DATA INFILE '/tmp/tweets.csv' INTO TABLE tweet FIELDS TERMINATED BY ',' ENCLOSED BY  '"' IGNORE 1 LINES (tweet_id, @dummy, @dummy, @dummy, @dummy, timestamp, @dummy, text, @dummy);
Query OK, 10045 rows affected, 10089 warnings (0.25 sec)
Records: 10045  Deleted: 0  Skipped: 0  Warnings: 10089
timestampカラムのデータを切り詰めたとかフィールドの数が合わないってワーニングが出てたけど大勢に影響がないので気にしない。

mysql55> SHOW TABLE STATUS FROM myisam\G
*************************** 1. row ***************************
           Name: tweet
         Engine: MyISAM
        Version: 10
     Row_format: Dynamic
           Rows: 10045
 Avg_row_length: 125
    Data_length: 1263404
Max_data_length: 281474976710655
   Index_length: 217088
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2013-08-19 19:39:02
    Update_time: 2013-08-19 19:41:06
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.00 sec)

mysql55> SHOW TABLE STATUS FROM mroonga_storage\G
*************************** 1. row ***************************
           Name: tweet
         Engine: mroonga
        Version: 10
     Row_format: Dynamic
           Rows: 10045
 Avg_row_length: 0
    Data_length: 46469120
Max_data_length: 0
   Index_length: 0
      Data_free: 0
 Auto_increment: NULL
    Create_time: NULL
    Update_time: NULL
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.00 sec)

mysql55> SHOW TABLE STATUS FROM mroonga_wrapper\G
*************************** 1. row ***************************
           Name: tweet
         Engine: mroonga
        Version: 10
     Row_format: Dynamic
           Rows: 10045
 Avg_row_length: 125
    Data_length: 1263404
Max_data_length: 0
   Index_length: 217088
      Data_free: 0
 Auto_increment: NULL
    Create_time: NULL
    Update_time: 2013-08-19 19:41:19
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment: Engine "MyISAM"
1 row in set (0.00 sec)

$ ls -l myisam/* | tee >(awk '{i+=$5}END{print i}')
-rw-rw---- 1 mysql mysql      61  8月 19 19:38 2013 myisam/db.opt
-rw-rw---- 1 mysql mysql 1263404  8月 19 19:41 2013 myisam/tweet.MYD
-rw-rw---- 1 mysql mysql  217088  8月 19 19:41 2013 myisam/tweet.MYI
-rw-rw---- 1 mysql mysql    8638  8月 19 19:39 2013 myisam/tweet.frm
1489191

$ ls -l mroonga_storage* | tee >(awk '{i+=$5}END{print i}')
-rw-rw---- 1 mysql mysql     4096  8月 19 19:41 2013 mroonga_storage.mrn
-rw-rw---- 1 mysql mysql 12857344  8月 19 19:39 2013 mroonga_storage.mrn.0000000
-rw-rw---- 1 mysql mysql  8437760  8月 19 19:41 2013 mroonga_storage.mrn.0000103
-rw-rw---- 1 mysql mysql  4198400  8月 19 19:41 2013 mroonga_storage.mrn.0000104
-rw-rw---- 1 mysql mysql  4198400  8月 19 19:41 2013 mroonga_storage.mrn.0000105
-rw-rw---- 1 mysql mysql 29634560  8月 19 19:41 2013 mroonga_storage.mrn.0000106
-rw-rw---- 1 mysql mysql  1048576  8月 19 19:39 2013 mroonga_storage.mrn.001

mroonga_storage:
合計 16
-rw-rw---- 1 mysql mysql   61  8月 19 19:38 2013 db.opt
-rw-rw---- 1 mysql mysql 8638  8月 19 19:39 2013 tweet.frm
60387835

$ ls -l mroonga_wrapper* | tee >(awk '{i+=$5}END{print i}')
-rw-rw---- 1 mysql mysql     4096  8月 19 19:39 2013 mroonga_wrapper.mrn
-rw-rw---- 1 mysql mysql 12857344  8月 19 19:39 2013 mroonga_wrapper.mrn.0000000
-rw-rw---- 1 mysql mysql    65536  8月 19 19:39 2013 mroonga_wrapper.mrn.0000103
-rw-rw---- 1 mysql mysql  1048576  8月 19 19:39 2013 mroonga_wrapper.mrn.001

mroonga_wrapper:
合計 1464
-rw-rw---- 1 mysql mysql      61  8月 19 19:38 2013 db.opt
-rw-rw---- 1 mysql mysql 1263404  8月 19 19:41 2013 tweet.MYD
-rw-rw---- 1 mysql mysql  217088  8月 19 19:41 2013 tweet.MYI
-rw-rw---- 1 mysql mysql    8638  8月 19 19:39 2013 tweet.frm
15464743

更新時刻やファイルサイズからして、.mrnと.mrn.000000はなんかテーブル情報持ってて、.mrn.00010x(から連番になるんだろう)ファイルがデータ本体ぽい。足すとData_lengthっぽくなるし。
MyISAMのテーブルはフルテキストインデックス作る気がないのでここまでとして、mroonga_storageとmroonga_wrapperでそれぞれインデックスを作ってみる。

mysql55> ALTER TABLE mroonga_storage.tweet ADD FULLTEXT KEY (text) COMMENT 'parser "TokenBigram"';
Query OK, 0 rows affected (0.48 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql55> ALTER TABLE mroonga_wrapper.tweet ADD FULLTEXT KEY (text) COMMENT 'parser "TokenBigram"';
Query OK, 10045 rows affected (1.18 sec)
Records: 10045  Duplicates: 0  Warnings: 0

mysql55> SHOW TABLE STATUS FROM mroonga_storage\G
*************************** 1. row ***************************
           Name: tweet
         Engine: mroonga
        Version: 10
     Row_format: Dynamic
           Rows: 10045
 Avg_row_length: 0
    Data_length: 46469120
Max_data_length: 0
   Index_length: 0
      Data_free: 0
 Auto_increment: NULL
    Create_time: NULL
    Update_time: NULL
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.00 sec)

mysql55> SHOW TABLE STATUS FROM mroonga_wrapper\G
*************************** 1. row ***************************
           Name: tweet
         Engine: mroonga
        Version: 10
     Row_format: Dynamic
           Rows: 10045
 Avg_row_length: 125
    Data_length: 1263404
Max_data_length: 0
   Index_length: 217088
      Data_free: 0
 Auto_increment: NULL
    Create_time: NULL
    Update_time: 2013-08-19 19:45:54
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment: Engine "MyISAM"
1 row in set (0.00 sec)

$ ls -l mroonga_storage* | tee >(awk '{i+=$5}END{print i}')
-rw-rw---- 1 mysql mysql     4096  8月 19 19:45 2013 mroonga_storage.mrn
-rw-rw---- 1 mysql mysql 17051648  8月 19 19:45 2013 mroonga_storage.mrn.0000000
-rw-rw---- 1 mysql mysql  8437760  8月 19 19:41 2013 mroonga_storage.mrn.0000103
-rw-rw---- 1 mysql mysql  4198400  8月 19 19:41 2013 mroonga_storage.mrn.0000104
-rw-rw---- 1 mysql mysql  4198400  8月 19 19:41 2013 mroonga_storage.mrn.0000105
-rw-rw---- 1 mysql mysql 29634560  8月 19 19:41 2013 mroonga_storage.mrn.0000106
-rw-rw---- 1 mysql mysql  8437760  8月 19 19:45 2013 mroonga_storage.mrn.0000107
-rw-rw---- 1 mysql mysql  2134016  8月 19 19:45 2013 mroonga_storage.mrn.0000108
-rw-rw---- 1 mysql mysql  8392704  8月 19 19:45 2013 mroonga_storage.mrn.0000108.c
-rw-rw---- 1 mysql mysql  1048576  8月 19 19:45 2013 mroonga_storage.mrn.001

mroonga_storage:
合計 16
-rw-rw---- 1 mysql mysql   61  8月 19 19:38 2013 db.opt
-rw-rw---- 1 mysql mysql 8638  8月 19 19:45 2013 tweet.frm
83546619

$ ls -l mroonga_wrapper* | tee >(awk '{i+=$5}END{print i}')
-rw-rw---- 1 mysql mysql     4096  8月 19 19:45 2013 mroonga_wrapper.mrn
-rw-rw---- 1 mysql mysql 17051648  8月 19 19:45 2013 mroonga_wrapper.mrn.0000000
-rw-rw---- 1 mysql mysql 16842752  8月 19 19:45 2013 mroonga_wrapper.mrn.0000104
-rw-rw---- 1 mysql mysql  8437760  8月 19 19:45 2013 mroonga_wrapper.mrn.0000105
-rw-rw---- 1 mysql mysql  7639040  8月 19 19:45 2013 mroonga_wrapper.mrn.0000106
-rw-rw---- 1 mysql mysql 12587008  8月 19 19:45 2013 mroonga_wrapper.mrn.0000106.c
-rw-rw---- 1 mysql mysql  1048576  8月 19 19:45 2013 mroonga_wrapper.mrn.001

mroonga_wrapper:
合計 1464
-rw-rw---- 1 mysql mysql      61  8月 19 19:38 2013 db.opt
-rw-rw---- 1 mysql mysql 1263404  8月 19 19:45 2013 tweet.MYD
-rw-rw---- 1 mysql mysql  217088  8月 19 19:45 2013 tweet.MYI
-rw-rw---- 1 mysql mysql    8638  8月 19 19:45 2013 tweet.frm
65100071
SHOW TABLE STATUSには計上されないんだね。。容量の増加量はストレージモードで23MiB, ラッパーモードで48MiBくらい。

TokenBigramのトークン数はフルテキスト文字数とイコールで、SUM(CHARACTER_LENGTH(text))で取ったら504972だったので、トークンは概算で50万とする。アルファベットはまとめて1つのトークンにするとかそういうのは取り敢えず今は考えない。
⇒本当はSUM(CHARACTER_LENGTH(text) - 1)になるかと思ったんだけど、ならないみたい。
http://groonga.org/docs/spec/search.html

1トークンあたりのサイズは(2 * charset + PRIMARY KEY SIZE)くらいかなと期待すると、utf8は1文字3バイトでPRIMARY KEYがBIGINTの8バイトで16バイト。

単純に掛け算すると8MiBくらいが期待だったんだけど、とてもそんなもんじゃ済んでない。単純にLOAD DATAしただけでも60MiB食うような感じだから、内部的に色々情報を持っててこれじゃ済まないってことなんだろうけど。

取り敢えず思ったより行くよね、というところに止めておいて他の何かで追試したい。というか、してくる。


TokenMecabでどのくらい減らせるかも調べたい。。

2013年8月8日木曜日

Amazon RDSの各種プロシージャの中身の見方

http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.MySQL.CommonDBATasks.html

↑に記載されてるようなやつ。

mysql> SELECT * FROM information_schema.routines\G
..

でルーチンボディやその他属性関連色々見られる。


mysql.rds_skip_repl_errorとか見ていて判りやすいですね。

mysql> SELECT routine_body FROM information_schema.routines WHERE specific_name= 'rds_skip_repl_error'\G
..

ルーチンボディはライセンスがよく判らないので貼らないでおこうそうしよう。。

Amazon RDSのリードレプリカでClient requested master to start replication from impossible positionに出会う

マスターがMulti-AZ構成で、フェイルオーバーした時に、リードレプリカのI/Oスレッドが止まっちゃいました。

mysql56> SHOW SLAVE STATUS\G
..
                Last_IO_Errno: 1236
                Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Client requested master to start replication from impossible position; the first event 'bin.000001' at 64056, the last event read from './bin.000001' at 4, the last byte read from './bin.000001' at 4.'
..

ログ出力はこんな感じ。別のサーバーで再現させただけなので数字はテキトーです。


Error:1236自体は、「I/Oスレッドがマスターのbinlogを読み込もうとしたら、致命的な(リトライしても決して成功しない)エラーになった」という意味で、後続のメッセージが重要になったりします。

この場合は、"Client requested master to start replication from impossible position;"がそれですね。スレーブのI/OスレッドはMASTER_LOG_FILE= 'bin.000001', MASTER_LOG_POS= 64056をマスターに要求したけれど、マスターのbin.000001ファイル上にはPosition 64056のイベントは存在しない、というエラーです。

たぶん、マスターが元のAZにいたときに、スレーブがぴったり遅延なくbinlogを受信していた && sync_binlog= 0だったので元のマスターがwrite()したbinlogがfsync()される前に切り替わってしまったのが原因でせう。

MySQL on EC2などであればCHANGE MASTER TOで直したりもできるんですが(マスターに存在しないトランザクションがスレーブに受信されちゃってる状態なので、ある程度は調整しないとではあるんですが)そこはRDS、それは無理。

https://forums.aws.amazon.com/thread.jspa?messageID=452065&#452065

"you should create a new read replica to replace the broken one."だそうで。
まあ、マスターに無いbinlogがスレーブに行っちゃっている時点でデータの整合性も保証できなくなってるわけで、おとなしく作り直すのがいいんでしょうね。


ちなみにですが、マスター上に存在しないバイナリーログファイルを指定するとこんな感じに。

mysql56> SHOW SLAVE STATUS\G
..
                Last_IO_Errno: 1236
                Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file'
..

そんなバイナリーログファイル持ってないぜって感じですね。


mysql.rds_skip_repl_errorで直るかなぁって相談受けたんだけど、無理です。
CALLステートメントでよく呼ぶストアドルーチンの中身の見方は↓こんな感じ。

http://yoku0825.blogspot.jp/2013/08/amazon-rds.html