Tuesday, June 21, 2016

WordPressの応答をVarnishで高速化

https://varnish-cache.org/
Varnishを使ってWordPressをキャッシュする方法です。
Varnish port 80 -> nginx port 8080 -> php-fpm -> WordPress という構成にします。

Varnishは、いままで使ったことがなかったので、導入だけでも触っておこうと考えて、よくありそうなユースケースとして、ウェブメディアの前段にキャッシュを置く、という使い方をしてみました。
ほかに、外部サービスのAPIが不安定だったりする場合、間にVarnishを挟んで、可用性とパフォーマンスを確保する使い方もあるようです。
External API Caching with Varnish & Nginx http://blog.runnable.com/post/144975295096/external-api-caching-with-varnish-nginx


以下、既に、WordPressが立っているという状況で進めていきます。
環境は、CentOS 6.7です。

Varnishをインストール
$ rpm --nosignature -i http://repo.varnish-cache.org/redhat/varnish-4.1/el6/noarch/varnish-release/varnish-release-4.1-2.el6.noarch.rpm
$ yum install varnish
# varnishd -V
varnishd (varnish-4.1.2 revision 0d7404e)
Copyright (c) 2006 Verdens Gang AS
Copyright (c) 2006-2015 Varnish Software AS[

nginxの設定ファイルを編集
nginxの設定。ポート8080番で待ち受けるようにします。
# vim /etc/nginx/conf.d/default.conf
listen       80;
->
listen       8080;
https://gist.github.com/takeshiyako2/5cd855e9d3bc2e55b8cb5d5f70d1ff6e#file-default-conf

Varnishの設定ファイルを編集
Varnishのポートの設定。80番で待ち受けるようにします。
# vim /etc/sysconfig/varnish
VARNISH_LISTEN_PORT=6081
->
VARNISH_LISTEN_PORT=80
https://gist.github.com/takeshiyako2/5cd855e9d3bc2e55b8cb5d5f70d1ff6e#file-varnish

VCL(Varnish Configuration Language)の設定。
以下、設定のポイントです。
・バックエンドをnginx(127.0.0.1:8080)に
・localhostからのパージリクエストを許可(ここでは、全てのキャッシュをパージするBANを設定)
・WordPress管理者ページをキャッシュしないように
・コンテンツでは、クッキーを無視して、キャッシュが効くように
# vim /etc/varnish/default.vcl

以上で設定は完了です。

nginxとVarnishをリロード(or リスタート)
# service nginx restart
# service varnish restart
ちゃんとキャッシュされているでしょうか?
Varnishにキャッシュされたコンテンツがnginxログに出なくなっているとおもいます。
キャッシュが破棄される時間、TTLは、/etc/sysconfig/varnishで設定されています。必要に応じて編集すると良いでしょう。デフォルトでは120秒です。

キャッシュをパージするには?
curlでVarnishのAPIを叩きます。
以下のコマンドで、全てのキャッシュをパージします。
# curl -X BAN -v http://localhost/
細かくパスを指定してパージもできます。詳しくは公式ドキュメントを参照してください。
Purging and banning — Varnish version 4.1.2 documentation https://www.varnish-cache.org/docs/4.1/users-guide/purging.html

ベンチマーク
Varnishなし。
# ab -c 100 -n 10000 http://192.168.33.10/
Server Software:        nginx/1.10.1
Server Hostname:        192.168.33.10
Server Port:            80

Document Path:          /
Document Length:        10400 bytes

Concurrency Level:      100
Time taken for tests:   222.524 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      106320000 bytes
HTML transferred:       104000000 bytes
Requests per second:    44.94 [#/sec] (mean)
Time per request:       2225.244 [ms] (mean)
Time per request:       22.252 [ms] (mean, across all concurrent requests)
Transfer rate:          466.59 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   4.7      0      51
Processing:    83 2218 452.3   2118    5395
Waiting:       31 2070 435.9   1977    5210
Total:         83 2218 451.4   2119    5395

Percentage of the requests served within a certain time (ms)
  50%   2119
  66%   2250
  75%   2347
  80%   2420
  90%   2731
  95%   3164
  98%   3642
  99%   3945
 100%   5395 (longest request)
Varnishあり。
Server Software:        nginx/1.10.1
Server Hostname:        192.168.33.10
Server Port:            80

Document Path:          /
Document Length:        10465 bytes

Concurrency Level:      100
Time taken for tests:   1.546 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      107936450 bytes
HTML transferred:       104650000 bytes
Requests per second:    6466.26 [#/sec] (mean)
Time per request:       15.465 [ms] (mean)
Time per request:       0.155 [ms] (mean, across all concurrent requests)
Transfer rate:          68158.75 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    7   2.6      6      19
Processing:     3    8   2.7      8      27
Waiting:        0    5   2.9      5      18
Total:          9   15   3.4     15      29

Percentage of the requests served within a certain time (ms)
  50%     15
  66%     16
  75%     17
  80%     17
  90%     20
  95%     22
  98%     26
  99%     27
 100%     29 (longest request)
Varnishなし 44.94 req/s、Varnishあり 6466.26 req/s。
Varnishありの転送サイズが若干多いのは、ヘッダーが付与されているからかなと。

まとめ
Varnishを導入して、WordPressの応答を高速化しました。
初歩的な使いかたはできたかな?と思います。
今回はやりませんでしたが、ディレクトリ単位、ファイル単位といった細かい粒でキャッシュのパージができます。このため、応用次第で、様々なサイトにキャッシュを導入できたりしそうです。サーバサイドアプリの応答が遅くて、そこそこアクセスがあるサイトとかだったら、導入を検討してみる価値があるかもしれません。
ちなみに。単純に、WordPressのキャッシュを高速に返したいのであれば、nginxのproxy_cacheで十分だと思います。。


top image from https://varnish-cache.org/

Thursday, May 19, 2016

nginxモジュールのngx_dynamic_upstreamを使えるようにする


nginxモジュールの ngx_dynamic_upstream を試してみたかったので、使えるようにしてみました。
nginxをyumからインストールして、ユーザ追加などの雑用を任せて、そのあとにソースからコンパイルします。
モジュールの使い方については、ここでは説明しません。
環境は、CentOS 6.7です。

nginxの最新版をyumからインストール。
# rpm -ivh http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm
# yum -y install nginx
オプションを確認します。
# nginx -V
nginx version: nginx/1.10.0
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-16) (GCC)
built with OpenSSL 1.0.1e-fips 11 Feb 2013
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_geoip_module=dynamic --with-http_perl_module=dynamic --add-dynamic-module=njs-1c50334fbea6/nginx --with-threads --with-stream --with-stream_ssl_module --with-http_slice_module --with-mail --with-mail_ssl_module --with-file-aio --with-ipv6 --with-http_v2_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic'
nginxのビルドに必要なライブラリをインストール。
# yum install pcre-devel zlib-devel openssl-devel libxml2-devel libxslt-devel gd-devel perl-ExtUtils-Embed GeoIP-devel
nginxをダウンロード。
$ cd /usr/local/src
$ git clone https://github.com/cubicdaiya/ngx_dynamic_upstream.git
$ wget http://nginx.org/download/nginx-1.10.0.tar.gz
$ tar zxvf nginx-1.10.0.tar.gz
$ cd nginx-1.10.0
configureに、先ほどのオプションを全部追加すると、以下のエラーが出ます。
adding module in njs-1c50334fbea6/nginx
./configure: error: no njs-1c50334fbea6/nginx/config was found
これは、nginx with HTTP JavaScript moduleです。オプションから --add-dynamic-module=njs-1c50334fbea6/nginxを外してconfigureを実行します。
必要な場合は、https://github.com/nginx/njs を準備しましょう。

configureを実行。
$ ./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_geoip_module=dynamic --with-http_perl_module=dynamic --with-threads --with-stream --with-stream_ssl_module --with-http_slice_module --with-mail --with-mail_ssl_module --with-file-aio --with-ipv6 --with-http_v2_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic' --add-module=/usr/local/src/ngx_dynamic_upstream
インストール。
# make
# make install
# nginx -V
nginx version: nginx/1.10.0
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-16) (GCC)
built with OpenSSL 1.0.1e-fips 11 Feb 2013
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_geoip_module=dynamic --with-http_perl_module=dynamic --with-threads --with-stream --with-stream_ssl_module --with-http_slice_module --with-mail --with-mail_ssl_module --with-file-aio --with-ipv6 --with-http_v2_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic' --add-module=/usr/local/src/ngx_dynamic_upstream
ngx_dynamic_upstreamが有効になりました。

Top image from James Morris upstream - we're on the same page

Thursday, May 12, 2016

MySQL HandlerSocketのレイテンシを監視するNagiosプラグイン

https://github.com/takeshiyako2/nagios-check_handlersocket_latency

MySQL HandlerSocketのレイテンシを監視するプラグインを書きました。
簡単な使い方。
% check_handlersocket_latency -w [waring seconds] -c [critical seconds] -host [hostname]
% check_handlersocket_latency -w 0.70 -c 1.00 -host localhost
デフォルトでは、mysqlデータベースのuserテーブルから、Hostがlocalhostのレコードを取り出して、時間を測っています。
デフォルト値は以下のようにしています。
host: localhost
port: 9998
database: mysql
table: user
index: PRIMARY
columns: Host
value: localhost
これは、オプションで変更可能です。
たとえば、以下の様なテーブルを用意したときは、このようになります。
mysql> use sampledb;
mysql> CREATE TABLE personal(id int PRIMARY KEY, name varchar(20));
mysql> INSERT INTO personal (id,name) VALUES (100, "test");
$ ./check_handlersocket_latency -w 0.005 -c 0.020 -host localhost -database sampledb -table personal -columns id -value 100
OK: HandlerSocket read response in 0.001996 s|latency_seconds=0.001996