В продолжение статьи:
Ускорение и оптимизация PHP-сайта. Какие технологии стоит выбирать при настройке сервера под PHP
В отличии от предыдущего материала, в этой статье сделан упор на сравнение скорости отклика и интерпретации кода для различных версий PHP, включая PHP 7 beta3.
Для ранних версий PHP, проведено тестирование между оптимизаторами кода apc, xcache и opcaсhe.
Эта статья не содержит тестов на производительность, таких как нагрузочные тесты ab и siege. Возможно, об этом я напишу в одной из следующих статей.
В данном случае, меня не интересует сколько страниц за секунду способна сгенерировать та или иная версия php-интерпретатора, скорее то, с какой скоростью она сгенерирует мне страницу и с какой задержкой.
В данном случае разница в том, что тесты производительности замеряют отношение скорости интерпретатора к общим ресурсам сервера, а так же подготовленности других связанных компонентов web-системы к работе на повышенных нагрузках.
Остановимся на скорости и отклике. Очевидно что производительность зависит от скорости, но высокая скорость не может гарантировать высокую производительность. Это, возможно, связанно с тем, что недостаточно хорошо настроен web-сервер или база данных, а также с какими-то не было ограничениями, например сетевого стека.
Что бы не заниматься попыткой объять необъятное, мы просто замерим скорость и отклик работы интерпретаторов php, на мощном сервере без нагрузки, с одинаковыми конфигурациями web-сервера, базы данных и операционной системы для всех испытуемых. Используем конфигурацию php-fpm + nginx. База данных MariaDB. Все технические детали скрыты под спойлером ниже.
Так же вы можете прочитать другие мои публикации на тему «Идеального» кластера
- «Идеальный» кластер. Часть 3.1 Внедрение MySQL Multi-Master кластера
- «Идеальный» кластер. Часть 2.2: Высокодоступный и масштабируемый web-сервер, лучшие технологии на страже вашего бизнеса
- О виртуальном кластере на hetzner
- Frontend: NGINX + Keepalived (vrrp) на CentOS
- HAPRoxy для Percona или Galera на CentOS. Его настройка и мониторинг в Zabbix
- Zabbix 2.2 верхом на nginx + php-fpm и mariadb
Технические детали и конфигурации
Испытуемый сервер:
CPU: Intel Xeon E5-1620v2 4c/8t 3,7 GHz+/3,9 GHz+
RAM: 64 GB DDR3 ECC 1600 MHz
Intel DC S3500 Series 300 Гб.
Centos 6.7:
Linux 2.6.32-40-pve #1 SMP Fri Jul 24 11:16:05 CEST 2015 x86_64 x86_64 x86_64 GNU/Linux
sysctl:
net.ipv4.ip_forward=1
kernel.sysrq=1
net.ipv4.tcp_syncookies=1
net.bridge.bridge-nf-call-ip6tables=0
net.bridge.bridge-nf-call-iptables=0
net.bridge.bridge-nf-call-arptables=0
kernel.msgmnb=65536
kernel.msgmax=65536
kernel.shmmax=4294967295
kernel.shmall=268435456
net.netfilter.nf_conntrack_max=99999999
fs.inotify.max_user_watches=99999999
net.ipv4.tcp_max_tw_buckets=99999999
net.ipv4.tcp_max_tw_buckets_ub=65535
net.ipv4.tcp_max_syn_backlog=65536
net.core.somaxconn=65535
fs.file-max=99999999
kernel.sem=1000 128000 128 512
vm.dirty_ratio=5
fs.aio-max-nr=262144
kernel.panic=1
net.ipv4.conf.all.rp_filter=1
net.ipv4.conf.default.send_redirects=1
net.ipv4.conf.all.send_redirects=0
net.ipv4.ip_dynaddr=1
kernel.shmmni=4096
net.ipv4.tcp_keepalive_time=15
net.ipv4.tcp_keepalive_intvl=10
net.ipv4.tcp_keepalive_probes=5
net.ipv4.tcp_fin_timeout=30
net.ipv4.tcp_window_scaling=0
net.ipv4.tcp_sack=0
net.ipv4.tcp_timestamps=0
PHP
PHP 5.3.29 (cli) (built: Aug 14 2014 14:15:02)
Copyright 1997-2014 The PHP Group
Zend Engine v2.3.0, Copyright 1998-2014 Zend Technologies
PHP 5.3.29 (cli) (built: Aug 14 2014 14:15:02)
Copyright 1997-2014 The PHP Group
Zend Engine v2.3.0, Copyright 1998-2014 Zend Technologies
with XCache v3.2.0, Copyright 2005-2014, by mOo
with XCache Cacher v3.2.0, Copyright 2005-2014, by mOo
PHP 5.3.29 (cli) (built: Aug 14 2014 14:15:02)
Copyright 1997-2014 The PHP Group
Zend Engine v2.3.0, Copyright 1998-2014 Zend Technologies
with Zend OPcache v7.0.5, Copyright 1999-2015, by Zend Technologies
The Zend Engine API version 220100525 which is installed, is newer.
Contact Zend Technologies at www.zend.com for a later version of Zend Guard Loader.
PHP 5.4.42 (cli) (built: Jun 12 2015 09:19:10)
Copyright 1997-2014 The PHP Group
Zend Engine v2.4.0, Copyright 1998-2014 Zend Technologies
PHP 5.4.42 (cli) (built: Jun 12 2015 09:19:10)
Copyright 1997-2014 The PHP Group
Zend Engine v2.4.0, Copyright 1998-2014 Zend Technologies
with XCache v3.2.0, Copyright 2005-2014, by mOo
with XCache Cacher v3.2.0, Copyright 2005-2014, by mOo
PHP 5.5.27 (cli) (built: Jul 10 2015 23:40:40)
Copyright 1997-2015 The PHP Group
Zend Engine v2.5.0, Copyright 1998-2015 Zend Technologies
PHP 5.6.11 (cli) (built: Jul 10 2015 22:43:20)
Copyright 1997-2015 The PHP Group
Zend Engine v2.6.0, Copyright 1998-2015 Zend Technologies
PHP 7.0.0beta3 (cli) (built: Aug 5 2015 19:11:12)
Copyright 1997-2015 The PHP Group
Zend Engine v3.0.0-dev, Copyright 1998-2015 Zend Technologies
XCache
[xcache]
xcache.shm_scheme = «mmap»
xcache.size = 1G
xcache.count = 8
xcache.slots = 8K
xcache.ttl = 3600
xcache.gc_interval = 3600
xcache.var_size = 64M
xcache.var_count = 2
xcache.var_slots = 8K
xcache.var_ttl = 3600
xcache.mmap_path = "/tmp/xcache"
xcache.cacher = On
xcache.stat = On
xcache.optimizer = On
xcache.test = Off
xcache.readonly_protection = Off
[xcache.coverager]
xcache.coverager = Off
xcache.coveragedump_directory = ""
OpCache
zend_extension=opcache.so
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=1024
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=3907
opcache.fast_shutdown=1
opcache.blacklist_filename=/etc/php.d/opcache*.blacklist
APC
extension = apc.so
apc.enabled=1
apc.shm_size=1024M
apc.ttl=86400
apc.user_ttl=7200
apc.num_files_hint=20000
apc.enable_cli=1
apc.cache_by_default=1
Nginx:
nginx version: nginx/1.9.3
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 --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 --http-client-body-temp-path=/var/cache/nginx/client_body --http-proxy-temp-path=/var/cache/nginx/proxy --http-fastcgi-temp-path=/var/cache/nginx/fastcgi --http-uwsgi-temp-path=/var/cache/nginx/uwsgi --http-scgi-temp-path=/var/cache/nginx/scgi --lock-path=/var/run/nginx.lock --pid-path=/var/run/nginx.pid --lock-path=/var/lock/subsys/nginx --user=nginx --group=nginx --with-file-aio --with-ipv6 --with-http_ssl_module --with-http_spdy_module --with-http_realip_module --with-http_addition_module --with-http_xslt_module --with-stream_ssl_module --with-stream --with-threads --with-http_image_filter_module --with-http_geoip_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-mail_ssl_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_stub_status_module --with-http_perl_module --with-mail --with-pcre --with-debug --add-module=/usr/src/nginx-1.9.3/ModSecurity-master/nginx/modsecurity --add-module=/usr/src/nginx-1.9.3/ngx_cache_purge-master --add-module=/usr/src/nginx-1.9.3/ngx_pagespeed-master --add-module=/usr/src/nginx-1.9.3/nginx-push-stream-module-master --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic' --with-ld-opt=-Wl,-E
worker_processes auto;
timer_resolution 100ms;
pid /var/run/nginx.pid;
thread_pool default threads=32 max_queue=655360;
events {
worker_connections 10000;
multi_accept on;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$host — $remote_user [$time_local] "$request"' '$status $body_bytes_sent "$http_referer"' '"$http_user_agent" "$http_x_forwarded_for"';
log_format defaultServer '[$time_local][$server_addr] $remote_addr ($http_user_agent) -> "$http_referer" $host "$request" $status';
log_format downloadsLog '[$time_local] $remote_addr "$request"';
log_format Counter '[$time_iso8601] $remote_addr $request_uri?$query_string';
access_log off;
access_log /dev/null main;
error_log /dev/null;
connection_pool_size 256;
client_header_buffer_size 4k;
client_max_body_size 600m;
large_client_header_buffers 8 32k;
request_pool_size 4k;
output_buffers 1 32k;
postpone_output 1460;
gzip on;
gzip_min_length 1000;
gzip_proxied any;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript text/x-javascript application/javascript;
gzip_disable «msie6»;
gzip_comp_level 6;
gzip_http_version 1.0;
gzip_vary on;
sendfile on;
aio threads;
directio 10m;
tcp_nopush on;
tcp_nodelay on;
server_tokens off;
keepalive_timeout 75 20;
server_names_hash_bucket_size 128;
server_names_hash_max_size 8192;
ignore_invalid_headers on;
server_name_in_redirect off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.4.4 8.8.8.8 valid=300s;
resolver_timeout 10s;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'AES128+EECDH:AES128+EDH';
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_session_cache shared:SSL:50m;
ssl_prefer_server_ciphers on;
ssl_trusted_certificate /etc/ssl/certs/ca-certs.pem;
spdy_headers_comp 1;
add_header Alternate-Protocol 443:npn-spdy/3;
add_header Strict-Transport-Security «max-age=63072000; includeSubdomains;»;
add_header X-Content-Type-Options nosniff;
proxy_buffering off;
proxy_buffer_size 8k;
proxy_buffers 8 64k;
proxy_connect_timeout 300m;
proxy_read_timeout 300m;
proxy_send_timeout 300m;
proxy_store off;
proxy_ignore_client_abort on;
fastcgi_read_timeout 300m;
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
proxy_cache_path /var/cache/nginx/page levels=2 keys_zone=pagecache:100m inactive=1h max_size=10g;
fastcgi_cache_path /var/cache/nginx/fpm levels=2 keys_zone=FPMCACHE:100m inactive=1h max_size=10g;
fastcgi_cache_key "$scheme$request_method$host";
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
upstream memcached_backend { server 127.0.0.1:11211; }
real_ip_header X-Real-IP;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
allow all;
server {
listen 80 reuseport;
}
include /etc/nginx/conf.d/*.conf;
}
server {
listen *:80;
server_name habratest.livelinux.ru www.habratest.livelinux.ru;
root /var/www/habratest.livelinux.ru/web;
index index.html index.htm index.php index.cgi index.pl index.xhtml;
error_page 400 /error/400.html;
error_page 401 /error/401.html;
error_page 403 /error/403.html;
error_page 404 /error/404.html;
error_page 405 /error/405.html;
error_page 500 /error/500.html;
error_page 502 /error/502.html;
error_page 503 /error/503.html;
recursive_error_pages on;
location = /error/400.html {
internal;
}
location = /error/401.html {
internal;
}
location = /error/403.html {
internal;
}
location = /error/404.html {
internal;
}
location = /error/405.html {
internal;
}
location = /error/500.html {
internal;
}
location = /error/502.html {
internal;
}
location = /error/503.html {
internal;
}
error_log /var/log/ispconfig/httpd/habratest.livelinux.ru/error.log;
access_log /var/log/ispconfig/httpd/habratest.livelinux.ru/access.log combined;
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
location /stats/ {
index index.html index.php;
auth_basic «Members Only»;
auth_basic_user_file /var/www/clients/client1/web1/web/stats/.htpasswd_stats;
}
location ^~ /awstats-icon {
alias /usr/share/awstats/icon;
}
location ~ \.php$ {
try_files /70b2e8b422a0dce8501e61dafabafa26.htm php;
}
location php {
try_files $uri =404;
include /etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_intercept_errors on;
}
location / {
try_files $uri @rewrite;
}
location @rewrite {
rewrite ^ /index.php;
}
}
php-fpm:
[web1]
listen = /var/lib/php5-fpm/web1.sock
listen.owner = web1
listen.group = client1
listen.mode = 0660
user = web1
group = client1
pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 5
pm.max_requests = 0
chdir = /
php_admin_value[open_basedir] = /var/www/clients/client1/web1/web:/var/www/clients/client1/web1/private:/var/www/clients/client1/web1/tmp:/var/www/habratest.livelinux.ru/web:/srv/www/habratest.livelinux.ru/web:/usr/share/php5:/usr/share/php:/tmp:/usr/share/phpmyadmin:/etc/phpmyadmin:/var/lib/phpmyadmin
php_admin_value[session.save_path] = «tcp://localhost:11211»
php_admin_value[upload_tmp_dir] = /var/www/clients/client1/web1/tmp
php_admin_value[sendmail_path] = "/usr/sbin/sendmail -t -i -fwebmaster@habratest.livelinux.ru"
MariaDB:
Server version: 10.0.21-MariaDB MariaDB Server
[mysqld]
symbolic-links=0
default_storage_engine = InnoDB
innodb_file_per_table = 1
event_scheduler=on
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
connect_timeout = 600000
wait_timeout = 28800
max_connections = 600
max_allowed_packet = 512M
max_connect_errors = 10000
net_read_timeout = 600000
connect_timeout = 600000
net_write_timeout = 600000
innodb_open_files = 512
innodb_buffer_pool_size = 2G
innodb_buffer_pool_instances = 2
innodb_file_format = barracuda
innodb_locks_unsafe_for_binlog = 1
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
transaction-isolation = READ-COMMITTED
innodb-data-file-path = ibdata1:10M:autoextend
innodb-log-file-size = 256M
innodb_log_buffer_size = 8M
skip-name-resolve
skip-external-locking
skip-innodb_doublewrite
query_cache_size = 128M
query_cache_type = 1
query_cache_min_res_unit = 2K
join_buffer_size = 8M
read_rnd_buffer_size = 3M
table_definition_cache = 2048
table_open_cache = 2048
thread_cache_size = 128
tmp_table_size = 200M
max_heap_table_size = 200M
log_error = /var/log/mysql/mysql-error.log
key_buffer_size = 256M
optimizer_switch='derived_merge=off,derived_with_keys=off'
Как будем тестировать?
В текущем сервере, установлен zabbix-prox и его задачи каждую минуту:
- Открывать главную страницу испытуемого сайта, дожидаться определенного содержимого на странице, убеждаться, что ответ от сервера — код 200.
- Следующим шагом идет авторизация в админку сайта, это происходит отправкой соответсвующего POST запроса. Сверка текста и кода ответа на странице с заложенным эталоном. Этот шаг касается почти всех подсистем web-сервера, и во многом его скорость зависит от скорости взаимодействия с базой данных
- Последним шагом является выход из админки сайта, сверка кода ответа и текста на странице выхода
- По итогам каждого шага, zabbix будет скрупулезно замерять и записывать скорость рендеринга php-кода в html понятный браузеру и демонстрировать нам графики полученных результатов
- Для каждого испытуемого будут записываться значения в течение одного часа и в качестве результата будет выступать средние значения за этот час
- Скорость измеряется в KBps (килобайт в секунду), а отклик в ms (миллисекундах)
- Тестирование будет с того же сервера, при обращении через localhost, так что влияние на результат скорости интернет-соединения исключено
Тестирование:
Сравнение скорости интерпретации страницы и времени отклика, для всех версий PHP, без использования оптимизаторов:
Чем выше результат (KBps), тем лучше
Чем ниже результат (ms), тем лучше
Сравнение скорости интерпретации страницы и времени отклика, для всех версий PHP, с использованием Opcache:
Чем выше результат (KBps), тем лучше
Чем ниже результат (ms), тем лучше
Сравнение скорости интерпретации страницы и времени отклика, PHP54, с использованием APC, xCache и Opcache
Чем выше результат (KBps), тем лучше
Чем ниже результат (ms), тем лучше
Сравнение скорости интерпретации страницы и времени отклика, PHP53, с использованием APC, xCache и Opcache
Чем выше результат (KBps), тем лучше
Чем ниже результат (ms), тем лучше
По вопросам сотрудничества, мои контакты в профиле