<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>cyano &#187; Apache</title>
	<atom:link href="http://www.onflow.jp/cyano/archives/category/apache/feed" rel="self" type="application/rss+xml" />
	<link>http://www.onflow.jp/cyano</link>
	<description>Just another WordPress site</description>
	<lastBuildDate>Sat, 24 Dec 2011 09:24:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Software Design 2007年 09月号にmod_rewrite活用テクニックを書きました</title>
		<link>http://www.onflow.jp/cyano/archives/156?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=software-design-2007%25e5%25b9%25b4-09%25e6%259c%2588%25e5%258f%25b7%25e3%2581%25abmod_rewrite%25e6%25b4%25bb%25e7%2594%25a8%25e3%2583%2586%25e3%2582%25af%25e3%2583%258b%25e3%2583%2583%25e3%2582%25af%25e3%2582%2592%25e6%259b%25b8%25e3%2581%258d%25e3%2581%25be%25e3%2581%2597%25e3%2581%259f</link>
		<comments>http://www.onflow.jp/cyano/archives/156#comments</comments>
		<pubDate>Thu, 23 Aug 2007 02:08:54 +0000</pubDate>
		<dc:creator>ksakai</dc:creator>
				<category><![CDATA[Apache]]></category>

		<guid isPermaLink="false">http://www.onflow.jp/kleio/2007/08/software-design-2007%e5%b9%b4-09%e6%9c%88%e5%8f%b7%e3%81%abmod_rewrite%e6%b4%bb%e7%94%a8%e3%83%86%e3%82%af%e3%83%8b%e3%83%83%e3%82%af%e3%82%92%e6%9b%b8%e3%81%8d%e3%81%be%e3%81%97%e3%81%9f/</guid>
		<description><![CDATA[
 <a href="http://www.onflow.jp/cyano/archives/156">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.amazon.co.jp/gp/redirect.html?ie=UTF8&#038;location=http%3A%2F%2Fwww.amazon.co.jp%2FSoftware-Design-%25E3%2582%25BD%25E3%2583%2595%25E3%2583%2588%25E3%2582%25A6%25E3%2582%25A8%25E3%2582%25A2-%25E3%2583%2587%25E3%2582%25B6%25E3%2582%25A4%25E3%2583%25B3-2007%25E5%25B9%25B4%2Fdp%2FB000UE0HPY%2F&#038;tag=11922964-22&#038;linkCode=ur2&#038;camp=247&#038;creative=1211">Software Design 2007年 09月号</a>にmod_rewrite活用テクニックを書きました。</p>
<p>公式ドキュメントでも黒魔術などと称されている悪名高いモジュールmod_rewriteですが、要は設定例や内部でどのように動くかが解説されていないためによくわからないモジュールとされているだけであって、それらを理解してしまえば普通に使いこなすことができるようになります。</p>
<p>例えば以下のことを知らないような人向けに書いてみました。</p>
<p><span id="more-156"></span></p>
<ul>
<li>RewriteRuleディレクティブに渡される（RewriteRuleディレクティブで評価される）URLが、RewriteRuleディレクティブをどこに書くか（httpd.confか.htaccessかなど）によって違う</li>
<li>RewriteBaseディレクティブはなんのためにあるのかよくわからない</li>
<li>RewriteCondで使える変数に何があるか、そしてそれらの変数が何を指すのかわからない</li>
<li>RewriteRuleの第三引数の各種フラグ（LとかNとかPとかQSAとか）がよくわからない</li>
</ul>
<p>また設定例として、携帯からのアクセスを特定のURLに振り向ける、拡張子が.htmlから.phpに変わった場合でもリンク切れを起こさない方法、DNSを用いない簡易的なラウンドロビン、特定のファイル名のファイルをアップロードするだけで素早くメンテナンス画面に切り替えられるようにする、Amazon風のURLを実現する方法などを挙げてみました。</p>
<p>さらに、<a href="http://www.gihyo.co.jp/magazines/wdpress">WEB+DB press</a> Vol.38「RESTレシピ」などでも連載が始まって注目されているRESTなどとも絡めて、mod_rewriteを使ってURLをRESTful（REST準拠な）URLにするためのテクニックにも軽く触れています。</p>
<p>正規表現の解説も2ページほど付けましたので、mod_rewriteで多用する正規表現が苦手という方にもオススメです。</p>
<p><iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=11922964-22&#038;o=9&#038;p=8&#038;l=as1&#038;asins=B000UE0HPY&#038;fc1=000000&#038;IS2=1&#038;lt1=_blank&#038;lc1=0000FF&#038;bc1=000000&#038;bg1=FFFFFF&#038;f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://www.onflow.jp/cyano/archives/156/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavaScriptやCSSを動的にdeflate圧縮するのではなく、あらかじめ圧縮しておいたものを配信することでサーバーのCPUリソースを節約する</title>
		<link>http://www.onflow.jp/cyano/archives/141?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=javascript%25e3%2582%2584css%25e3%2582%2592%25e5%258b%2595%25e7%259a%2584%25e3%2581%25abdeflate%25e5%259c%25a7%25e7%25b8%25ae%25e3%2581%2599%25e3%2582%258b%25e3%2581%25ae%25e3%2581%25a7%25e3%2581%25af%25e3%2581%25aa%25e3%2581%258f%25e3%2580%2581%25e3%2581%2582%25e3%2582%2589%25e3%2581%258b%25e3%2581%2598%25e3%2582%2581</link>
		<comments>http://www.onflow.jp/cyano/archives/141#comments</comments>
		<pubDate>Sun, 10 Jun 2007 21:12:16 +0000</pubDate>
		<dc:creator>ksakai</dc:creator>
				<category><![CDATA[Apache]]></category>

		<guid isPermaLink="false">http://www.onflow.jp/kleio/2007/06/javascript%e3%82%84css%e3%82%92%e5%8b%95%e7%9a%84%e3%81%abdeflate%e5%9c%a7%e7%b8%ae%e3%81%99%e3%82%8b%e3%81%ae%e3%81%a7%e3%81%af%e3%81%aa%e3%81%8f%e3%80%81%e3%81%82%e3%82%89%e3%81%8b%e3%81%98%e3%82%81/</guid>
		<description><![CDATA[
 <a href="http://www.onflow.jp/cyano/archives/141">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://asiamoth.com/mt/archives/2006-11/16_2331.php">prototype.jsを10KBにする方法</a>や<a href="http://d.hatena.ne.jp/odz/20061120/1164089177">Safari と gzip 圧縮 JavaScript</a>などですでに述べられてることですが、mod_deflateでリクエストがある度にアセット（CSSやJavaScript）にdeflate圧縮をかけるのは、deflate処理が軽いからと言っても、塵も積もれば馬鹿にならない（WWWサーバーやAPサーバーに本来使って欲しいCPUリソースを蝕む）訳で、deflateしたいアセットには予めgzip圧縮してそれを配信し、サーバーのCPUリソースに優しいようにしましょう、というお話。</p>
<p><span id="more-141"></span></p>
<p>今回は、予めgzip圧縮するという作業を自動化するために、Railsでよく使われるデプロイツールである<a href="http://www.capify.org/">Capistrano</a>を利用します。</p>
<p>基本的な方針としては、(1)ローカルの開発環境上ではCSSやJavaScriptは非圧縮（編集しやすいように）、(2)サーバー上にデプロイされたCSSやJavaScriptにはgzip圧縮をかける（帯域削減のため）、(3)非圧縮CSSや非圧縮JavaScriptをサーバー上にも置いておく（gzip対応してないブラウザ向け）、という3点です。</p>
<p>例えば(1)の例は/asets/js/prototype.js（非圧縮）、(2)の例は/asets/js/prototype.js（gzip圧縮済み）、(3)の例は/asets/js/prototype.js.ungz（非圧縮）と言った感じ。ここで(1)と(2)のファイル名を揃えているのは楽をするため。つまりローカル開発環境とサーバー上でファイル名が異なってると、いちいちscriptタグを書き換えるのがめんどくさいのです。</p>
<p>さて、上で述べたようにサーバー上にデプロイされたアセットをgzip圧縮するCapistranoのタスクは以下の通り。これは<code>#{current_path}</code>に最新リリースがデプロイされた後に実行されるコードです。:updateタスクの中で実行されるようにしておくと良いでしょう。</p>
<pre>desc &lt;&lt;-DESC
Updates the code and fixes the symlink under a transaction
DESC
task :update do
transaction do
update_code
compress_assets
end
end

desc "Compress assets"
task :compress_assets do
run "find #{current_path}/public/assets/ -name '*.js' -exec gzip {} \;"
run "find #{current_path}/public/assets/ -name '*.css' -exec gzip {} \;"
run "cd #{current_path}/public/assets/js;for i in *;do mv $i ${i%.js.gz}.js;done"
run "cd #{current_path}/public/assets/css;for i in *;do mv $i ${i%.css.gz}.css;done"
run "cd #{current_path}/public/assets/js;for i in *;do gzip -dc $i >$i.ungz;done"
run "cd #{current_path}/public/assets/css;for i in *;do gzip -dc $i >$i.ungz;done"
end</pre>
<p>いちおう説明しておくと、findの2行で/public/assets/配下のJavaScriptファイルやCSSファイルにgzip圧縮をしています。次の2行は、gzip圧縮をかけると例えば名前がprototype.js.gzと変わってしまうので、prototype.jsに戻しています。最後の2行は圧縮後のprototype.jsを解凍し、prototype.js.ungzというファイルを作る部分です。</p>
<p>そうすると、/assets/jsの中身は以下のようになります。</p>
<pre>-/assets/js/
|
|-prototype.js（gzip圧縮済み）
|-prototype.js.ungz（非圧縮）</pre>
<p>さて、これをApacheのディレクティブを活用して配信するわけです。方針はgzip受け取れるブラウザはprototype.jsをそのまま受け取る、gzipを受け取れないブラウザやgzip扱いにバグありブラウザはprototype.js.ungzを受け取る、というもの。</p>
<pre>&lt;Directory /home/httpd/vhosts/example.jp/current/public/assets&gt;
&lt;Files ~ ".(css|js)$"&gt;
SetEnvIf Accept-Encoding "gzip" can_compress_assets
# Netscape 4.x has some problems...
BrowserMatch ^Mozilla/4 !can_compress_assets
# Netscape 4.06-4.08 have some more problems
BrowserMatch ^Mozilla/4.0[678] !can_compress_assets
# MSIE masquerades as Netscape, but it is fine
BrowserMatch bMSIE can_compress_assets

RewriteCond {%ENV:can_compress_assets} !1
RewriteRule ^(.+)(.css|.js)$ $1$2.ungz [L,QSA]
Header set Content-Encoding: gzip env=can_compress_assets
&lt;/Files&gt;
&lt;/Directory&gt;</pre>
<p>説明。まず<code>SetEnvIf Accept-Encoding &quot;gzip&quot;</code>でHTTPリクエストヘッダの中に<code>Accept-Encoding: gzip</code>があれば、圧縮できる（<code>can_compress_assets</code>）という環境変数を立てます。その後、BrowserMatchでごにょごにょやってるのは、一部ブラウザでgzipの扱いに問題があるため、問題があるブラウザはgzipしてないコンテンツをサーブする（<code>!can_compress_assets</code>）ようにします。</p>
<p>次のRewriteCond、RewriteRuleは環境変数<code>can_compress_assets</code>がセットされていなかった場合（非圧縮コンテンツを返すべき場合）、例えばprototype.jsがリクエストされたら、非圧縮のprototype.js.ungzを代わりに返すというものです。</p>
<p>最後の<code>Header set Content-Encoding: gzip env=can_compress_assets</code>は、圧縮されたコンテンツを返している場合、HTTPレスポンスヘッダに<code>Content-Encoding: gzip</code>を追加するというものです。こうしないとブラウザは返されたコンテンツがgzipされていることを知らないため、解凍してくれません。</p>
<p><code>Content-Encoding: gzipを付けるならAddType gzip .js</code>でいいじゃないか、という意見が聞こえてきますが、その場合、上の非圧縮コンテンツを返している際も<code>HTTPレスポンスヘッダにContent-Encoding: gzip</code>が付いてしまい、ブラウザが圧縮されてないものを解凍しようとして混乱してしまいます。</p>
<p>CSSファイルやJavaScriptファイルはサイト内で数十になることも多く、それが数千万回リクエストされるとなると、それらのdeflate処理にかかっていたコストは馬鹿に出来なくなります。こうして予めgzip圧縮しておくことで、それらのコストを削減し、少しでも地球に優しくしようという試みでした。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.onflow.jp/cyano/archives/141/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mod_expiresとmod_rewriteを使ってサイトの帯域節約と体感速度を向上させる方法</title>
		<link>http://www.onflow.jp/cyano/archives/140?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=mod_expires%25e3%2581%25a8mod_rewrite%25e3%2582%2592%25e4%25bd%25bf%25e3%2581%25a3%25e3%2581%25a6%25e3%2582%25b5%25e3%2582%25a4%25e3%2583%2588%25e3%2581%25ae%25e5%25b8%25af%25e5%259f%259f%25e7%25af%2580%25e7%25b4%2584%25e3%2581%25a8%25e4%25bd%2593%25e6%2584%259f%25e9%2580%259f%25e5%25ba%25a6%25e3%2582%2592</link>
		<comments>http://www.onflow.jp/cyano/archives/140#comments</comments>
		<pubDate>Sat, 09 Jun 2007 09:23:35 +0000</pubDate>
		<dc:creator>ksakai</dc:creator>
				<category><![CDATA[Apache]]></category>

		<guid isPermaLink="false">http://www.onflow.jp/kleio/2007/06/mod_expires%e3%81%a8mod_rewrite%e3%82%92%e4%bd%bf%e3%81%a3%e3%81%a6%e3%82%b5%e3%82%a4%e3%83%88%e3%81%ae%e5%b8%af%e5%9f%9f%e7%af%80%e7%b4%84%e3%81%a8%e4%bd%93%e6%84%9f%e9%80%9f%e5%ba%a6%e3%82%92/</guid>
		<description><![CDATA[
 <a href="http://www.onflow.jp/cyano/archives/140">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>普通の帯域節約術としては、mod_deflateでdeflate圧縮するとか、CSSやJSファイルのHTTPレスポンスヘッダにLast-ModifiedやEtagを追加しておいて、ブラウザがHTTPリクエストヘッダにIf-Modified-SinceやIf-None-Matchを付加するようにし、コンテンツが変更されていなかったら304 Not Modifiedを返すという方法を取るかと思います。</p>
<p>しかし、HTTPサーバーはコンテンツの数だけ304 Not Modifiedを返さないといけないため、その分帯域を消費しますし、またCSSや画像などのパーツの304 Not Modifiedが返ってくるまで、そのパーツのレンダリングが行えないという問題があります（つまり体感速度に影響します）。</p>
<p>今回紹介するのは<code>Expires</code>ヘッダや<code>Cache-Control: max-age=31536000</code>を活用して、<strong>CSSやJSなどのファイルをリクエストする際、それらのファイルが変更されない限り、If-Modified-Sinceなどのリクエストをそもそも発生させなくする</strong>方法です。</p>
<p><span id="more-140"></span></p>
<p>まず、Expiresヘッダの説明。これは、このHTTPレスポンスで返されたコンテンツの有効期限を指定するものです。例えば<code>Expires: Sun, 08 Jun 2008 07:07:37 GMT</code>と返ってくると、その日が訪れるまでブラウザはキャッシュの中身のものを使い続けます。つまり、Expiresで指定した日が訪れるまでIf-Modified-Sinceなどのリクエストをしなくなります。</p>
<p><code>Cache-Control: max-age=31536000</code>の方は、31536000秒（365日）間はそのコンテンツが有効であると判断されます。つまり31536000秒間はブラウザのキャッシュから読み続けることになり、Expiresと同様にIf-Modified-Sinceなどのリクエストをしなくなります。</p>
<p>Apacheで<code>Expires</code>ヘッダや<code>Cache-Control: max-age=31536000</code>を付加させるディレクティブは以下の通り（この例では1年後が有効期限に来るように設定しています）。</p>
<pre>ExpiresActive On
ExpiresDefault "access plus 1 year"</pre>
<p>ちなみに、<a href="http://www.ietf.org/rfc/rfc2068.txt">RFC2068</a>の14.21節によれば、HTTP/1.1サーバーは有効期限として「無期限」を指定したい場合は、「ちょうど1年後をExipresに指定すべき」とあり、また「HTTP/1.1サーバーは有効期限として1年以上を返すべきでない」とされています。</p>
<p>さて、こうしてExpiresヘッダを指定してしまうと、CSSなどを変更したときに、（ファイル名が同じである限り）Expiresで設定した有効期限が訪れるまでブラウザが新しいものを読みに行ってくれなくなるという問題が発生します。これを解決するのがmod_rewrite。</p>
<p>ここでのミソは<strong>ファイル名が同じである限りキャッシュから読み続ける</strong>ということ。つまりファイル名さえ変えてしまえば、新しいファイルとして取得してきてくれるわけです。</p>
<p>しかしながら、CSSの変更を加える度に毎回linkタグで読み込むCSSのファイル名を変えるのはものすごく手間がかかります。そこで、ファイルにバージョン名を含ませる（/assets/css/base.<span style="color:#FF0000">v20070609</span>.css）のだけれど、実体は/assets/css/base.cssを読むようにすることが出来るのがmod_rewrite。その設定方法は以下の通り。</p>
<pre>&lt;Directory /home/httpd/vhosts/example.jp/current/public/assets&gt;
RewriteEngine on

RewriteRule ^(.*?).vd+.(.*)$ $1.$2 [QSA,L]
&lt;/Directory&gt;</pre>
<p>こうすることで、実体の/assets/css/base.cssを更新したときに、<br />
<code>&lt;link href=&quot;/assets/css/base.<span style="color:#FF0000">v20070609</span>.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;</code><br />
から<br />
<code>&lt;link href=&quot;/assets/css/base.<span style="color:#FF0000">v20070610</span>.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;</code><br />
に変更すれば、ブラウザは変更後のファイルを読みに行ってくれます。</p>
<p>さて、これは応用編になりますが、RailsアプリなどでCapistranoを使うと、サイトが以下のようなファイル構成になります。
</p>
<pre>---current -&gt;(20070609071925へのシンボリックリンク)
|
|-releases/
|-20070609071925/
|   |-public/
|       |-index.cfm
|       |-assets/
|           |
|           |-css/
|           |  |
|           |  |-reset.css
|           |  |-base.css
|           |
|           |-js/
|              |
|              |-protopype.js
|
|-20070609065605/</pre>
<p>つまり、releases以下にリリースされたサイトが蓄積され、currentから最新版のリリースディレクトリへシンボリックリンクが張られている状態になります。</p>
<p>ここで、releases以下のディレクトリ名がユニーク（ぶつからない）ことを利用して、上のmod_rewriteのソリューションを使うことが出来ます。</p>
<p>つまり、アプリケーションロジックでcurrentシンボリックリンクのリンク先をresolveして（20070609071925などというディレクトリ名を取得し）、CSS読み込みタグをアプリケーションで下記のように動的に書き出す<br />
<code>&lt;link href=&quot;/assets/css/base.<span style="color:#FF0000">v(リリースディレクトリ名)</span>.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;</code><br />
ことで、Capistranoでサイトをリリースするたびに、自動で新しいCSSが読み込まれるようになります。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.onflow.jp/cyano/archives/140/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Apache 2.2 mod_filterを使いこなす &#8211; AddOutputFilterByType DEFLATE text/htmlを書き換えてみる</title>
		<link>http://www.onflow.jp/cyano/archives/137?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=apache-22-mod_filter%25e3%2582%2592%25e4%25bd%25bf%25e3%2581%2584%25e3%2581%2593%25e3%2581%25aa%25e3%2581%2599-addoutputfilterbytype-deflate-texthtml%25e3%2582%2592%25e6%259b%25b8%25e3%2581%258d%25e6%258f%259b%25e3%2581%2588%25e3%2581%25a6%25e3%2581%25bf%25e3%2582%258b</link>
		<comments>http://www.onflow.jp/cyano/archives/137#comments</comments>
		<pubDate>Mon, 28 May 2007 05:41:33 +0000</pubDate>
		<dc:creator>ksakai</dc:creator>
				<category><![CDATA[Apache]]></category>
		<category><![CDATA[mod_deflate]]></category>
		<category><![CDATA[mod_filter]]></category>

		<guid isPermaLink="false">http://www.onflow.jp/kleio/2007/05/apache-22-mod_filter%e3%82%92%e4%bd%bf%e3%81%84%e3%81%93%e3%81%aa%e3%81%99-addoutputfilterbytype-deflate-texthtml%e3%82%92%e6%9b%b8%e3%81%8d%e6%8f%9b%e3%81%88%e3%81%a6%e3%81%bf%e3%82%8b/</guid>
		<description><![CDATA[
 <a href="http://www.onflow.jp/cyano/archives/137">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>ApacheにはコンテンツのMIME-typeに応じてフィルターをかけるAddOutputFilterByTypeディレクティブがありますが、<a href="http://httpd.apache.org/docs/2.2/ja/mod/core.html#addoutputfilterbytype" title="AddOutputFilterByType ディレクティブ">Apache 2.1 以降で非推奨になり</a>、代わりに<a href="http://httpd.apache.org/docs/2.2/ja/mod/mod_filter.html">mod_filter</a>でフィルターをかけることが勧められているようです。</p>
<p>しかしながら、mod_filterの実例があまりにも少ないため、どう使っていいか分からないのが現状です。なので、AddOutputFilterByType DEFLATE text/htmlを書き換えてみることにしました。</p>
<p><span id="more-137"></span></p>
<p><a href="http://httpd.apache.org/docs/2.2/ja/mod/mod_deflate.html">mod_deflate</a>のドキュメントには、実例として画像以外をすべて圧縮する方法が以下のように書かれています。</p>
<pre>&lt;Location /&gt;
# Insert filter
SetOutputFilter DEFLATE

# Netscape 4.x has some problems...
BrowserMatch ^Mozilla/4 gzip-only-text/html

# Netscape 4.06-4.08 have some more problems
BrowserMatch ^Mozilla/4.0[678] no-gzip

# MSIE masquerades as Netscape, but it is fine
# BrowserMatch bMSIE !no-gzip !gzip-only-text/html

# NOTE: Due to a bug in mod_setenvif up to Apache 2.0.48
# the above regex won't work. You can use the following
# workaround to get the desired effect:
BrowserMatch bMSI[E] !no-gzip !gzip-only-text/html

# Don't compress images
SetEnvIfNoCase Request_URI
.(?:gif|jpe?g|png)$ no-gzip dont-vary

# Make sure proxies don't deliver the wrong content
Header append Vary User-Agent env=!dont-vary
&lt;/Location&gt;</pre>
<p>これをベースにMIME-typeがtext/*、application/xhtml、application/xmlの場合、deflateするようにしたものが以下になります。</p>
<pre>&lt;Location /&gt;
# Netscape 4.x has some problems...
BrowserMatch ^Mozilla/4 gzip-only-text/html

# Netscape 4.06-4.08 have some more problems
BrowserMatch ^Mozilla/4.0[678] no-gzip

# MSIE masquerades as Netscape, but it is fine
BrowserMatch bMSIE !no-gzip !gzip-only-text/html

# ここからフィルター設定
FilterDeclare Compression CONTENT_SET
FilterProvider Compression DEFLATE Content-Type $text/plain
FilterProvider Compression DEFLATE Content-Type $text/css
FilterProvider Compression DEFLATE Content-Type $application/xhtml
FilterProvider Compression DEFLATE Content-Type $application/xml
FilterProvider Compression DEFLATE Content-Type $application/xhtml+xml
FilterProvider Compression DEFLATE Content-Type $application/rss+xml
FilterProvider Compression DEFLATE Content-Type $application/atom+xml
FilterProvider Compression DEFLATE Content-Type $application/x-javascript
FilterProvider Compression DEFLATE Content-Type $image/svg+xml
FilterChain Compression
# ここまでフィルター設定

# Don't append Vary heder for specific files
SetEnvIfNoCase Request_URI .(?:gif|jpe?g|png|zip|lzh|exe)$ dont-vary

# Make sure proxies don't deliver the wrong content
Header append Vary User-Agent env=!dont-vary
Header append Vary Accept-Encoding env=!dont-vary
&lt;/Location&gt;</pre>
<p>まず、FilterDeclareディレクティブでCompressionという名前のフィルター群のタイプがCONTENT_SETであると宣言します（これはなぜそうする必要があるのかよく分からないので教えてください）。</p>
<p>次にFilterProviderディレクティブでCompressionフィルター群にフィルターを追加しています。FilterProviderディレクティブの第一引数はフィルター群に付ける名前（今回はCompression）、第二引数はフィルターのプロバイダー名です。mod_deflateモジュールを読み込むと、ap_register_output_filter関数でDEFLATEというプロバイダー名が自動的に登録されます（そのプロバイダーがdeflateを行います）。第三引数（Content-type $text/plain）はフィルターを実行する条件を指定するもので、今回はHTTPレスポンスヘッダのContent-typeがtext/plainに部分一致した場合のみ、フィルターを実行するという条件をつけています。</p>
<p>最後のFilterChainディレクティブでCompressionフィルター群がApacheのリクエストを通じて呼び出されるようにします（つまりFilterChainディレクティブを使わないと、定義されたフィルター群は実行されません）。</p>
<p>ここで気になるのが、BrowserMatchディレクティブで環境変数に設定したno-gzipやgzip-only-text/htmlがフィルター実行の条件の絞込み（FilterProviderディレクティブの第三引数）に使われていないということです。実はこれらの環境変数はmod_deflateモジュール内で参照され、たとえばno-gzipが設定されていた場合は、自動的にフィルターが外れるようになっています。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.onflow.jp/cyano/archives/137/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>30万個ぐらいの静的ファイルを配信するサーバーの選び方</title>
		<link>http://www.onflow.jp/cyano/archives/112?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=30%25e4%25b8%2587%25e5%2580%258b%25e3%2581%2590%25e3%2582%2589%25e3%2581%2584%25e3%2581%25ae%25e9%259d%2599%25e7%259a%2584%25e3%2583%2595%25e3%2582%25a1%25e3%2582%25a4%25e3%2583%25ab%25e3%2582%2592%25e9%2585%258d%25e4%25bf%25a1%25e3%2581%2599%25e3%2582%258b%25e3%2582%25b5%25e3%2583%25bc%25e3%2583%2590%25e3%2583%25bc%25e3%2581%25ae</link>
		<comments>http://www.onflow.jp/cyano/archives/112#comments</comments>
		<pubDate>Wed, 26 Apr 2006 13:09:18 +0000</pubDate>
		<dc:creator>ksakai</dc:creator>
				<category><![CDATA[Apache]]></category>

		<guid isPermaLink="false">http://www.onflow.jp/kleio/2006/04/30%e4%b8%87%e5%80%8b%e3%81%90%e3%82%89%e3%81%84%e3%81%ae%e9%9d%99%e7%9a%84%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab%e3%82%92%e9%85%8d%e4%bf%a1%e3%81%99%e3%82%8b%e3%82%b5%e3%83%bc%e3%83%90%e3%83%bc%e3%81%ae/</guid>
		<description><![CDATA[
 <a href="http://www.onflow.jp/cyano/archives/112">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>naoyaさんが公開されてる<a href="http://d.hatena.ne.jp/naoya/20060404/1144121846">Inside Hatena Bookmark&#8217;s Backend の資料</a>などを読むと、mod_perlなサーバーやMySQLサーバーの選び方の参考になったりするわけですが、世の中を見渡してみても、静的コンテンツ（画像とか）を配信するサーバーの指南書らしきものはなかなか見あたりませんでした。</p>
<p>なので、経験を元に書いてみることにします。</p>
<p><span id="more-112"></span></p>
<p>弊社の画像配信サーバーには、平均10kbぐらい（たぶん）の画像が30万個ぐらいあって、それをDell PowerEdge 1750+<a href="http://www.lighttpd.net/">lighttpd</a>を使って配信してます。</p>
<p>以前は搭載メモリ1GBのサーバーを使っていたのですが、その時のvmstatがこのような感じ。</p>
<pre>procs -----------memory---------- ---swap-- -----io---- --system-- ----cpu---- r  b   swpd   free   buff  cache   si   so    bi    bo   in    cs us sy id wa 0  1  31368  55072 598708 119256    0    0   946     0 1573  1577  0  1 71 27 0  3  31368  54580 600728 119576    0    0  1184   682 1600  1521  0  1 71 27 0  2  31368  51168 603412 120012    0    0  1472     0 1646  1634  0  1 74 25 0  1  31368  48764 606928 120136    0    0  1794     0 1567  1299  0  1 75 25 0  1  31368  47280 608764 120120    0    0  1014   684 1608  1618  0  1 74 25 0  3  31368  47252 611056 120428    0    0  1212     6 1504  1283  0  1 74 25 0  1  31368  47656 613236 120328    0    0  1138   720 1487  1125  0  1 74 25 0  2  31368  46288 615728 120436    0    0  1286     0 1534  1382  0  1 73 26</pre>
<p>見て分かるのが、CPUのディスクI/O待ち（wa）が大きいこと。実際、画像が配信されてくるまで一呼吸置くぐらいあって、これはディスクI/Oがやばいんだろうなと思ってました。なので、ディスクを高速化しないといけないのかなぁ、と思っていたのですが、すでにSCSIでRAID5だしどうしたものかと思っていたのです。</p>
<p>しかし、Linuxにあるファイルキャッシュを使えばいいんじゃないと気付いたのです。Linuxは、『一度読み込んだファイルは再び読み込まれる可能性が高い』という前提の元、読み込んだファイルをメモリー上にキャッシュしておくのです（memory欄のcacheがファイルキャッシュに使われてるメモリー量）。ファイルキャッシュは空きメモリーの中からLinuxが勝手に確保してくれるので、メモリーを2GBに増設してみました。増設後のvmstatがこんな感じ。</p>
<pre>
procs -----------memory---------- ---swap-- -----io---- --system-- ----cpu----
r  b   swpd   free   buff  cache   si   so    bi    bo   in    cs us sy id wa
0  0    696  46956 235932 1457628    0    0    48  1512 2938  5197  1  4 94  1
2  0    696  47020 235932 1457628    0    0     0     0 3077  5451  1  5 94  0
0  1    696  46956 235932 1457628    0    0    68   756 3457  6351  2  6 91  1
1  0    696  46764 235932 1457628    0    0    28  6404 5446  7418  2  8 81  9
0  0    696  46828 235936 1457624    0    0    20     0 3653  6699  2  6 91  0
0  0    696  46636 235944 1457616    0    0    92  1504 3644  6701  2  7 89  2
0  0    696  46636 235948 1457872    0    0    48     0 3469  6373  2  7 91  1
0  0    696  46572 235964 1457856    0    0    32     0 3837  7359  2  7 90  1
0  0    696  46508 235980 1457840    0    0    48     0 3513  6718  2  7 90  1
0  0    696  46572 235980 1457840    0    0     0     0 3058  5742  1  5 93  0
0  0    696  46508 235980 1457840    0    0    36  1592 2834  4880  1  4 93  2
0  0    696  46508 235980 1457840    0    0    12     0 3379  6077  1  5 93  0
0  0    696  46508 235980 1457840    0    0     0     0 3159  5850  1  5 94  0</pre>
<p>ほとんどI/O待ちが発生していないことが分かります。つまり、よく読み込まれる画像はほとんどファイルキャッシュに入ってしまって、キャッシュから読み込んでいると言うことです（上に比べてbi(ディスクからの読み込み量)が少ないことからも分かります）。この対策をしたことで、サーバーから出て行く秒間のデータ量が約3倍ぐらいになりました（つまりディスクI/Oのボトルネックが解消し、画像配信速度が向上したと言うこと）。</p>
<p>そこで、導き出されるサーバーの選び方は以下のようになるのではないでしょうか。</p>
<table>
<tr>
<th scope="row">CPU</th>
<td>そこそこのもの<br />
弊社では3.0GHz*2で500req/sこなしてるときのロードアベレージが1.6とか</td>
</tr>
<tr>
<th scope="row">メモリ</th>
<td>
<p>配信すべきコンテンツ1つあたりの平均ファイルサイズ*よく読み込まれるコンテンツの数+500MB</p>
<p>500MBはカーネルとかHTTPDとかが消費するメモリ（おおよそです）</p>
</td>
</tr>
<tr>
<th scope="row">ディスク</th>
<td>SCSIでRAID1かRAID5（かな）</td>
</tr>
</table>
<p>ところで、なぜこのボトルネックに気付かなかったかというと、<a href="http://httpd.apache.org/docs/2.0/programs/ab.html">ab</a>や<a href="http://jakarta.apache.org/jmeter/">JMeter</a>で負荷テストをしていたからです。つまり、これらのベンチマークツールでは数十万個のファイルのランダムリクエストを擬似的に発生させることができなかったのであり（JMeterとかだとできるのかもしれないですけど調べてないです…）、リクエストしていたせいぜい数十個のファイルはファイルキャッシュに入ってしまっていたので、負荷テスト時にはディスクI/Oのボトルネックが表面化しなかったのです。</p>
<p>もしかするとまだまだ改善できるかもしれないので、つっこみとかお待ちしてます。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.onflow.jp/cyano/archives/112/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>HTTPSの認証ページから認証後、HTTPのページへセキュリティーの警告無しにリダイレクトする方法</title>
		<link>http://www.onflow.jp/cyano/archives/110?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=https%25e3%2581%25ae%25e8%25aa%258d%25e8%25a8%25bc%25e3%2583%259a%25e3%2583%25bc%25e3%2582%25b8%25e3%2581%258b%25e3%2582%2589%25e8%25aa%258d%25e8%25a8%25bc%25e5%25be%258c%25e3%2580%2581http%25e3%2581%25ae%25e3%2583%259a%25e3%2583%25bc%25e3%2582%25b8%25e3%2581%25b8%25e3%2582%25bb%25e3%2582%25ad%25e3%2583%25a5%25e3%2583%25aa</link>
		<comments>http://www.onflow.jp/cyano/archives/110#comments</comments>
		<pubDate>Wed, 26 Apr 2006 00:32:44 +0000</pubDate>
		<dc:creator>ksakai</dc:creator>
				<category><![CDATA[Apache]]></category>

		<guid isPermaLink="false">http://www.onflow.jp/kleio/2006/04/https%e3%81%ae%e8%aa%8d%e8%a8%bc%e3%83%9a%e3%83%bc%e3%82%b8%e3%81%8b%e3%82%89%e8%aa%8d%e8%a8%bc%e5%be%8c%e3%80%81http%e3%81%ae%e3%83%9a%e3%83%bc%e3%82%b8%e3%81%b8%e3%82%bb%e3%82%ad%e3%83%a5%e3%83%aa/</guid>
		<description><![CDATA[
 <a href="http://www.onflow.jp/cyano/archives/110">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>『<a href="http://takagi-hiromitsu.jp/diary/20051130.html#p01">SSLを入力画面から使用しないのはそろそろ「脆弱性」と判断してしまってよいころかも</a>』という記事があるように、 パスワードを送信する段階で初めてSSLを使うはなく（パスワード入力フォームはHTTPで送信され、そのページのformタグのaction属性がhttpsになってる状態）、その前の段階でパスワード入力フォームが改竄されていないことを証明するために、パスワード入力フォームもHTTPSなページで表示することが望ましい状況になってきました。</p>
<p>で、そんなような仕組みを作った後で考えないといけないことは、認証後どうやってHTTPに戻すかと言うこと。つまり、すべてのページでHTTPSを使うのはサーバーに負荷がかかり現実的ではないので、認証する部分だけHTTPSで改竄や盗聴を防ぎ、その他のページはHTTPで済まそうという事です。図にするとこんな感じ。</p>
<table>
<tr>
<th scope="col">&nbsp;</th>
<th scope="col">クライアント</th>
<th scope="col">経路</th>
<th scope="col">サーバー</th>
<th scope="col">経路</th>
<th scope="col">クライアント</th>
</tr>
<tr>
<td>ステージ1</td>
<td>ログインフォームへのリンクをクリック</td>
<td>HTTPS</td>
<td>ログインフォームHTMLを返す</td>
<td>HTTPS</td>
<td>ログインフォームを得る</td>
</tr>
<tr>
<td>ステージ2</td>
<td>ログインフォーム送信</td>
<td>HTTPS</td>
<td>ログイン処理</td>
<td>HTTPS(*1)</td>
<td>ログイン後の画面</td>
</tr>
</table>
<p>普通に考えると、パスワードを認証後のHTTPレスポンスヘッダ(*1の部分)で<br /><code>Location: http://www.exmaple.com/logined.html</code><br />とかすればいいんじゃないの？と思うのですが、そうするとIEで「セキュリティーで保護されていないページに移動しようとしています」というような警告ダイアログが出てきてしまいます。</p>
<p><del>そんな警告ダイアログが出るのはユーザーフレンドリーじゃないので、それを防ぐ方法。</del></p>
<p><span id="more-110"></span></p>
<p>解決方法は簡単で、レスポンスヘッダで対応できないならレスポンスボディーで対処すればOK（Yahoo!なんかもこの方法を使っているようです）。たとえば、認証後、*1のところで以下のようなHTMLを返してあげれば、ブラウザがHTTPなページにリダイレクトしてくれるわけです。</p>
<pre>&lt;html&gt;
&lt;head&gt;
&lt;meta http-equiv=&quot;refresh&quot; content=&quot;0; url=<code>http://www.exmaple.com/logined.html</code>&quot;&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
&lt;!--
location.href = &quot;<code>http://www.exmaple.com/logined.html</code>&quot;;
//--&gt;
&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;p&gt;ログインが完了しました。&lt;a href=&quot;http://www.exmaple.com/logined.html&quot;&gt;続けるにはここをクリックしてください&lt;/a&gt;。&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<p>追記 2006年4月26日</p>
<p>セキュリティー警告を回避することをフレンドリーというのはいかがなものか、というトラックバックなどもいただきましたので、あわせて<a href="http://www.onflow.jp/blog/archives/2006/04/httpshttpie.html">HTTPSからHTTPのページに移動する際にIEのセキュリティー警告を回避できることについて</a>もご覧ください</p>
]]></content:encoded>
			<wfw:commentRss>http://www.onflow.jp/cyano/archives/110/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>mod_proxy_balancerで中〜大規模サーバー運用するときの勘所 &#8211; (4) mod_deflateと組み合わせる際の注意点編</title>
		<link>http://www.onflow.jp/cyano/archives/102?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=mod_proxy_balancer%25e3%2581%25a7%25e4%25b8%25ad%25e3%2580%259c%25e5%25a4%25a7%25e8%25a6%258f%25e6%25a8%25a1%25e3%2582%25b5%25e3%2583%25bc%25e3%2583%2590%25e3%2583%25bc%25e9%2581%258b%25e7%2594%25a8%25e3%2581%2599%25e3%2582%258b%25e3%2581%25a8%25e3%2581%258d%25e3%2581%25ae%25e5%258b%2598%25e6%2589%2580-4-mod_</link>
		<comments>http://www.onflow.jp/cyano/archives/102#comments</comments>
		<pubDate>Sat, 04 Feb 2006 14:37:27 +0000</pubDate>
		<dc:creator>ksakai</dc:creator>
				<category><![CDATA[Apache]]></category>

		<guid isPermaLink="false">http://www.onflow.jp/kleio/2006/02/mod_proxy_balancer%e3%81%a7%e4%b8%ad%e3%80%9c%e5%a4%a7%e8%a6%8f%e6%a8%a1%e3%82%b5%e3%83%bc%e3%83%90%e3%83%bc%e9%81%8b%e7%94%a8%e3%81%99%e3%82%8b%e3%81%a8%e3%81%8d%e3%81%ae%e5%8b%98%e6%89%80-4-mod_/</guid>
		<description><![CDATA[
 <a href="http://www.onflow.jp/cyano/archives/102">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Apache2.2から、ロードバランシングをしてくれる<a href="http://httpd.apache.org/docs/2.2/ja/mod/mod_proxy_balancer.html">mod_proxy_balancer</a> というモジュールが標準添付になりました。</p>
<p>このモジュール、その名前の通り、ApacheレベルでHTTPリクエストをバックエンドのサーバーに振り分けることでロードバランシングをしてくれるモジュールです。</p>
<p><a href="http://httpd.apache.org/docs/2.2/ja/mod/mod_proxy_balancer.html">Apacheの公式ドキュメント</a>や試しに入れてみた人のBlogなどは散見されますが、実際の現場で運用している事例というのはまだ無いようです。</p>
<p>そこで、実際にピーク時にover 500 request/secでmod_proxy_balancerなサーバーを運用している経験をふまえ、つまずいた点などを公開していきたいと思います。</p>
<p><span id="more-102"></span></p>
<p>今回は、mod_deflateと組み合わせる際の注意点です。<a href="http://www.onflow.jp/blog/archives/2006/02/mod_proxy_balan_2.html" title="mod_proxy_balancerで中〜大規模サーバー運用するときの勘所 - (3) BalancerMemberに渡すパラメーター編">前回</a>までの設定ではhttpd.confに以下のように書いていたかと思います。</p>
<pre>ProxyRequests Off
ProxyPass / balancer://cluster/ timeout=2

&lt;Proxy balancer://cluster/&gt;
BalancerMember http://192.168.1.1/ loadfactor=10 keepalive=On
BalancerMember http://192.168.1.2/ loadfactor=10 keepalive=On
&lt;/Proxy&gt;</pre>
<p>さて、mod_proxy_balancerようなモジュールを使うサイトというのはApacheレベルで300 Request/secを超えるようなサイトだと思います。このようなサイトで気になってくるのは帯域の問題。基本的に流せるデータ量によって回線使用料が決まってくるのであり、圧縮効率のよいHTMLやCSSやJavaScriptはなるべく<a href="http://httpd.apache.org/docs/2.2/ja/mod/mod_deflate.html">mod_deflate</a>で圧縮して転送し、またブラウザにキャッシュされた後から変更のないファイルは「304 Not Modified」をHTTPレスポンスとして送ることで、データの転送量を少しでも削減することが重要になります。</p>
<p>普通に圧縮すればいいだけだろうと思って、以下のように設定すると、意外と帯域が節約できてないことに気づくと思います。</p>
<pre>ProxyRequests Off
ProxyPass / balancer://cluster/ timeout=2

&lt;Proxy balancer://cluster/&gt;
AddOutputFilterByType DEFLATE text/html text/css application/x-javascript
BalancerMember http://192.168.1.1/ loadfactor=10 keepalive=On
BalancerMember http://192.168.1.2/ loadfactor=10 keepalive=On
&lt;/Proxy&gt;</pre>
<p>これで帯域が節約できない原因は意外なところにありました。</p>
<p>BalancerMemberで指定したバックエンドのサーバーが返すHTTPレスポンスには普通ETagという、コンテンツが更新されているかどうかを判定するためのヘッダが含まれるのですが、そのETagの生成に、ファイルのinode番号が使われていたのでした。</p>
<p>inode番号はサーバーごとにほぼ固有の値になってしまうのであり、192.168.1.1と192.168.1.2にアクセスが振り分けられた際には、それぞれ違うETagが返されてしまいます。違うEtagが返ってくると、ブラウザはコンテンツが更新されたものとして、新たに取得してしまうので、その分の帯域を使ってしまうと言うことでした。</p>
<p>これの解決策として、<a href="http://httpd.apache.org/docs/2.2/ja/mod/mod_headers.html">mod_headers</a>モジュールを使ってブラウザへETagヘッダを返さないようにするのと、ブラウザからのIf-None-MatchヘッダをBalancerMemberに渡さないようにする方法をとりました。</p>
<pre>ProxyRequests Off
ProxyPass / balancer://cluster/ timeout=2

&lt;Proxy balancer://cluster/&gt;
AddOutputFilterByType DEFLATE text/html text/css application/x-javascript
RequestHeader unset If-None-Match
Header unset ETag
BalancerMember http://192.168.1.1/ loadfactor=10 keepalive=On
BalancerMember http://192.168.1.2/ loadfactor=10 keepalive=On
&lt;/Proxy&gt;</pre>
<p><a href="http://httpd.apache.org/docs/2.2/ja/mod/core.html#fileetag">FileETag ディレクティブ</a>でETagの生成にinode番号を使わないようにする（<code>FileETag MTime Size</code>）とすることでも回避可能ですが、IEでは一旦ETagがキャッシュされてしまうと新しいETagに置き換えてくれないという問題があり、この回避策は見送りました。</p>
<p>さて、これでもまだ帯域が節約できていないことに気づくと思います。</p>
<p>原因はブラウザシェア8〜9割を占めるIEの実装にありました。</p>
<p><a href="http://httpd.apache.org/docs/2.2/ja/mod/mod_deflate.html">mod_deflate</a>を使うと、レスポンスヘッダにVary: Accept-Encodingが追加されるのですが、これがあると常にIEはIf-Modified-Sinceヘッダを送らずにコンテンツを取得しようとするのでした。（See also: <a href="http://blog.livedoor.jp/nipotan/archives/124283.html">IE ぁぃぃ〜 &#8211; にぽたん研究所</a>）</p>
<p>これの回避策としてはレスポンスヘッダからVaryヘッダを取り除くことが挙げられます。副作用としてAccept-Encoding: deflateを送っていないブラウザにもdelateなコンテンツをデリバリしてしまうことになりますが、 deflateに対応していないブラウザというのはごく少数だと思われるので、問題ないと言うことにしました。</p>
<pre>ProxyRequests Off
ProxyPass / balancer://cluster/ timeout=2

&lt;Proxy balancer://cluster/&gt;
AddOutputFilterByType DEFLATE text/html text/css application/x-javascript
RequestHeader unset If-None-Match
Header unset ETag
Header unset Vary
BalancerMember http://192.168.1.1/ loadfactor=10 keepalive=On
BalancerMember http://192.168.1.2/ loadfactor=10 keepalive=On
&lt;/Proxy&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.onflow.jp/cyano/archives/102/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mod_proxy_balancerで中〜大規模サーバー運用するときの勘所 &#8211; (3) BalancerMemberに渡すパラメーター編</title>
		<link>http://www.onflow.jp/cyano/archives/101?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=mod_proxy_balancer%25e3%2581%25a7%25e4%25b8%25ad%25e3%2580%259c%25e5%25a4%25a7%25e8%25a6%258f%25e6%25a8%25a1%25e3%2582%25b5%25e3%2583%25bc%25e3%2583%2590%25e3%2583%25bc%25e9%2581%258b%25e7%2594%25a8%25e3%2581%2599%25e3%2582%258b%25e3%2581%25a8%25e3%2581%258d%25e3%2581%25ae%25e5%258b%2598%25e6%2589%2580-3-bala</link>
		<comments>http://www.onflow.jp/cyano/archives/101#comments</comments>
		<pubDate>Sat, 04 Feb 2006 14:07:10 +0000</pubDate>
		<dc:creator>ksakai</dc:creator>
				<category><![CDATA[Apache]]></category>

		<guid isPermaLink="false">http://www.onflow.jp/kleio/2006/02/mod_proxy_balancer%e3%81%a7%e4%b8%ad%e3%80%9c%e5%a4%a7%e8%a6%8f%e6%a8%a1%e3%82%b5%e3%83%bc%e3%83%90%e3%83%bc%e9%81%8b%e7%94%a8%e3%81%99%e3%82%8b%e3%81%a8%e3%81%8d%e3%81%ae%e5%8b%98%e6%89%80-3-bala/</guid>
		<description><![CDATA[
 <a href="http://www.onflow.jp/cyano/archives/101">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Apache2.2から、ロードバランシングをしてくれる<a href="http://httpd.apache.org/docs/2.2/ja/mod/mod_proxy_balancer.html">mod_proxy_balancer</a> というモジュールが標準添付になりました。</p>
<p>このモジュール、その名前の通り、ApacheレベルでHTTPリクエストをバックエンドのサーバーに振り分けることでロードバランシングをしてくれるモジュールです。</p>
<p><a href="http://httpd.apache.org/docs/2.2/ja/mod/mod_proxy_balancer.html">Apacheの公式ドキュメント</a>や試しに入れてみた人のBlogなどは散見されますが、実際の現場で運用している事例というのはまだ無いようです。</p>
<p>そこで、実際にピーク時にover 500 request/secでmod_proxy_balancerなサーバーを運用している経験をふまえ、つまずいた点などを公開していきたいと思います。</p>
<p><span id="more-101"></span></p>
<p>今回は、BalancerMemberディレクティブに渡すパラメーターのチューニングについてです。<a href="http://www.onflow.jp/blog/archives/2006/02/mod_proxy_balan_1.html" title="mod_proxy_balancerで中〜大規模サーバー運用するときの勘所 - (2) ProxyPassディレクティブに渡すパラメーター編">前回</a>までの設定ではhttpd.confに以下のように書いていたかと思います。</p>
<pre>ProxyRequests Off
ProxyPass / balancer://cluster/ timeout=2

&lt;Proxy balancer://cluster/&gt;
BalancerMember http://192.168.1.1/ loadfactor=10
BalancerMember http://192.168.1.2/ loadfactor=10
&lt;/Proxy&gt;</pre>
<p>さて、mod_proxy_balancerはバックエンドのサーバーが生きているかどうかを試すために、常に一定数のリクエストをBalancerMemberディレクティブで設定されたバックエンドのサーバーに投げているようです。<code>SetHandler server-status</code>で見られるページには以下のようなアクセスとして見えます。（<code><a href="http://httpd.apache.org/docs/2.2/ja/mod/mod_status.html#extendedstatus">ExtendedStatus On</a></code>にしておかないと見られません）</p>
<table>
<tr>
<th scope="row">Srv</th>
<th scope="row">PID</th>
<th scope="row">Acc</th>
<th scope="row">M</th>
<th scope="row">CPU</th>
<th scope="row">SS</th>
<th scope="row">Req</th>
<th scope="row">Conn</th>
<th scope="row">Child</th>
<th scope="row">Slot</th>
<th scope="row">Client</th>
<th scope="row">VHost</th>
<th scope="row">Request</th>
</tr>
<tr>
<td>13-0</td>
<td>-</td>
<td>0/0/117397</td>
<td>.</td>
<td>0.85</td>
<td>3</td>
<td>1</td>
<td>0.0</td>
<td>0.00</td>
<td>299.21</td>
<td>::1</td>
<td>example.com</td>
<td>GET /</td>
</tr>
</table>
<p>さて、このリクエストを逆手にとって、HTTP/1.1のKeepAliveさせることで、新たにバックエンドとHTTPコネクション張るをコストを押さえようと考えました。</p>
<p>まず、バックエンドのサーバーのhttpd.confを編集することで、HTTP/1.1のKeepAliveを有効にします。</p>
<pre>KeepAlive On
MaxKeepAliveRequests 300
KeepAliveTimeout 30</pre>
<p>これで、HTTPレベルでのKeepAliveはOKになりました。</p>
<p>その後、mod_proxy_balancerの入っているサーバーからバックエンドとのコネクションがTCP/IPレベルで切断されないように、TCP/IPレベルでKeepAliveするようにBalancerMemberにkeepaliveパラメーターを渡しました。</p>
<pre>ProxyRequests Off
ProxyPass / balancer://cluster/ timeout=2

&lt;Proxy balancer://cluster/&gt;
BalancerMember http://192.168.1.1/ loadfactor=10 keepalive=On
BalancerMember http://192.168.1.2/ loadfactor=10 keepalive=On
&lt;/Proxy&gt;</pre>
<p>残念ながら、この設定をする前とした後でのベンチマークを取っていないので、確実にスピードアップが図れたかどうかは不明ですが、おそらくレスポンスタイムは向上していると思います。</p>
<p>次回は<a href="http://www.onflow.jp/blog/archives/2006/02/mod_proxy_balan_3.html">mod_deflateと組み合わせる際の注意点</a>を解説します。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.onflow.jp/cyano/archives/101/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mod_proxy_balancerで中〜大規模サーバー運用するときの勘所 &#8211; (2) ProxyPassディレクティブに渡すパラメーター編</title>
		<link>http://www.onflow.jp/cyano/archives/100?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=mod_proxy_balancer%25e3%2581%25a7%25e4%25b8%25ad%25e3%2580%259c%25e5%25a4%25a7%25e8%25a6%258f%25e6%25a8%25a1%25e3%2582%25b5%25e3%2583%25bc%25e3%2583%2590%25e3%2583%25bc%25e9%2581%258b%25e7%2594%25a8%25e3%2581%2599%25e3%2582%258b%25e3%2581%25a8%25e3%2581%258d%25e3%2581%25ae%25e5%258b%2598%25e6%2589%2580-2-prox</link>
		<comments>http://www.onflow.jp/cyano/archives/100#comments</comments>
		<pubDate>Sat, 04 Feb 2006 13:44:46 +0000</pubDate>
		<dc:creator>ksakai</dc:creator>
				<category><![CDATA[Apache]]></category>

		<guid isPermaLink="false">http://www.onflow.jp/kleio/2006/02/mod_proxy_balancer%e3%81%a7%e4%b8%ad%e3%80%9c%e5%a4%a7%e8%a6%8f%e6%a8%a1%e3%82%b5%e3%83%bc%e3%83%90%e3%83%bc%e9%81%8b%e7%94%a8%e3%81%99%e3%82%8b%e3%81%a8%e3%81%8d%e3%81%ae%e5%8b%98%e6%89%80-2-prox/</guid>
		<description><![CDATA[
 <a href="http://www.onflow.jp/cyano/archives/100">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Apache2.2から、ロードバランシングをしてくれる<a href="http://httpd.apache.org/docs/2.2/ja/mod/mod_proxy_balancer.html">mod_proxy_balancer</a> というモジュールが標準添付になりました。</p>
<p>このモジュール、その名前の通り、ApacheレベルでHTTPリクエストをバックエンドのサーバーに振り分けることでロードバランシングをしてくれるモジュールです。</p>
<p><a href="http://httpd.apache.org/docs/2.2/ja/mod/mod_proxy_balancer.html">Apacheの公式ドキュメント</a>や試しに入れてみた人のBlogなどは散見されますが、実際の現場で運用している事例というのはまだ無いようです。</p>
<p>そこで、実際にピーク時にover 500 request/secでmod_proxy_balancerなサーバーを運用している経験をふまえ、つまずいた点などを公開していきたいと思います。</p>
<p><span id="more-100"></span></p>
<p>今回は、ProxyPassディレクティブに渡すパラメーターのチューニングについてです。<a href="http://www.onflow.jp/blog/archives/2006/02/mod_proxy_balan.html" title="mod_proxy_balancerで中〜大規模サーバー運用するときの勘所 - (1)mod_proxy_balancerの設定">前回</a>までの設定ではhttpd.confに以下のように書いていたかと思います。</p>
<pre>ProxyRequests Off
ProxyPass / balancer://cluster/

&lt;Proxy balancer://cluster/&gt;
BalancerMember http://192.168.1.1/ loadfactor=10
BalancerMember http://192.168.1.2/ loadfactor=10
&lt;/Proxy&gt;</pre>
<p>こう設定した場合、mod_proxy_balancerがフリーのワーカーを取得できなかった場合、フリーのワーカーを取得するまで待つのではなく、即座にクライアントにエラーを返してしまいます。</p>
<p>アクセス数が50 request/secぐらいまではこの設定で問題なかったのですが、150 request/secを超えたあたりから、フリーのワーカーが取得できないというエラーが頻発するようになりました。おそらく、ワーカーの生成が間に合ってないために発生していたものだと思われます。</p>
<p>なので、ワーカーの生成を2秒ほど待つように設定しました。</p>
<pre>ProxyRequests Off
ProxyPass / balancer://cluster/ timeout=2

&lt;Proxy balancer://cluster/&gt;
BalancerMember http://192.168.1.1/ loadfactor=10
BalancerMember http://192.168.1.2/ loadfactor=10
&lt;/Proxy&gt;</pre>
<p>こう設定したことで、ワーカーが取得できないためにクライアントにエラーが返ることは無くなりました。</p>
<p>次回は<a href="http://www.onflow.jp/blog/archives/2006/02/mod_proxy_balan_2.html">BalancerMemberに渡すパラメーターについて</a>解説します。 </p>
]]></content:encoded>
			<wfw:commentRss>http://www.onflow.jp/cyano/archives/100/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mod_proxy_balancerで中〜大規模サーバー運用するときの勘所 &#8211; (1) mod_proxy_balancerの設定編</title>
		<link>http://www.onflow.jp/cyano/archives/99?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=mod_proxy_balancer%25e3%2581%25a7%25e4%25b8%25ad%25e3%2580%259c%25e5%25a4%25a7%25e8%25a6%258f%25e6%25a8%25a1%25e3%2582%25b5%25e3%2583%25bc%25e3%2583%2590%25e3%2583%25bc%25e9%2581%258b%25e7%2594%25a8%25e3%2581%2599%25e3%2582%258b%25e3%2581%25a8%25e3%2581%258d%25e3%2581%25ae%25e5%258b%2598%25e6%2589%2580-1-mod_</link>
		<comments>http://www.onflow.jp/cyano/archives/99#comments</comments>
		<pubDate>Sat, 04 Feb 2006 13:30:52 +0000</pubDate>
		<dc:creator>ksakai</dc:creator>
				<category><![CDATA[Apache]]></category>

		<guid isPermaLink="false">http://www.onflow.jp/kleio/2006/02/mod_proxy_balancer%e3%81%a7%e4%b8%ad%e3%80%9c%e5%a4%a7%e8%a6%8f%e6%a8%a1%e3%82%b5%e3%83%bc%e3%83%90%e3%83%bc%e9%81%8b%e7%94%a8%e3%81%99%e3%82%8b%e3%81%a8%e3%81%8d%e3%81%ae%e5%8b%98%e6%89%80-1-mod_/</guid>
		<description><![CDATA[
 <a href="http://www.onflow.jp/cyano/archives/99">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Apache2.2から、ロードバランシングをしてくれる<a href="http://httpd.apache.org/docs/2.2/ja/mod/mod_proxy_balancer.html">mod_proxy_balancer</a> というモジュールが標準添付になりました。</p>
<p>このモジュール、その名前の通り、ApacheレベルでHTTPリクエストをバックエンドのサーバーに振り分けることでロードバランシングをしてくれるモジュールです。</p>
<p><a href="http://httpd.apache.org/docs/2.2/ja/mod/mod_proxy_balancer.html">Apacheの公式ドキュメント</a>や試しに入れてみた人のBlogなどは散見されますが、実際の現場で運用している事例というのはまだ無いようです。</p>
<p>そこで、実際にピーク時にover 500 request/secでmod_proxy_balancerなサーバーを運用している経験をふまえ、つまずいた点などを公開していきたいと思います。</p>
<p><span id="more-99"></span></p>
<p>まず、mod_proxy_balancerの設定から。よく、httpd.confでこのようになっている設定例を見かけます。</p>
<pre>ProxyRequests Off
ProxyPass / balancer://cluster

&lt;Proxy balancer://cluster&gt;
BalancerMember http://192.168.1.1 loadfactor=10
BalancerMember http://192.168.1.2 loadfactor=10
&lt;/Proxy&gt;</pre>
<p>こう設定した場合、http://example.com/でアクセスした場合は問題なくリクエストが行われたのですが、http://example.com/dir/などサブディレクトリにアクセスした場合、403 forbiddenが返ってきてしまいました。その時のerror_logには以下のように書かれていました。</p>
<p> [Fri Dec 30 22:25:00 2005] [warn] proxy: No protocol handler was valid for the URL /dir/. If you are using a DSO version of mod_proxy, make sure the proxy submodules are included in the configuration using LoadModule.</p>
<p>エラーを文字通り受け取れば、mod_proxy_httpなどのmod_proxyのサブモジュールがロードされていないためにエラーが起こっていると思ってしまいがちですが、そうではないのです。（実際にこのエラーが起きたときにはmod_proxy_httpなどはロードされていました）</p>
<p>原因は「ProxyPass /」ディレクティブが、URLに含まれるすべての「/」に適用されてしまうために、このようなエラーになってしまうと言うことでした。</p>
<p>httpd.confの設定を以下のように変えることで解決しました。</p>
<pre>ProxyRequest Off
ProxyPass / balancer://cluster/

&lt;Proxy balancer://cluster/&gt;
BalancerMember http://192.168.1.1/ loadfactor=10
BalancerMember http://192.168.1.2/ loadfactor=10
&lt;/Proxy&gt;</pre>
<p>次回は<a href="http://www.onflow.jp/blog/archives/2006/02/mod_proxy_balan_1.html">ProxyPassディレクティブに渡すパラメーターについて</a>解説します。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.onflow.jp/cyano/archives/99/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

