2007-11-10 ウチの環境では
FastCGIを使わない方が早い事が判明(笑)
どうやら、fork & exec速度>FastCGIの内部で処理する速度 っぽい。
◆ [日記][FreeBSD][tDiary] 結局色々書き換え
リファー取ってるrefererDbiIO.rbが@dbhを再利用しないので再利用する様に書き換えてみたり、counter.rbがカウンターファイルをぶち壊しそうなので排他ロックを取るようにしてみたり。
もう疲れたよ……。
◆ [日記][FreeBSD] データベースバックアップ時の問題と解決策
tDiaryをMySQLで走らせられる事は成功した。
ということは、データベース(MySQL)のバックアップを取る必要があるという事だ。
色々方法はあるが、基本は、MySQLを止めて、ファイルをコピー。厳密にはrsyncだが。
で、止めている間の処理が問題になる。といっても、1日1回、わずか30秒の停止時間なのだが(これでもかなり頑張って短くした)、その間にアクセスが来ると500 Internal Server Errorになってしまう。
これは今ひとつだ。
と言うわけで、データベースバックアップの為の停止時間中は、
ごめんメンテ(バックアップ)中。30秒ほど待ってリロードしてね!
という文字を返す様にtDiaryをいじる。
具体的にはindex.rbの「rescue Exception」の行の前にこんな感じのを追加した。
rescue DBI::DatabaseError => e
# DB error...
if (e.err == 2003) then
if @cgi then
print @cgi.header( 'type' => 'text/plain' )
else
print "Content-Type: text/plain\n\n"
end
print "ごめんメンテ(バックアップ)中。30秒ほど待ってリロードしてね!"
else
if @cgi then
print @cgi.header( 'type' => 'text/plain' )
else
print "Content-Type: text/plain\n\n"
end
puts "#$! (#{$!.class})"
puts ""
puts $@.join( "\n" )
puts "[Error:#{e.err}] #{e.errstr}"
end
何をやっているのかというと、DBI::DatabaseErrorが来た時(データベース関連のエラーが来た時)に、err番号が2003の時には「ごめんメンテ(バックアップ)中。30秒ほど待ってリロードしてね!」と表示して、それ以外の時にはExceptionとほぼ同じものを表示するというプログラム。
err番号2003というのは、相手にTCPレベルでコネクションが張れない(rejectされた)時のエラー番号……ぽい(笑) 違ってたらごめん。
んで、普通はそれで動くと思っていたのだが……罠が。
うちの設定ではセキュリティを重視するために、
net.inet.tcp.blackhole=2
とやって、知らないパケットをシカトする設定にしている。
で、何が起きるかというと、rubyのDBIでconnectを呼び出すと、synを送って……待つ。そしてタイムアウトして500 Internal Server Errorになってしまうのだ! 例外投げてよ!!(笑)TCPの3hand-shake失敗したら500になるのかよ!!
……というか、これは困った。マジで困った。
最初に考えた案として、mysqlと同じポートに「コネクションを受け付けない」サーバを一時的に(バックアップ中のみ)立ち上げれば良いんじゃないかというアイディア。
しかし、これはmysqlを再起動する時に悪さをする可能性がある。
うーん、なんか良い方法無いかなぁ……と思い、「結局はrstパケットなりポート到達不能パケットなり、エラーだぜ!ってパケットを返せば良いんだよね~」と思い立つ(笑)
どうやるか。
ipfwの機能として、
reject
パケットを捨てます。ICMP ホスト / ポート到達不能パケットを (適切な方を) 発信元へ送ります。
(ファイアウォールより)
こんなのがある。
んで、ipfwは標準動作(?)ではipfwのindex値(エントリー番号?)は100から始まる。
というわけで、mysqlを止める前に、
/sbin/ipfw add 10 reject tcp アクセス元のIP to アクセス先のIP アクセス先のポート via lo0
として、OSレベルで弾く設定をする。
んで、mysqlを止めて、スナップショットを取って、mysqlを再起動した後に
/sbin/ipfw delete 10
とすれば、またアクセスできるようになる。
これでめでたく(?)mysqlが止まっている30秒間だけは、mysqlにアクセスしようとするとrejectされて、例外が投げられ、無事(?)「ごめんメンテ(バックアップ)中。30秒ほど待ってリロードしてね!」という画面になる(笑)
あー、なんでこんな微妙な所をいじってるんだろう、ワシは(笑)
その30秒間にアクセスに来る人間なんて……いるのか!?(笑)
欠点:サーチエンジンが「偶然」その30秒間にクロールをかますと、非常に面白い結果になると思われる(笑)
追記:→回避策
ちゃんとHTTPのステータスコードをエラーで返せば良いんじゃないかと思いつく。
nphなんて方法を一瞬考えたが、面倒すぎる(笑)
どうしようか悩んでると、カスタムエラーレスポンスとリダイレクトというページに、
それを起動することになったエラーの状態を クライアントまで確実に伝えるために "Status:" ヘッダを含むべきです。
という記述が。どうやらヘッダ内でStatus: ほげほげ\nって出力するとそのエラーコードになる模様。
というわけで、早速テスト
rescue DBI::DatabaseError => e
# DB error...
print "Status: 503 Service Unavailable\n"
if (e.err == 2003) then
print文でStatus 503を返す様に変更。
ブラウザで見てみる。わかんねー!(笑)
telnetで直接叩く。おぉ、ホントだ503って返ってきてる。ログにも503って残った。
これでよし、と。
同じような理由でrescue Exceptionの時には500を返す様に変更
rescue Exception
print "Status: 500 Internal Server Error\n"
if @cgi then
いるだろぅ?
◆ [ネタ] ニコ動、2次創作OKで新作映画を公開
さて、どう動く…(笑)
◆ [ネタ] 「ヤンデレオンリー 病み鍋PARTY2 11/11都産貿台東館にてnice boat.」
そういえばおとボクオンリーと同じ日で同じ会場ですな。暇があったら行ってこよう。
『病みキャラランキング』があり、1位桂言葉(School Days)・2位芙蓉楓(SHUFFLE!)・3位竜宮レナ(ひぐらしのなく頃に)&我妻由乃(未来日記)
さすがは言葉さま。
◆ [ネタ] フィギュア専門店にも初音ミク
もはや何でもありありですな(笑)
◆ [ネタ] 「初音ミク=ネギ、鏡音リン=たくあん」か?
タイトルで噴いて、内容で再度噴いたわ!(笑)
◆ [ネタ] 涼宮ハルヒの憂鬱の映像でアニメ「CLANNAD」OPを作る→ニコニコ動画(RC2)‐【MAD】HARUNAD ハルナド
なかなか良かったので紹介。
◆ [ネタ] 手乗りタイガーを掲げた逢坂大河が手乗りサイズで登場
だああぁあーーーーーー 見かけたら買ってしまいそうだだだだだーー
◆ [ネタ] ニコニコ動画の午前0時の時報に初音ミクが登場していた
うむ、これは良いモノだ(笑)
◆ [情報] MIAU、DL違法化反対パブコメ最終案と、パブコメジェネレータを公開
今こそ声を大にして、思っている事を言うのだ。