Home

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

xenconsoled を止めないために

Xen を使っていると、xm console を実行したときに

xenconsole: Could not open tty `/dev/pts/2': No such file or directory

というメッセージをよく見るね。
ご存知の通り xenconsoled が落ちてるせいだ。
暇なときに、根本的に落ちないようにする方法はないのかと思って調べてみたけど見つけられなかった。
起動しなおせば済むんで原因を追及する人がいないんだろうね。
ということで、自分も対症療法として

#!/bin/sh
pgrep xenconsoled > /dev/null 2>&1
if [ $? -ne 0 ]; then
  /usr/sbin/xenconsoled
fi

というスクリプトを /etc/cron.hourly に入れておく。
関係ないけど pgrep 便利だな〜。

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

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

パスワード入力をスキップして scp できないアカウント

シェルスクリプトの中で scp を使うことになって、パスワード入力をスキップしようとしてハマった。
接続先のサーバは1台で、うまくいくアカウントとダメなアカウントがある。
scp -v でログを吐かせて比較してみたけど、うまくいかない方は
debug1: Server accepts key: pkalg ssh-dss blen 433
の行から後が違うということが分かっただけ。
そこから悩むこと数時間。
ふと、サーバ側のそれぞれのアカウントのホームディレクトリを見たら、うまくいかない方の .ssh ディレクトリのパーミッションが 755 になっていることに気付いた。
700 に変更したら通った。
・・・。
自分のせいなのは分かっているよ。
でも激しく脱力。

MySQL への接続元ホストをサブネットで指定

MySQL で特定の IP アドレスの範囲からの接続だけを許可する場合はワイルドカード「%」を使わないといけないと思っていたんだけど、リファレンスを見ていたらサブネットマスクで指定する方法が載っていた。
http://dev.mysql.com/doc/refman/5.1/ja/connection-access.html
GRANT の構文のページには詳しく書かれてないので気付かなかったよ〜。
ワイルドカードだとクラスの範囲でしか指定できないけど、こっちならもっと柔軟に設定できるね。
例えば

mysql> grant all privileges on *.* to hoge@'192.168.10.0/255.255.255.192';
mysql> grant all privileges on *.* to hoge@'192.168.10.64/255.255.255.192';

こんな風に指定するだけ。
確認してみると

mysql> select host,user from mysql.user;
+-------------------------------+------+
| host                          | user |
+-------------------------------+------+
| 127.0.0.1                     | root |
| 192.168.10.0/255.255.255.192  | hoge |
| 192.168.10.64/255.255.255.192 | hoge |
| localhost                     | root |
| localhost.localdomain         | root |
+-------------------------------+------+
6 rows in set (0.00 sec)

バッチリだ。