瞬間的な高負荷に耐える為にアプリケーション側を変更せず、nginxの設定のみで対応する方法
CDNとは、「Contents Delivery Network」といわれるもので、最適なネットワークを経由してWebコンテンツをキャッシュし効率的に配信できる物です。Amazon(AWS)では「CloudFront」というサービスがあります。他にも「Akamai」などが有名です。
前提条件
- バックエンドにProxyするCMSを使う(ここではPlone) (画像等も静的なデータではなくCMSから配信)
今回の実験
- CDNには、Amazon(AWS) CloudFrontを用いた
- nginx - Varnish - CMSアプリ(Plone(複数台))という構成(当社が普段から使っている構成)
- 画像やファイルなどのみをCDNから配信させる
- 画像やファイルのオリジナルは、Plone内つまり、同じnginxからCDNに転送
手順
- CDN(Amazon CloudFront)を設定する。
Web用、HTTP/HTTPSを使う、Custom Originの設定を行う。(下部の「参考にしたサイト(1)」を参照) - nginxの設定を行う
ポイント
方式
- nginxにて指定のURI(画像などを特定)は、CDN(CloudFront)にリダイレクトする
- 指定のURIは、正規表現を用いて、Ploneの仕様に合わせて特定する(これはVarnishのキャッシュ設定と同じ設定を持ってきた)
VarnishのサンプルVCLはこちら
nginxのconf
- locationの中で、proxy_passが1回しか指定できない
- 複数の条件を分岐できない且つネスト出来ない <これは一番ハマった。(下部の「参考にしたサイト(3)」を参照)
- Amazon CloudFrontからデータを取得する時は、Ploneからデータを取得出来るようにする (下部の「参考にしたサイト(2)」を参照)
設定ファイルの抜粋
nginx.conf
upstream to_varnish {
server 127.0.0.1:6081;
}
server {
...
省略
...
location / {
if ($uri ~* \.(jpe?g|png|gif|pdf|gz|tgz|bz2|tbz|zip|tiff|tif)$) {
set $no_plone A;
}
if ($uri ~* /(image|(image_(?:[^/]|(?!view.*).+)))$) {
set $no_plone A;
}
if ($uri ~* \.(svg|swf|ico|mp3|mp4|m4a|ogg|mov|avi|wmv|flv)$) {
set $no_plone A;
}
if ($uri ~* \.(css|js)$) {
set $no_plone A;
}
if ( $http_user_agent != "Amazon CloudFront" ) {
set $no_plone "${no_plone}B";
}
if ($no_plone = AB) {
expires 1h;
rewrite ^ http://YOUR_SUBDOMAIN.cloudfront.net$request_uri? last;
}
proxy_pass http://to_varnish/VirtualHostBase/http/YOUR_DOMAIN:80/Plone/VirtualHostRoot/;
}
動作確認
- nginxのログを閲覧
Amazon CloudFront からのアクセスがあることを確認 - Firebugなどでネットワークの取得元を確認
画像などが、302でCDNへリダイレクトされていて、取得元URLが変わっていた
効果
数人でアクセスしているレベルだと、Varnishで十分はさばけるので、効果を感じることが出来なかった。
(リダイレクトが発生する分、100ms程度時間が掛かるケースもあった)
実際に高負荷状態を作り、Varnishでも耐えられない程度の状態でないと、実感できないと思う。