WordPress のチューニングポイントを探す 2
前回 WordPress のチューニングポイントを探す の続編。MySQL のクエリーキャッシュと、 memcached による分散キャッシュサーバを導入して、WordPress の高速化を目指す。
MySQL のクエリーキャッシュ
デフォルト状態では、クエリーキャッシュが有効になっていないため、有効にする。動作を確認する為に実行されたクエリーをファイルに保存する。クエリーキャッシュを有効にした直後のアクセスと、2 回目のアクセスでどのような変化があるかを調べる。
-
# mysqladmin -u root variables | grep query_cache_
-
-
| query_cache_limit | 1048576 |
-
| query_cache_min_res_unit | 4096 |
-
| query_cache_size | 0 |
-
| query_cache_type | ON |
-
| query_cache_wlock_invalidate | OFF |
-
-
# vi /etc/my.cnf
-
-
[mysqld]
-
datadir=/var/lib/mysql # 初期設定
-
socket=/var/lib/mysql/mysql.sock # 初期設定
-
user=mysql # 初期設定
-
old_passwords=1 # 初期設定
-
query_cache_limit=1M # 1MB より大きい結果はキャッシュしない
-
query_cache_min_res_unit=4k # 4K が推奨値
-
query_cache_size=24M # クエリキャッシュにメモリを 24M (bytes) 割り当てる
-
query_cache_type=1 # 0: OFF 1: ON 2: DEMAND
-
log=/var/log/mysql-all.log # クエリーを全文保存
-
-
[mysqld_safe] # 初期設定
-
log-error=/var/log/mysqld.log # 初期設定
-
pid-file=/var/run/mysqld/mysqld.pid # 初期設定
-
-
# echo ""> /var/log/mysql-all.log
-
# chown mysql. /var/log/mysql-all.log
-
# service mysqld restart
-
# mysqladmin -u root variables | grep query_cache_
-
-
| query_cache_limit | 1048576 |
-
| query_cache_min_res_unit | 4096 |
-
| query_cache_size | 25165824 |
-
| query_cache_type | ON |
-
| query_cache_wlock_invalidate | OFF |
-
-
# mysqladmin -u root extended-status | grep Qcache
-
-
| Qcache_free_blocks | 1 |
-
| Qcache_free_memory | 25157000 |
-
| Qcache_hits | 0 |
-
| Qcache_inserts | 0 |
-
| Qcache_lowmem_prunes | 0 |
-
| Qcache_not_cached | 1 |
-
| Qcache_queries_in_cache | 0 |
-
| Qcache_total_blocks | 1 |
-
-
# echo ""> /var/log/mysql-all.log
-
# httperf --hog --server=10.0.0.1 --uri=/wordpress/?p=3 --num-conns=1 --num-calls=1 --rate=1
-
# cat /var/log/mysql-all.log | wc -l
-
-
22
-
-
# mysqladmin -u root extended-status | grep Qcache
-
-
| Qcache_free_blocks | 1 |
-
| Qcache_free_memory | 25115576 |
-
| Qcache_hits | 0 |
-
| Qcache_inserts | 16 |
-
| Qcache_lowmem_prunes | 0 |
-
| Qcache_not_cached | 3 |
-
| Qcache_queries_in_cache | 16 |
-
| Qcache_total_blocks | 42 |
-
-
# echo ""> /var/log/mysql-all.log
-
# httperf --hog --server=10.0.0.1 --uri=/wordpress/?p=3 --num-conns=1 --num-calls=1 --rate=1
-
# cat /var/log/mysql-all.log | wc -l
-
-
22
-
-
# mysqladmin -u root extended-status | grep Qcache
-
-
| Qcache_free_blocks | 1 |
-
| Qcache_free_memory | 25115576 |
-
| Qcache_hits | 16 |
-
| Qcache_inserts | 16 |
-
| Qcache_lowmem_prunes | 0 |
-
| Qcache_not_cached | 5 |
-
| Qcache_queries_in_cache | 16 |
-
| Qcache_total_blocks | 42 |
1 回目のアクセスで 22 回のクエリーが実行された事が分かった。その内、16 クエリーがキャッシュに保存された。(クエリーに保存されるのは、SELECT 文のみ) 2 回目のアクセスでは、同じページへのアクセスなので、前回同様に 22 回のクエリーが実行された。その内、16 回のクエリーがキャッシュに保存された内容と一致し、キャッシュから返された。クエリーを有効にすることで、多少の高速化が見込めそうだ。
WordPress 標準のキャッシュ機能
WordPress には標準でキャッシュ機能がある。
-
# cd $wordpress_root_dir
-
# vi wp-config
-
-
define('ENABLE_CACHE',true); // 先頭の方に追加
-
-
# mkdir ./wp-content/cache
-
# chmod 777 ./wp-content/cache
WordPress 2.5 より、この機能が削除された。
memcached による分散キャッシュ
memcached は高性能な分散メモリキャッシュサーバで、データベースへのクエリー結果を一時的にキャッシュできる。MySQL のクエリーキャッシュの場合は、実際に問い合わせが発生するが、memcached の場合は問い合わせが発生しない。memcached は分散キャッシュサーバなので、複数のサーバで構築する事も出来るが、今回はlocalhost で memcached にアクセスできるように WordPress をインストールしたサーバに memcached を同居させる。memcached を有効にした直後のアクセスと、2 回目のアクセスでどのような変化があるかを調べる。
-
# cd $wordpress_root_dir
-
# wget http://dag.wieers.com/rpm/packages/rpmforge-release/rpmforge-release-0.3.6-1.el5.rf.i386.rpm
-
# rpm -ihv rpmforge-release-0.3.6-1.el5.rf.i386.rpm
-
# yum install php-pecl-memcache memcached
-
# service memcached start
-
# chkconfig memcached on
次に WordPress に取り込むために object-cache.php をダウンロードし、./wp-content/object-cache.php として設置する。
http://ryan.boren.me/2005/12/23/memcached-backend/
http://plugins.trac.wordpress.org/browser/memcached/trunk/object-cache.php
WordPress と memcached が同じサーバーの場合は特に設定は必要ないが、異なるサーバーの場合は、wp-config.php に追記する必要がある。
-
# echo "$memcached_servers = array('192.168.1.1:11211', '192.168.1.2:11211');">> ./wp-config.php
必要ではないが、便利なツールとして memcache.php がある。これを設置すると、memcache でキャッシュしているサイズを表示する事ができる。
http://livebookmark.net/journal/2008/05/21/memcachephp-stats-like-apcphp/
http://livebookmark.net/memcachephp/memcachephp.zip
memcached が動作しているサーバと、接続するのに必要な認証情報を編集する必要がある。
-
# cat memcache.php |grep -e "define('ADMIN_" -e "add more as an array"
-
-
define('ADMIN_USERNAME','memcache'); // Admin Username
-
define('ADMIN_PASSWORD','password'); // Admin Password
-
$MEMCACHE_SERVERS[] = 'localhost:11211'; // add more as an array
memcache.php を開くと、現在のキャッシュ容量が Used: 0 KBytes (0.0%) と表示されていれば正常。準備は整ったので、実際に memcached を動作させ、アクセスする。
-
# service mysqld restart
-
# echo ""> /var/log/mysql-all.log
-
# httperf --hog --server=10.0.0.1 --uri=/wordpress/?p=3 --num-conns=1 --num-calls=1 --rate=1
-
# cat /var/log/mysql-all.log | wc -l
-
-
22
-
-
# mysqladmin -u root extended-status | grep Qcache
-
-
| Qcache_free_blocks | 1 |
-
| Qcache_free_memory | 25115576 |
-
| Qcache_hits | 0 |
-
| Qcache_inserts | 16 |
-
| Qcache_lowmem_prunes | 0 |
-
| Qcache_not_cached | 2 |
-
| Qcache_queries_in_cache | 16 |
-
| Qcache_total_blocks | 42 |
memcache.php を確認すると、17 クエリー (Current Items 17) がキャッシュに保存されており Used: 18.7 KBytes (0.0%) となっている。MySQL のクエリーキャッシュには 16 クエリー保存されている。
-
# echo ""> /var/log/mysql-all.log
-
# httperf --hog --server=10.0.0.1 --uri=/wordpress/?p=3 --num-conns=1 --num-calls=1 --rate=1
-
# cat /var/log/mysql-all.log | wc -l
-
-
11
-
-
# mysqladmin -u root extended-status | grep Qcache
-
-
| Qcache_free_blocks | 1 |
-
| Qcache_free_memory | 25115576 |
-
| Qcache_hits | 5 |
-
| Qcache_inserts | 16 |
-
| Qcache_lowmem_prunes | 0 |
-
| Qcache_not_cached | 4 |
-
| Qcache_queries_in_cache | 16 |
-
| Qcache_total_blocks | 42 |
2 回目のアクセスでは、memcached のキャッシュに保存された内容と一致し、最終的に 11 回のクエリーが実行された。その内、5 クエリーが MySQL キャッシュに保存された内容と一致し、キャッシュから返された。大幅に減少しており、かなりの高速化が見込めそうだ。検証する為に設定したクエリーの全文保存は、負荷が増加する為、通常運営時は無効にする。
-
# sed -i 's/log=/#log=/g' /etc/my.cnf
-
# service mysqld restart
パフォーマンス測定
httperf を使って、チューニング後のパフォーマンスを測定する。生成する負荷は、WordPress の 1 ページ (?p=3) に X={1,5,10.20.50} 人 (--rate=X) が同時にアクセスして、合計 100 回 (--num-conns=100) 表示されたらベンチマークを終了する。Apache の設定はデフォルト値とする。
-
# ssh 10.0.0.1 "service memcached restart"
-
# ssh 10.0.0.2 "service httpd restart"
-
# ssh 10.0.0.2 "service mysqld restart"
-
# sleep 3
-
# httperf --hog --server=10.0.0.1 --uri=/wordpress/?p=3 --num-conns=100 --num-calls=1 --rate=1
-
-
httperf --hog --client=0/1 --server=10.0.0.1 --port=80 --uri=/wordpress/?p=3 --rate=1 --send-buffer=4096 --recv-buffer=16384 --num-conns=100 --num-calls=1
-
Total: connections 100 requests 100 replies 100 test-duration 99.488 s
-
-
Connection rate: 1.0 conn/s (994.9 ms/conn, <=1 concurrent connections)
-
Connection time [ms]: min 459.9 avg 479.0 max 559.8 median 466.5 stddev 24.2
-
Connection time [ms]: connect 0.2
-
Connection length [replies/conn]: 1.000
-
-
Request rate: 1.0 req/s (994.9 ms/req)
-
Request size [B]: 75.0
-
-
Reply rate [replies/s]: min 1.0 avg 1.0 max 1.0 stddev 0.0 (19 samples)
-
Reply time [ms]: response 448.6 transfer 30.2
-
Reply size [B]: header 230.0 content 9911.0 footer 2.0 (total 10143.0)
-
Reply status: 1xx=0 2xx=100 3xx=0 4xx=0 5xx=0
-
-
CPU time [s]: user 27.90 system 71.59 (user 28.0% system 72.0% total 100.0%)
-
Net I/O: 10.0 KB/s (0.1*10^6 bps)
-
-
Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
-
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0
-
-
# ssh 10.0.0.2 "mysqladmin -u root extended-status | grep Max_used_connections"
-
-
| Max_used_connections | 1 |
-
-
# ssh 10.0.0.1 "service memcached restart"
-
# ssh 10.0.0.2 "service httpd restart"
-
# ssh 10.0.0.2 "service mysqld restart"
-
# sleep 3
-
# httperf --hog --server=10.0.0.1 --uri=/wordpress/?p=3 --num-conns=100 --num-calls=1 --rate=5
-
-
httperf --hog --client=0/1 --server=10.0.0.1 --port=80 --uri=/wordpress/?p=3 --rate=5 --send-buffer=4096 --recv-buffer=16384 --num-conns=100 --num-calls=1
-
Total: connections 100 requests 100 replies 100 test-duration 21.629 s
-
-
Connection rate: 4.6 conn/s (216.3 ms/conn, <=17 concurrent connections)
-
Connection time [ms]: min 528.4 avg 1948.2 max 8628.6 median 1789.5 stddev 1026.5
-
Connection time [ms]: connect 0.2
-
Connection length [replies/conn]: 1.000
-
-
Request rate: 4.6 req/s (216.3 ms/req)
-
Request size [B]: 75.0
-
-
Reply rate [replies/s]: min 3.6 avg 4.2 max 4.8 stddev 0.5 (4 samples)
-
Reply time [ms]: response 1897.1 transfer 50.9
-
Reply size [B]: header 230.0 content 9911.0 footer 2.0 (total 10143.0)
-
Reply status: 1xx=0 2xx=100 3xx=0 4xx=0 5xx=0
-
-
CPU time [s]: user 4.68 system 16.95 (user 21.6% system 78.4% total 100.0%)
-
Net I/O: 46.1 KB/s (0.4*10^6 bps)
-
-
Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
-
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0
-
-
# ssh 10.0.0.2 "mysqladmin -u root extended-status | grep Max_used_connections"
-
-
| Max_used_connections | 16 |
-
-
# ssh 10.0.0.1 "service memcached restart"
-
# ssh 10.0.0.2 "service httpd restart"
-
# ssh 10.0.0.2 "service mysqld restart"
-
# sleep 3
-
# httperf --hog --server=10.0.0.1 --uri=/wordpress/?p=3 --num-conns=100 --num-calls=1 --rate=10
-
-
httperf --hog --client=0/1 --server=10.0.0.1 --port=80 --uri=/wordpress/?p=3 --rate=10 --send-buffer=4096 --recv-buffer=16384 --num-conns=100 --num-calls=1
-
Total: connections 100 requests 100 replies 100 test-duration 22.186 s
-
-
Connection rate: 4.5 conn/s (221.9 ms/conn, <=65 concurrent connections)
-
Connection time [ms]: min 1423.8 avg 8411.0 max 18285.9 median 8540.5 stddev 3848.5
-
Connection time [ms]: connect 0.2
-
Connection length [replies/conn]: 1.000
-
-
Request rate: 4.5 req/s (221.9 ms/req)
-
Request size [B]: 75.0
-
-
Reply rate [replies/s]: min 2.4 avg 4.0 max 4.8 stddev 1.1 (4 samples)
-
Reply time [ms]: response 8321.4 transfer 89.4
-
Reply size [B]: header 230.0 content 9911.0 footer 2.0 (total 10143.0)
-
Reply status: 1xx=0 2xx=100 3xx=0 4xx=0 5xx=0
-
-
CPU time [s]: user 2.61 system 19.58 (user 11.8% system 88.2% total 100.0%)
-
Net I/O: 45.0 KB/s (0.4*10^6 bps)
-
-
Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
-
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0
-
-
# ssh 10.0.0.2 "mysqladmin -u root extended-status | grep Max_used_connections"
-
-
| Max_used_connections | 22 |
-
-
# ssh 10.0.0.1 "service memcached restart"
-
# ssh 10.0.0.2 "service httpd restart"
-
# ssh 10.0.0.2 "service mysqld restart"
-
# sleep 3
-
# httperf --hog --server=10.0.0.1 --uri=/wordpress/?p=3 --num-conns=100 --num-calls=1 --rate=20
-
-
httperf --hog --client=0/1 --server=10.0.0.1 --port=80 --uri=/wordpress/?p=3 --rate=20 --send-buffer=4096 --recv-buffer=16384 --num-conns=100 --num-calls=1
-
Maximum connect burst length: 1
-
-
Total: connections 100 requests 100 replies 100 test-duration 21.534 s
-
-
Connection rate: 4.6 conn/s (215.3 ms/conn, <=86 concurrent connections)
-
Connection time [ms]: min 1024.4 avg 10203.0 max 21183.5 median 10542.5 stddev 5459.2
-
Connection time [ms]: connect 0.2
-
Connection length [replies/conn]: 1.000
-
-
Request rate: 4.6 req/s (215.3 ms/req)
-
Request size [B]: 75.0
-
-
Reply rate [replies/s]: min 2.8 avg 4.2 max 5.0 stddev 1.0 (4 samples)
-
Reply time [ms]: response 10091.4 transfer 111.4
-
Reply size [B]: header 230.0 content 9911.0 footer 2.0 (total 10143.0)
-
Reply status: 1xx=0 2xx=100 3xx=0 4xx=0 5xx=0
-
-
CPU time [s]: user 1.81 system 19.73 (user 8.4% system 91.6% total 100.0%)
-
Net I/O: 46.3 KB/s (0.4*10^6 bps)
-
-
Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
-
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0
-
-
# ssh 10.0.0.2 "mysqladmin -u root extended-status | grep Max_used_connections"
-
-
| Max_used_connections | 22 |
-
-
# ssh 10.0.0.1 "service memcached restart"
-
# ssh 10.0.0.2 "service httpd restart"
-
# ssh 10.0.0.2 "service mysqld restart"
-
# sleep 3
-
# httperf --hog --server=10.0.0.1 --uri=/wordpress/?p=3 --num-conns=100 --num-calls=1 --rate=50
-
-
httperf --hog --client=0/1 --server=10.0.0.1 --port=80 --uri=/wordpress/?p=3 --rate=50 --send-buffer=4096 --recv-buffer=16384 --num-conns=100 --num-calls=1
-
Maximum connect burst length: 1
-
-
Total: connections 100 requests 100 replies 100 test-duration 21.443 s
-
-
Connection rate: 4.7 conn/s (214.4 ms/conn, <=98 concurrent connections)
-
Connection time [ms]: min 851.2 avg 11621.5 max 20695.9 median 11338.5 stddev 5828.4
-
Connection time [ms]: connect 0.2
-
Connection length [replies/conn]: 1.000
-
-
Request rate: 4.7 req/s (214.4 ms/req)
-
Request size [B]: 75.0
-
-
Reply rate [replies/s]: min 3.0 avg 4.3 max 5.8 stddev 1.2 (4 samples)
-
Reply time [ms]: response 11573.4 transfer 47.9
-
Reply size [B]: header 230.0 content 9911.0 footer 2.0 (total 10143.0)
-
Reply status: 1xx=0 2xx=100 3xx=0 4xx=0 5xx=0
-
-
CPU time [s]: user 1.98 system 19.47 (user 9.3% system 90.8% total 100.0%)
-
Net I/O: 46.5 KB/s (0.4*10^6 bps)
-
-
Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
-
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0
-
-
# ssh 10.0.0.2 "mysqladmin -u root extended-status | grep Max_used_connections"
-
-
| Max_used_connections | 25 |
チューニング後の測定結果のポイントとなる点を以下に示す。
| --rate=1 |
Request rate: 1.0 req/s Reply time [ms]: response 448.6 Errors: total 0 Max_used_connections 1 |
| --rate=5 |
Request rate: 4.6 req/ Reply time [ms]: response 1897.1 Errors: total 0 Max_used_connections 16 |
| --rate=10 |
Request rate: 4.5 req/s Reply time [ms]: response 8321.4 Errors: total 0 Max_used_connections 22 |
| --rate=20 |
Request rate: 4.6 req/s Reply time [ms]: response 10091.4 Errors: total 0 Max_used_connections 22 |
| --rate=50 |
Request rate: 4.7 req/s Reply time [ms]: response 11573.4 Errors: total 0 Max_used_connections 25 |
--rate=1 のときは、1 リクエストあたりの平均 response 448.6 [ms] で、まだまだサーバに余裕がある。--rate=5~50 をみると、Request rate が 4.5~4.7 req/s となっているため、サーバに余裕が無い状態を示している。MySQL への同時コネクション数は、初期設定では最大 100 だが、測定結果の Max_used_connections をみると、最大 25 となっている。このため、まだまだ MySQL 側には余裕があるがサーバからのリクエストが届いていない状態を表しており、MySQL 側がボトルネックになっている可能性は低いと考えられる。
[...] ■参考 http://blog.dealforest.net/2009/03/wordpress-%E3%81%AB-memcached-%E3%82%92%E4%BD%BF%E3%81%86%E6%89%8B%E9%A0%86/ http://na-ga.net/blog/?p=590 [...]