さくらVPS512で、Yahoo!砲食らっても WordPress を平常運転させるための設定

2010年の年末に、「カイ士伝」のさくらVPSへの引っ越しを手伝ったわけですが、その後も元気にサーバは動き続けているようです。
引っ越し当初は、Web サーバとして lighttpd を導入してたんですけど、僕の個人的な好みがかわって、途中で Nginx に切り替えました。
特に大きなトラブルもなくサクサクと動いてたようですが、昨日突然の Yahoo!砲で、平常時の数倍のアクセスがあったようです。

Yahoo!砲くらったけど月額980円のさくらVPSとチューニングでサーバー落とさず乗り切ったよ – カイ士伝

ただ、アクセスが大量にあった初日(1記事に5.5万PV)にもサーバ負荷が高くなってるとか気付かずに、余波でちょっと多くなってた翌日(1記事に1.3万PV)に気づいたというくらいの平常運転っぷり。
Nginx 痺れますわー。

僕は、カイ士伝の WordPress ダッシュボードにログインする権限もらってないんで、プラグインとかどんなのが入ってるか知りませんので、バックエンドのサーバ環境についてだけ。
たぶん、WP Super Cache とかのキャッシュ系プラグインは使ってないと思うよ。

PHP

Web サーバとして Nginx を使ってるので、Apache の mod_php のように Web サーバに組み込めません。
そんなわけで、FastCGI (php-fpm) を使用しています。

/etc/php-fpm.d/www.conf は、こんな感じ

[www]
listen = /var/run/php-fpm.sock
listen.owner = nobody
listen.group = nobody
listen.mode = 0666
user = nginx
group = nginx
pm = static
pm.max_children = 5
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
slowlog = /var/log/php-fpm/www-slow.log
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_admin_value[upload_max_filesize] = 16M
php_admin_value[post_max_size] = 16M

static にして、5プロセスだけ起動します。
ilste ポートは、Unix ドメインソケットにしてますね。

あと、PHPアクセラレーターの eAccelerator が入ってます。

Web サーバ

Nginx を採用してます。短時間(5分間)のリバースプロキシキャッシュありで。
設定は、こんな感じ。

user              nginx;
worker_processes  2;
worker_rlimit_nofile 4096;
error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;

events {
    multi_accept off;
    worker_connections  1024;
    use epoll;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    log_format  backend '$http_x_forwarded_for - $remote_user [$time_local] "$request" '
                        '$status $body_bytes_sent "$http_referer" '
                        '"$http_user_agent"';

    access_log  /var/log/nginx/access.log  main;
    server_tokens     off;
    server_name_in_redirect off;
    port_in_redirect  off;

    client_max_body_size    16m;
    client_body_buffer_size 256k;
    sendfile        on;

    keepalive_timeout   5;

    gzip_static       on;
    gzip              on;
    gzip_http_version 1.0;
    gzip_vary         on;
    gzip_comp_level   6;
    gzip_types        text/plain text/xml text/css text/javascript
                      application/xhtml+xml application/xml
                      application/rss+xml application/atom_xml
                      application/javascript application/x-javascript
                      application/x-httpd-php;
    gzip_disable      "MSIE [1-6]\.";

    proxy_cache_path  /var/cache/nginx levels=1:2
                      keys_zone=one:4m max_size=50m inactive=120m;
    proxy_temp_path   /var/tmp/nginx;
    proxy_cache_key   "$scheme://$host$request_uri";
    proxy_set_header  Host               $host;
    proxy_set_header  X-Real-IP          $remote_addr;
    proxy_set_header  X-Forwarded-Host   $host;
    proxy_set_header  X-Forwarded-Server $host;
    proxy_set_header  X-Forwarded-For    $proxy_add_x_forwarded_for;
    proxy_set_header  Accept-Encoding    "";
    proxy_connect_timeout 5;
    proxy_send_timeout 10;
    proxy_read_timeout 120;
    proxy_hide_header X-Pingback;
    proxy_hide_header X-Powered-By;
    proxy_hide_header Etag;
    proxy_hide_header Vary;
    proxy_cache_use_stale timeout invalid_header http_500 http_502 http_503 http_504;
    proxy_cache_lock on;
    proxy_cache_lock_timeout 5s;

    upstream backend {
        server unix:/var/run/nginx-backend.sock;
    }

    upstream phpfpm {
        server unix:/var/run/php-fpm.sock;
    }

    include /etc/nginx/conf.d/*.conf;
}

目新しいところは無いですね。
php-fpm とか、バックエンドの Web サーバに接続するために UNIX ドメインソケット使ってるくらいでしょうか?
この後のバーチャルホスト設定で、upstream backend と php-fpm を使います。

続いて、バーチャルホスト設定
/etc/conf.d/default.conf

server {
    listen       80 default;
    server_name  _;
    root    /var/www/html;
    index   index.html index.htm index.php;
    charset utf-8;

    rewrite /wp-admin$ $scheme://$host$uri/ permanent;
    rewrite ^(.*)(index|home|default)\.html? $1 permanent;

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt { access_log off; log_not_found off; }
    location = /apple-touch-icon.png { access_log off; log_not_found off; }
    location = /apple-touch-icon-precomposed.png { access_log off; log_not_found off; }
    location ~ /\. { deny all; access_log off; log_not_found off; }

    set $mobile '';
    if ($http_user_agent ~* '(DoCoMo|J-PHONE|Vodafone|MOT-|UP\.Browser|DDIPOCKET|ASTEL|PDXGW|Palmscape|Xiino|sharp pda browser|Windows CE|L-mode|WILLCOM|SoftBank|Semulator|Vemulator|J-EMULATOR|emobile|mixi-mobile-converter)') {
      set $mobile '@ktai';
    }
    if ($http_user_agent ~* '(iPhone|iPod|incognito|webmate|Android|dream|CUPCAKE|froyo|BlackBerry|webOS|s8000|bada|IEMobile|Googlebot\-Mobile|AdsBot\-Google)') {
      set $mobile '@smartphone';
    }
    if ($http_cookie ~* "wptouch(_switch_cookie=normal|-pro-view=desktop)") {
        set $mobile "@smartphone.desktop";
    }

    location ~* /wp-(content|admin|includes) {
        index   index.php index.html index.htm;
        if ($request_filename ~* .*\.(xml|gz)) {
            break;
            expires 1d;
        }
        if ($request_filename ~* .*\.(txt|html?|js|css|swf)) {
            break;
            expires 30d;
        }
        if ($request_filename ~* .*\.(ico|jpe?g|gif|png|wmv|flv|mpg|gz)) {
            break;
            expires 365d;
        }
        if ($request_filename ~ .*\.php) {
            break;
            proxy_pass http://backend;
        }
    }
    location /feed { proxy_pass http://backend; }
    location ~ .*\.php { proxy_pass http://backend; }

    location / {
        set $do_not_cache 0;
        if ($http_cookie ~* "comment_author_|wordpress_(?!test_cookie)|wp-postpass_" ) {
            set $do_not_cache 1;
        }
        if ($request_method = POST) {
            set $do_not_cache 1;
        }

        proxy_no_cache     $do_not_cache;
        proxy_cache_bypass $do_not_cache;

        proxy_redirect     off;
        proxy_cache        one;
        proxy_cache_key    "$scheme://$host$request_uri$mobile";
        proxy_cache_valid  200 5m;
        proxy_cache_valid  404 5m;
        proxy_pass         http://backend;
    }
}

cookie を見て WordPress ログイン時にはキャッシュしないようにしています。あと POST メソッド送られたときも。
その他は、5分間だけリバースプロキシキャッシュにデータを取っています。

続いて、バックエンドのサーバの設定です。
/etc/conf.d/default.backend.conf

server {
    listen unix:/var/run/nginx-backend.sock;
    server_name  _;
    root   /var/www/html;
    access_log  /var/log/nginx/backend.access.log  backend;

    gzip              off;
    gzip_vary         off;

    location / {
        index  index.php index.html index.htm;
        try_files $uri $uri/ /index.php?$args /index.php?q=$uri&$args;
    }

    location ~ \.php$ {
        try_files $uri =404;
        expires        off;
        fastcgi_pass   phpfpm;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        include        fastcgi_params;
        fastcgi_param  REMOTE_ADDR      $http_x_real_ip;
        fastcgi_pass_header "X-Accel-Redirect";
        fastcgi_pass_header "X-Accel-Buffering";
        fastcgi_pass_header "X-Accel-Charset";
        fastcgi_pass_header "X-Accel-Expires";
        fastcgi_pass_header "X-Accel-Limit-Rate";
    }
}

listen してるのは、UNIX ドメインソケットですね。
Nginx では、TCP ポートだけでなく UNIX ドメインソケットも listen できます。

MySQL

MySQL は、クエリキャッシュとか有効にしてます。
/etc/my.cnf は、こんな感じです。

[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
character-set-server=utf8
symbolic-links=0
innodb_buffer_pool_size=64M
innodb_log_file_size=16M
innodb_flush_method=O_DIRECT
query_cache_size=128M
query_cache_limit=2M
query_cache_min_res_unit=4k
query_cache_type=1
tmp_table_size=128M
max_heap_table_size=128M
table_open_cache=1024
max_allowed_packet=1M
sort_buffer=256K
read_buffer_size=256K
read_rnd_buffer_size=256K
join_buffer_size=256K
key_buffer_size=16M
max_connections=256
thread_cache=256
wait_timeout=60

メモリ 1GB で使えるだけ使ってる感じです。
この辺は mysqltuner.pl で簡単にチェックできるので、チェックしてみると良いよ。
mysqltuner.pl は、以下のコマンドで実行できます。


$ perl <(wget -q -O - mysqltuner.pl)[/text] まぁ、ただ設定ファイル並べただけですが、実はこれらの設定済みなのが 網元 です。
よろしければ、使ってねー。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください