CGI の高負荷で、CGI 止められたら困るので、何とかして 訪問者の方には静的 HTML にアクセスして欲しい。
静的 HTML と言ってまず思い浮かぶのが squeeze.rb なのだが、 squeeze.rb が吐き出す HTML は元々は namazu のインデックス用に 作られたものなので、訪問者の方々に見せるにはちょっと不満がある。 というわけで、 squeeze.rb とはちょっと違った 静的 HTML 化を「超」場当たり的にやってみた。
以下のような動的な機能は全て失われてしまうが、 xrea の負荷制限にひっかかって見られなくなるよりはマシだろう。
これぐらいは全然困らんよね?元々、私の blog の方はリファラの表示 しないようにしてたし。
以下のような機能はちゃんと動く。
実装の基本方針は以下。
キャッシュ置場を仮に
/virtual/tmaeda/public_html/cache
とする。
古くてすんません、tdiary 1.5.6 向けですが、 キモは mod_rewrite なので、この方針は 2.0.0 などにも適用できるでしょう。
(nph-)index.rb で最終的な HTML 出力をやっている箇所
head['cookie'] = tdiary.cookies if tdiary.cookies.size > 0 print @cgi.header( head ) print body
の直前に、以下のようなキャッシュ書きだしのコードを追加。 単純に body をファイルにも出力するだけ。
if @cgi.valid?( 'date' ) then
if /^\d{8}$/ =~ @cgi['date'] then
File.open("/virtual/tmaeda/public_html/cache/#{@cgi['date']}.html", "w") {|f|
f.write body
File.open("/virtual/tmaeda/log/cache.log", "a+") {|f|
f.write "#{Time.now} static cache written(#{@cgi['date']}.html).\n"
}
}
end
end
同じく、 (nph-)index.rb のだいぶ上の方、
if @cgi.valid?( 'comment' ) then tdiary = TDiary::TDiaryComment::new( @cgi, "day.rhtml", conf ) elsif @cgi.valid?( 'date' )
の
tdiary = TDiary::TDiaryComment::new( @cgi, "day.rhtml", conf )
の直前に、以下のようなキャッシュ削除のコードを追加。
date_string = @cgi['date']
cache = "/virtual/tmaeda/public_html/cache/#{date_string}.html"
if FileTest.exist?(cache) then
File.delete(cache)
File.open("/virtual/tmaeda/log/cache.log", "a+") {|f|
f.write "#{Time.now} static cache cleared(#{date_string}.html).\n"
}
end
今度は update.rb をいじる。
まずは頭の
BEGIN { $defout.binmode }
の直下に、キャッシュを削除する関数を追加。
def delete_cache(cgi)
date_string = sprintf("%04d%02d%02d", cgi['year'], cgi['month'], cgi['day'])
cache = "/virtual/tmaeda/public_html/cache/#{date_string}.html"
if FileTest.exist?(cache) then
File.delete(cache)
File.open("/virtual/tmaeda/log/cache.log", "a+") {|f|
f.write "#{Time.now} static cache cleared(#{date_string}.html).\n"
}
end
end
あとは、これを処理を分岐させている if ... elsif ... の中の 何か所からか呼び出す。 append, edit, replace, comment のモードのときだけ呼び出せば 十分だと思う。
if @cgi.valid?( 'append' ) delete_cache(@cgi) # 追加 tdiary = TDiary::TDiaryAppend::new( @cgi, 'show.rhtml', conf ) elsif @cgi.valid?( 'edit' ) delete_cache(@cgi) # 追加 tdiary = TDiary::TDiaryEdit::new( @cgi, 'update.rhtml', conf ) elsif @cgi.valid?( 'replace' ) delete_cache(@cgi) # 追加 tdiary = TDiary::TDiaryReplace::new( @cgi, 'show.rhtml', conf ) elsif @cgi.valid?( 'appendpreview' ) or @cgi.valid?( 'replacepreview' ) ...(スッ飛ばして、次は comment) elsif @cgi.valid?( 'comment' ) delete_cache(@cgi) # 追加 tdiary = TDiary::TDiaryShowComment::new( @cgi, 'update.rhtml', conf )
かなり恥ずかしいコードだが、場当たり対応なので良いことにする。
元々はこんな感じの設定を .htaccess に書いていた。
RewriteRule ^([0-9]+)\.html$ nph-index.rb?date=$1
私の場合、アクセスの多い 20041101.html だけを キャッシュ転送の対象にしたいので、以下のように変更する。
RewriteCond %{REQUEST_URI} ^\/(20041101\.html$)
RewriteCond /virtual/tmaeda/public_html/cache/%1 -f
RewriteRule .* /virtual/tmaeda/public_html/cache/%1 [L]
RewriteRule ^([0-9]+)\.html$ nph-index.rb?date=$1
もし全部の記事をキャッシュに転送したいのであれば、 こんな感じに書くと良いだろう。
RewriteCond %{REQUEST_URI} ^\/([0-9]+\.html$)
RewriteCond /virtual/tmaeda/public_html/cache/%1 -f
RewriteRule .* /virtual/tmaeda/public_html/cache/%1 [L]
RewriteRule ^([0-9]+)\.html$ nph-index.rb?date=$1
以上。
台風がやんだら、今回追加した RewriteCond/RewriteRule を 消すだけで済むし(まぁ、表示の度に 毎回キャッシュに書き出すのはウザいけど)、また別のページに台風が 来たら RewriteCond のルールを追加するだけで良い。
欲を言えば、「index.rb がエラーを返したらキャッシュに転送する」 ってのができると最高なんだけどな〜。ごく稀に原因不明の Ruby の エラー([BUG] unknown node type 0 だか何だか)が出て 何度リロードしても表示されなくなることがあるので。
場当たり対応にしてはなかなか良いかもしれない。 「いつ CGI 止められるかわからない」という不安から開放され、 精神衛生上かなりよろしい。正直、「カウンタが回らない」なんてのは 「本文が表示されない」のに比べればどーでも良い問題だし (どうしても必要ならカウンタだけ別 CGI にする方法だってある)、 全てのページでこの挙動をデフォルトにしてしまおうかと 思っているぐらいだ。
その後の話。
効果絶大。
アクセス数は前日と同じぐらいだったけど、 負荷率は(xrea で禁止されてるので具体的な数値については伏せますが) 今までの平常時と同じレベルに戻りました。 20041101.html への負荷が事実上ゼロになるので当り前っちゃー当り前ですが。
これでどこからリンク張られても恐いもの無し。
コメントの「名前」欄や「E-mail」欄に最後にコメントを 投稿した人(正確にはキャッシュを作る際にアクセスしてきた人)の クッキーの情報が入った状態でキャッシュが生成されてしまうので、 デフォルト値として赤の他人の名前/E-Mailが入った状態で表示されてしまう ことになる。どーしたもんか、、、
すぐに思い付く方法としては、 「skel/dairy.rhtml でクッキーの値を入れないようにする」って方法だけど、 これじゃキャッシュの対象にしていないページの挙動にも影響が出ちゃうなぁ。 まぁ、コメント投稿する機会なんてそんなに頻繁ではないので、 これぐらい良いっちゃー良いか、、、
確かに入ってますね
小林さん。えーと、何が入ってますか?(^^;<br>名前とEmailの話ですか?<br>名前とEmail欄が自動で入らないようにしてるのは、<br>tmaeda.s45.xrea.com/ の方だけで tmaeda.s45.xrea.com/td/<br>の方は、(負荷対策をしてないので)前回のコメント時の名前とEmailが<br>自動で入るようにしてます(というから元々そうなっているのを<br>そのまま利用しているだけです)。<br><br>tmaeda.s45.xrea.com/20041101.html 等では、自動で他人の名前が入ってないはずですけど、、、入ってます?