Home

技術系のメモと日々の雑感

error reconnecting to master

MySQL のスレーブで、stop slave してから読み取りロックをかけてダンプを取ったときのこと。
ロックを解除して、start slave でレプリケーションを再開してから show slave status の出力を見たら、Last_IO_Error にメッセージが出ていた。

Last_IO_Error: error reconnecting to master 'hoge@XXX.XXX.XXX.XXX:3306' - retry-time: 60 retries: 86400

Slave_IO_Running も Slave_SQL_Running も Yes になってるし、Last_Errno は 0 なので、一時的なエラーだろうね。
でも、何となく気持ち悪いので mysqld をリスタートしてみたら、無事にメッセージは消えてくれた。
これって放っておいたら勝手に消えるのかな。

MySQL の configure で unrecognized options

MySQL 5.1.36 をソースから入れたときの話。
InnoDB を使うので、過去に作った手順に従って configure で --with-innodb を指定したら

configure: WARNING: unrecognized options: --with-innodb

と怒られた。
実は以前、このワーニングに気づかずにそのままコンパイルしてしまったことがあるんだけど、InnoDB は問題なく使えていた。
--with-innodb を指定しないでコンパイルしたら、当然ながら InnoDB は使えなかったから、とりあえずこのオプションは効いているってことだね。
とはいえ、ワーニングを放置しておくわけにもいかない。
暇を見つけて configure --help を眺めてみると、InnoDB を有効にするオプションの指定方法が変更されていた。
以下、関係があるところだけ。

--with-plugins=PLUGIN[[[,PLUGIN..]]]
Plugins to include in mysqld. (default is: none)
Must be a configuration name or a comma separated list of plugins.
Available configurations are: none max max-no-ndb all.
Available plugins are: partition daemon_example ftexample archive blackhole
csv example federated heap ibmdb2i innobase myisam myisammrg ndbcluster.

=== InnoDB Storage Engine ===
Plugin Name:      innobase
Description:      Transactional Tables using InnoDB
Supports build:   static and dynamic
Configurations:   max, max-no-ndb

ということで、今後は --with-plugins=innobase と指定しよう。

MySQL のスレーブのステータスを定期的にチェック

MySQL でレプリケーションを組んだ後、スレーブのステータスを定期的にチェックする方法を考えていた。
以前、Ver 5.0 で一度レプリケーションの構成を組んだときに、load data infile とか auto increment といったステートメントベースが非対応の SQL 文を使ってしまってレプリケーションが止まったことがあるので、それ以来ちょっとだけ気をつけるようにしている。
調べてみたら、mysql コマンドは標準入力から SQL 文を読み込んで実行できるので、今回はこれでいくことにした。
次のような簡単なスクリプトを cron で実行させるだけだ。

#!/bin/sh
echo 'show slave status¥G' | ¥
/usr/local/bin/mysql -u root -pXXXXXX | ¥
mail -s 'slave tatus' hoge@example.com

Last_Errno とかを見てエラーのときだけメールしてもいいんだけど、スクリプトで何かミスして実際にエラーになったときにメールが飛んでこなかったら大変なので今回はやめておこう。
こういうクリティカルなところはシンプルに限る。

mysqlbinlog の出力をリアルタイムで監視するには

MySQL でレプリケーションを組んだときに、バイナリログが急激に増えていくという現象が発生。
結局、cron で1日1回走らせていたプログラムがループして、更新がかかり続けていたというオチだった。
せっかくなのでこのときやったことをまとめておく。
こういう現象の原因を調べるにはクエリログを吐かせるのがいちばん簡単なんだろうけど、実運用しているサーバだったので負荷を上げたくないという理由で却下。
mysqlbinlog の出番だ。

mysqlbinlog --no-defaults mysql-bin.000015 | tail -f

これで出力を見張ってられるかと思ったら、ログへの出力が発生した時点でコマンドが終了してしまった。
man tail してみたら、-f オプションはパイプの場合は無視されるんだね。
普段こういう使い方をしないから気づかなかったな〜。
あきらめるわけにはいかないので強引な方法でいくことにした。

watch 'mysqlbinlog --no-defaults mysql-bin.000015 | tail'

これで一応ログの末尾を見張ることができる。
tail -f みたいに表示が流れていかないので見にくいけど。

watch -d -n 10 'mysqlbinlog --no-defaults mysql-bin.000015 | tail -n 30'

という風に実行したら少しはマシかな。
まぁ、こんなのでも max_binlog_size を小さくしておけば使えないことはないね。

ibdata1 のサイズを減らす手順

つい最近知ったんだけど、MySQL のソースに付いている my.cnf のひな型では innodb_data_file_path に autoextend が付いているので、このまま使いつづけると ibdata1 のサイズがどんどん大きくなっていくんだね。
とあるサーバで 30GB を越えていて焦った〜。
サイズを増やさないようにする設定は調べたらすぐに分かったんだけど、実際にやってみると引っかかりどころが色々とあったので手順をまとめておく。
検証に使った MySQL は 5.0 系だ。
先に書いておくと、my.cnf に

innodb_data_file_path = ibdata1:1G
innodb_file_per_table

といった設定を入れて mysqld をリスタートするだけでは ibdata1 のサイズは変わらないし、「.ibd」ファイルも作られなかった。
しかも、このとき mysqld はうまく動いているように見えるんだけど、ログに次のようなエラーが出力されるから、実はマズいことになっている。

InnoDB: Error: data file ./ibdata1 is of a different size
InnoDB: 386048 pages (rounded down to MB)
InnoDB: than specified in the .cnf file 655360 pages!
InnoDB: Could not open or create data files.


さて、前置きが長くなったけど手順は次の通りだ。

1.mysqldump --all-databases --single-transaction といった風にダンプを取る
2.InnoDB を使用しているテーブルをすべて削除
    ※drop database した方が分かりやすいかも
3.mysqld を停止
4.データディレクトリの中の ibdata1、ib_logfile0、ib_logfile1 を削除
5.上に書いた2行を my.cnf の [mysqld] セクションに追加
    ※この例では ibdata1 のサイズが 1GB になる
6.mysqld を起動
7.ダンプをリストア

そういえば、innodb_data_file_path で大きめのサイズを指定した場合、mysqld を起動したときに

# /etc/rc.d/init.d/mysql start
Starting MySQL...................................      [Failed]

という風にエラーになることがあるけど、これは ibdata1 ができあがるまでに時間がかかってタイムアウトしているだけで、実際には mysqld は正常に起動しているようだ。
この動作が分かってなくて何度もやり直してしまった。
ついでにうまくいったときのログも付けておく。

InnoDB: The first specified data file ./ibdata1 did not exist:
InnoDB: a new database to be created!
090703 17:17:51 InnoDB: Setting file ./ibdata1 size to 1024 MB
InnoDB: Database physically writes the file full: wait...
InnoDB: Progress in MB: 100 200 300 400 500 600 700 800 900 1000
090703 17:18:29 InnoDB: Log file ./ib_logfile0 did not exist: new to be created
InnoDB: Setting log file ./ib_logfile0 size to 5 MB
InnoDB: Database physically writes the file full: wait...
090703 17:18:30 InnoDB: Log file ./ib_logfile1 did not exist: new to be created
InnoDB: Setting log file ./ib_logfile1 size to 5 MB
InnoDB: Database physically writes the file full: wait...
InnoDB: Doublewrite buffer not found: creating new
InnoDB: Doublewrite buffer created
InnoDB: Creating foreign key constraint system tables
InnoDB: Foreign key constraint system tables created
090703 17:18:30 InnoDB: Started; log sequence number 0 0
090703 17:18:31 [Note] /usr/local/libexec/mysqld: ready for connections.
Version: 'X.X.XX' socket: '/tmp/mysql.sock' port: 3306 Source distribution

この機会にログをマメにチェックするクセをつけよう・・・。