Browse Month: November 2010

Rails と Merb の logger に現在日時をつける

Rails と Merb を使っていますが、logger(ログを出力するクラス)に現在日時をつける方法をまとめてみます。つまり、デバッグログを出すときに、デバッグログを出力した日時をあわせて出力するということです。

まず、Rails は、RAILS_ROOT/lib/my_formatter.rb を、次のような感じで作成します。

class MyFormatter < Logger::Formatter
Format = "[%s] %s:%s: %s\n"
def call(severity, time, progname, msg)
Format % [format_datetime(time), severity, progname, msg2str(msg)]
end
private
def format_datetime(time)
time.strftime("%Y-%m-%d %H:%M:%S")
end
end

そして、logger を使う前に Formatter  に MyFormatter を設定します。

logger = Logger.new(STDOUT)
logger.formatter = MyFormatter.new

次に Merb は、Merb.logger というクラスがありますが、これは実質 extlib/logger になっています。そのため、delimiter に現在日時を設定するだけなのですが、次のように init.rb などで設定しまうと、Merb の Ruby プロセスが起動した時刻固定になってしまいます。


Merb::Config.use do |c|
c[:log_delimiter] = "#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} "
end

そのため、さらに Controller の dispatch が呼ばれる前にフックするといいと思います。


class Application < Merb::Controller
self._before_dispatch_callbacks << lambda do |c|
Merb.logger.delimiter = "#{Time.now.strftime('%Y-%m-%d %H:%M:%S')} "
end
end

Merb の Controller は、dispatch の前後でフックを仕掛けることができるので便利です。

extlib::logger のデフォルトの delimiter は「~(チルダ)」になっているので、必ず変更したほうがいいと思います。

keepalived の HTTP ヘルスチェックを改良してみた

keepalived で、HTTP ヘルスチェックしているとき、今まではあまり特に考えず、次のようなシンプルな形になっていた。

virtual_server group HTTP {
delay_loop 3
lvs_sched wrr
lvs_method DR
protocol TCP
virtualhost status.server.example.com

real_server 192.168.0.1 80 {
weight 1
inhibit_on_failure
HTTP_GET {
url {
path /
status_code 200
}
connect_port 80
connect_timeout 5
}


}

これでしばらく運用していると、1台だけリアルサーバをメンテナンスしたいとき、高トラフィックなサイトなのでプログラムをデプロイしたいときウォームアップするために、一時的にリアルサーバをはずしたときがある。

今までこんなときは、LVS 側で ipvsadm コマンドを使っていたけれど、ipvsadm は root 権限が必要で、かつ複数の VIP で同じリアルサーバがあるときは、複数回コマンドを実行しなければならず、めんどうだった。

そこで、手軽にリアルサーバをはずせるように、かなり昔に紹介した mod_asis を使ってみることにした。

まず、keepalived 側は、次のように変更した。

virtual_server group HTTP {
delay_loop 3
lvs_sched wrr
lvs_method DR
protocol TCP
virtualhost status.server.example.com

real_server 192.168.0.1 80 {
weight 1
inhibit_on_failure
HTTP_GET {
url {
path /check.asis
status_code 200
}
connect_port 80
connect_timeout 5
}


}

192.168.0.1 80 に対して、ホスト名「status.server.example.com」で、check.asis をヘルスチェック用の URL にした。

そして、リアルサーバ (192.168.0.1) には、次のような VirtualHost を定義した。

LoadModule asis_module modules/mod_asis.so
<VirtualHost *>
ServerName status.server.example.com
DocumentRoot /var/www/status

<Directory /var/www/status>
Allow from All
</Directory>

AddHandler send-as-is asis

CustomLog /dev/null combined
</VirtualHost>

こんな感じで DocumentRoot を /var/www/status にした。ヘルスチェックは、一定秒ごとにリクエストがくるため、不要なアクセスログは出力しない方がいい。

次に /var/www/status に、HTTP ステータスコード 200 / 503 専用にファイルを用意した。

200.asis

Status: 200 OK
Content-Type: text/plain

s1

503.asis

Status: 503 Service Unavailable
Content-Type: text/plain

s1

そして、check.asis -> 200.asis を作成した。

$ ln -s 200.asis check.asis

これで設定は完了した。リアルサーバをはずしたいときは、リアルサーバで次のコマンドを一発実行すればよい。

$ ln -sf 503.asis check.asis

mod_asis を使えば、ヘルスチェックのために他の言語を使うことなく、HTTP のステータスコードを変更できるのが、とても便利ですね。

ハードディスクを交換した

本番サーバで、運用当初から使っていた 1U サーバの 160GB のハードディスクの容量がアクセスログでいよいよいっぱいになってきた。アクセスログは、何かあったときのためにできる限りとっておきたいので、1TB のハードディスクに交換してみることにした。

LVM になっているので、普通に 1TB を 2 台目のハードディスクを追加して増設してもよかったけれど、2 台ハードディスクがあると故障率も 2 倍になるので、1 台目のハードディスクを交換してみることにした。

OS は、CentOS 5.5 x86_64

既存のハードディスクは、次のようなパーティンション構成になっている。

/boot ext3 100MB

/ LVM 残りすべて

dd でコピーすればいいだと思っていたけれど、ちょっと調べてみるとより高速らしい dd_rescue を見つけたので、次のような手順でハードディスクを交換した。

0. dd_rescue をインストールする(dd_rescue は、EPEL の中にあるがかなり古いバージョンなので、新しいバージョンを使った方がいいかもしれない)

1. BIOS の設定で、2台目のハードディスクを有効にする(念のため、ネットワークケーブルを抜いておく)
$ sudo yum install -y dd_rescue

2. シングルユーザモードで起動する(linux 行に -s をつけてブートする)

3. ハードディスクのデータを、まるごとコピーする(おおよそ 60 分程度かかった)
sh-3.2# dd_rescue /dev/sda /dev/sdb

4. 新しいハードディスクに対して、fdisk して空き容量に対して LVM のパーティンションを作成する
sh-3.2# fdisk /dev/sdb

5. 基本パーティション3 を作成する -> n – p – 3

6. 基本パーティション3のタイプを LVM にする -> t  – 3 – 8e

7. 保存して終了するする -> w

8. シャットダウンする

9. 新しいハードディスクのみ接続する(古いハードディスクははずしてしまう)

10. BIOS の設定で、2台目のハードディスクを有効にする

11. シングルユーザモードで起動する

12. PV を作成する
sh-3.2# pvcreate /dev/sda3
Physical volume “/dev/sda3” successfully created

13. 作成した PV を、既存の VG に追加する
sh-3.2# vgextend vg00 /dev/sda3
Volume group “vg00” successfully extended

14. LV を拡張する
sh-3.2# lvextend -L +782.50G /dev/vg00/lvol1
Extending logical volume lvol1 to 930.91GB
Logical volume lvol1 successfully resized

15. ext3 を拡張する(おおよそ 34 分くらいかかった)
sh-3.2# resize2fs /dev/vg00/lvol1
resize2fs 1.39 (29-May-2006)
Filesystem at /dev/vg00/lvol1 is mounted on /; on-line reszing required

16. シングルユーザモードを終了する

17. 起動後、空きディスク容量を確認する

18. dd_rescue をアンインストールする
$ sudo yum remove -y dd_resuce

19. ネットワークケーブルを接続して、本番環境に再投入する

LVM なので、ハードディスクの容量の増設は簡単でよかった。

実は最初、コピー後の LVM パーティンションの基本領域を拡張しようと試行錯誤してしまった。インターネット上の情報で、「fdisk で一度 LVM 基本パーティンションを削除してから、再度 LVM 基本パーティションを作成して保存すると拡張できる」という情報があったが、僕の環境ではカーネルパニックしてしまった。

その他にもパーティンションをリサイズするツール GParted や Parted があるけれど、これらのツールはいずれも LVM をサポートしていなかった。ちなみに Parted で LVM の基本パーティションを操作しようとすると、次のエラーが出る。

“Error: Could not detect file system.”

その他にも、LVM 基本領域、そのものを拡張する情報があったけれど、かなり手順がめんどくさそうなので、今回は試さなかった。

ディスクイメージファイルを拡張する – diary of a madman

できたら、LVM 基本パーティション一つの方がきれいだけれど、そこはあまりこだわるポイントではない。

LVM 便利ですねー、ハードディスク1台のときも LVM にしておくと交換が簡単になりますよね。

Mecab-ruby on OSX 10.6

mecab-ruby が、OSX 10.6 でちゃんと動かなかったのでメモ。

MeCab は、Macports 経由でインストールする。

$ sudo port install mecab-ipadic-utf8

ここで、mecab-ruby-0.98 を展開して普通にインストールして、ruby から使うと、次のようなエラーになる。

0.98
RuntimeError: tagger.cpp(150) [load_dictionary_resource(param)] param.cpp(71) [ifs] no such file or directory: ./dicrc

これを直すには、mecab-ruby-0.98 の extconf.rb に、次のように変更する。

— extconf.rb-org        2010-11-05 18:49:52.000000000 +0900
+++ extconf.rb  2010-11-05 18:55:13.000000000 +0900
@@ -8,5 +8,6 @@
}

$CFLAGS += ‘ ‘ + `#{mecab_config} –cflags`.chomp
+$LDFLAGS = ‘-L/opt/local/lib’

have_header(‘mecab.h’) && create_makefile(‘MeCab’)

あとは、次のコマンドでインストールします。rvm を使っているので、通常ユーザでインストールします。

$ ruby extconf.rb

$ make install

これで、mecab-ruby に付属のテストプログラムを実行することで確認できますが、文字化けているため MeCab  の設定ファイルを、次のように設定します。

— mecabrc-org 2010-11-05 18:00:00.000000000 +0900
+++ mecabrc     2010-11-05 18:54:18.000000000 +0900
@@ -3,7 +3,7 @@
;
; $Id: mecabrc.in,v 1.3 2006/05/29 15:36:08 taku-ku Exp $;
;
-dicdir =  /opt/local/lib/mecab/dic/ipadic
+dicdir =  /opt/local/lib/mecab/dic/ipadic-utf8

; userdic = /home/foo/bar/user.dic

かなりはまったので、メモしておきます。