2012年9月28日金曜日

HandlerSocketの不思議な動作(まだ試す予定)

手元の環境でHandlerSocketと戯れていたら不思議な状態になった。

まずはHandlerSocketのRWポートでテーブルにアクセス。

$ telnet localhost 9999
..

P       0       d1      t1      PRIMARY num,val
0       1

0       =       1       1       1
0       2       1       c4ca4238a0b923820dcc509a6f75849b

コネクション張りっ放し。

別ターミナルからmysqlクライアントに入る。

mysql> lock table t1 write;

返ってこない。

更に別ターミナルからmysqlクライアント。

mysql> select count(*) from t1;

当然返ってこない。
PROCESSLISTはこんな感じになる。


mysql> show processlist;
+----+-------------+-----------------+---------------+---------+------+-------------------------------------------+-------------------------+
| Id | User        | Host            | db            | Command | Time | State                                     | Info                    |
+----+-------------+-----------------+---------------+---------+------+-------------------------------------------+-------------------------+
|  1 | system user | connecting host | NULL          | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL                    |
|  2 | system user | connecting host | NULL          | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL                    |
|  3 | system user | connecting host | NULL          | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL                    |
|  4 | system user | connecting host | NULL          | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL                    |
|  5 | system user | connecting host | handlersocket | Connect | NULL | handlersocket: mode=wr, 1 conns, 0 active | NULL                    |
|  6 | system user | connecting host | NULL          | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL                    |
|  7 | system user | connecting host | NULL          | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL                    |
| 13 | root        | localhost       | d1            | Query   |  229 | Waiting for table metadata lock           | lock table t1 write     |
| 14 | root        | localhost       | d1            | Query   |   10 | Waiting for table metadata lock           | select count(*) from t1 |
| 15 | root        | localhost       | d1            | Query   |    0 | NULL                                      | show processlist        |
+----+-------------+-----------------+---------------+---------+------+-------------------------------------------+-------------------------+
10 rows in set (0.00 sec)


ここまでは直感的なんだけど、更に別ターミナルでHandlerSocketを叩く。

$ telnet localhost 9999
..
P       1       d1      t1      PRIMARY num,val
0       1

1       =       1       100     1       0
0       2       100     f899139df5e1059396431415e770c6dd


あれ、読める。

一番最初のHandlerSocketを叩いてるtelnetを落とす。
LOCK TABLEが待つのは変わらない。
次につないだtelnetを落としてようやくWRITEロックが取れてLOCK TABLEが返ってくる。


これ、MyISAMにばんばん書く様な環境でHandlerSocketからもばんばん参照させると、
WRITEロックが取れずにクエリが滞留しまくるとか…?

RWポートだとこうだけど、ROポートからアクセスするとどうなるんだろうって気になってきた。
あとでやる。


【2012/09/28 12:03】
ROポート(9998)でも再現する。
でもMyISAMの更新は普通に出来た。
OPTIMIZE TABLEは止まったから、メタデータをロックしようとする奴だけかな。

2012年9月27日木曜日

Infobrightのバックアップを考えてみる

ぼんやりと色々考えてみる。

・Community EditionはINSERTが使えないので、そのままmysqldumpを取る訳にはいかない。
 ・取れるけど、一度まともなMySQLサーバーにリストアして、
  そこからわざわざSELECT .. INTO OUTFILE ..でエクスポートする必要があるので無駄。
 ・BRIGHTHOUSEエンジンはLOCK TABLE構文に対応していないので、
  --skip-lock-tablesを指定すること。

・というかそれならmysqldump --tab=..で取りたいところだけど、
 --tabオプションは--all-databasesと一緒に使えないので
 シェルスクリプトの中で全データベースをさらってやる必要がありそう。
 ・リストアはおんなじ様にデータベースをさらってやりながらmysqlimportでやる感じ。

・ド本命はファイルバックアップ。
 ・日本語ユーザーガイドでも推奨されてるし。
 ・ファイル圧縮率が高い(1/10くらいになる)ので、50GBの生データでも5GB。
  tarボールで固めてやるならそんなに時間かからないはず。


…別に24 * 365動かさなきゃならない理由が見付からないので、
どう考えてもファイルバックアップか。。

バイナリログを有効にしてBRIGHTHOUSEエンジンのテーブルに
LOAD DATA INFILE ..を叩いたら、ログできないよ! って怒られた(´・ω・`) < 増分バックアップ無理ー。
これ、商用版はできるのかな?


【2012/09/28 15:40】
ちなみに、binlog_format = ROWで

ERROR 1598 (HY000): Binary logging not possible. Message: Statement cannot be logged to the binary log in row-based nor statement-based format

と怒られたのでSTATEMENTにしてみたけど同じエラーが返ってきやがった(´・ω・`)
perrorで1598を調べると、Illegal error codeって言われるし(´・ω・`)

2012年9月25日火曜日

innodb_rollback_segmentsを探る(探りきれなかった)

リファレンスマニュアルにきっちり、
`デフォルトの128から減らせよ! 減らした方がパフォーマンス上がるぞ!'
的なことが書かれている割に、
どれくらい減らして良いのか、減らすと何が起きるのか
ほとんど情報の無いinnodb_rollback_segments。。

http://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_rollback_segments


取り敢えず5.5のソースにこんな記載が。

storage/innobase/include/trx0sys.h

/* Max number of rollback segments: the number of segment specification slots
in the transaction system array; rollback segment id must fit in one (signed)
byte, therefore 128; each slot is currently 8 bytes in size. If you want
to raise the level to 256 then you will need to fix some assertions that
impose the 7 bit restriction. e.g., mach_write_to_3() */

#define TRX_SYS_N_RSEGS                 128
/* Originally, InnoDB defined TRX_SYS_N_RSEGS as 256 but created only one
rollback segment.  It initialized some arrays with this number of entries.
We must remember this limit in order to keep file compatibility. */
#define TRX_SYS_OLD_N_RSEGS             256

5.1のソースを見ると、確かにTRX_SYS_N_REGSが256で定義されてて、
5.5にはあるinnodb_rollback_segmentsの数を判定するようなものがごっそり無い(あたりまえ


取り敢えず直感的に、
な感じがしたのでMySQL5.1でテスト。
Perlで512個のプロセスをfork()して一斉に$dbh->begin_workからの$dbh->do("INSERT ..")、
SLEEPして$dbh->rollback。

SHOW PROCESSLISTもSHOW ENGINE INNODB STATUSもざっと見ちゃんとトランザクションになってる。

…つながるねぇ、何の問題もないねぇ。。

とかやっているうちにありがたい情報が。
いつもありがとうございます(*-人-)


うーん、コア数変えながらベンチマーク取りたいけど、環境的に厳しい。。
それになんかロールバックセグメントそのものに対する興味がむくむくと。。

大体、128から1にしたら誤差かと思えるくらいはtpmC上がった気がするけど、
そんなに効果あるのかなこれ?


【2012/09/27 15:54】
$dbh->do("UPDATE ..")に変えてHistory list lengthをめりめりしてみたり、
Undoの数をめりめりしてみたけど限界っぽいものは掴めず。

5.5のstorage/innobase/include/trx0rseg.hにこんなのを見つける。


/* Maximum number of transactions supported by a single rollback segment */
#define TRX_RSEG_MAX_N_TRXS     (TRX_RSEG_N_SLOTS / 2)

からの、

/* Number of undo log slots in a rollback segment file copy */
#define TRX_RSEG_N_SLOTS        (UNIV_PAGE_SIZE / 16)

1ページ16KiBだから、512 * innodb_rollback_segmentsかと思ったけどさにあらず。。
ちなみに5.1はTRX_RSEG_N_SLOTSが1024ハードコード。

よし、もうだめぽ!
楽しかったので良しとする。

2012年9月20日木曜日

mysqldump --single-transaction --flush-logsの内部処理順番

いつも忘れるのでメモ。

--single-transactionと--flush-logsでmysqldumpを取ると、

1) FLUSH TABLES
2) FLUSH TABLES WITH READ LOCK
3) FLUSH LOGS
4) START TRANSACTION
5) SHOW MASTER STATUS
6) UNLOCK TABLES
..
の順番で処理。


--single-transactionと--flush-logsと--dump-slaveで取ると、
1) STOP SLAVE SQL_THREAD
2) FLUSH TABLES
3) FLUSH TABLES WITH READ LOCK
4) FLUSH LOGS
5) SHOW SLAVE STATUS
6) UNLOCK TABLES
..
last) START SLAVE SQL_THREAD
の順番で処理。

--single-transactionだからSQLスレッド止める必要無いのに止めちゃうはなしは
studio3104さんの記事が詳しかったです。

http://d.hatena.ne.jp/studio3104/20120424/1335270734

2012年9月9日日曜日

datadirにNFSを使うなら

MySQLのdatadirにNFSやそれに類するものを使う場合に
たった一つだけ絶対にやっておいていただきたいこと。

エラーログだけは、ローカルに吐かせて下さい。

NFSが綺麗にお亡くなりになっていただける場合は結構なのですが、
中途半端にNFS側DISKのお加減がよろしくなかったり致しました場合、

頼みの綱のエラーログに何も出ていない。

なんてことになります。
頼むよ。


ちなみにdatadirにNFSを使ってちょっとだけ試してみた感想。

・InnoDBバッファプールに載ってるデータのSELECTならNFSを落としても返ってくる。
・MyISAMのkey_bufferも同じだから、
 INDEXだけで結果セットを作れる&key_bufferに載ってればNFS落としても返ってくるんだろうな。
 (MyISAMは試してない)
・載ってないデータを取ろうとすると、State: Opening tablesで待つ。
・INSERTもState: updatingで待つ。失敗せずに待つ。待つ。

・OSのキャッシュに載ってる時って、kernel側はどうするんだろ?
 そもそもNFSのデータをキャッシュしたりするのかな?
・まあ色々重い。

コンポーネントが増えると障害点も増えるから、あんまりやってほしくないなNFS。。

2012年9月6日木曜日

MySQL5.5以降をcmakeする

いや別にMySQLでなくても良いけれども。

5.5になってconfigureスクリプトからcmakeになって、
それ以来どうも自分でコンパイルしていないなんて話をよく聞くので書いてみる。


1) 対話型モード
これが個人的に一番楽。
設定項目を1つずつ訊いてくれる。

$ cmake -i
Would you like to see advanced options? [No]: No
..

Variable Name: CMAKE_INSTALL_PREFIX
Description: install prefix
Current Value: /usr/local/mysql
New Value (Enter to keep current value): /usr/mysql/5.6.6
..

こんな調子で1つずつ訊いてくれるので、オプション忘れもなく楽。


2) オプションで指定して一気にやらせるモード
configureスクリプトに近い使い方だけど、オプションが全然違うから憶えにくくてこっちはちょっと。。

$ cmake -D <マクロ名>=<値>[ -D <マクロ名>=<値>..]

何も指定せずデフォルトのままで良い場合は引数に.(=カレントディレクトリ)を渡してやる。

$ cmake .

マクロ名と説明の一覧がどこにあるのか謎だから、いつもはcmake -iを使ってる。
もしくは、cmake -iなら設定しながらマクロ名も一緒に出るので、メモしておくのも手かも。

2012年9月5日水曜日

VirtualBox仮想マシンの設定を一括で(?)変える

普段はもともとテンプレートになるVMが作ってあって、そこからcloneしている。

途中でテンプレートに追加したい様な設定を思い付いても、
既に作っちゃったVMに対しては手動で追加する必要があるわけで。
流石に10を超えると手でやるのは面倒くさくなったのでコピペ用メモ。


ホストはWindows7 + cygwinだけれど、
cygwinを管理者として実行したらVBoxManageが動かなかったので注意。


$ VBoxManage list vms | awk -F[\{\}] '{print $2}' | while read vmname ; do
> VBoxManage sharedfolder remove $vmname --name src
> VBoxManage sharedfolder add $vmname --name src --hostpath c:\\cygwin\\usr\\local\\src
> done

これは共有フォルダの一括追加パターン。
removeしてからaddしてるけど、もともと共有フォルダsrcが設定されていないVMの分は
VBOX_E_OBJECT_NOT_FOUNDでエラーになるけど無視する。


VBoxManageに渡すコマンドの部分を変えれば一応いろんな一括変更に使える。はず。