HHVM (hip-hop): Сравнительное тестирование и настройка

b850c84df183e7de53fed67ed1ccebe2

Сегодня мы делимся результатами тестирования php скрипта с и без HHVM на скорость, а также сразу смотрим, как это внедряется, например на Fedora 20. Хотя об этом уже писали здесь, а здесь даже проводили нечто подобное, для верности напомним: HHVM PHP (hip-hop) — это открытая виртуальная машина спроектированная для выполнения программ написанных на PHP и HACK. Использует JIT компиляцию и была разработана в Facebook. 



Тест: HHVM + NGINX + FASTCGI vs. PHP-FPM + NGINX



Тестовый скрипт представляет из себя много регулярок, арифметических действий и обращений к базе.

В идеале для тестирования hhvm на скорость в скрипте не должно быть обращений к базе, они присутствуют в тесте только из-за того что он был нужен для текущих дел.

Софт:
Fedora 20
HipHop VM 2.4.0 (rel)
nginx/1.4.4
PHP 5.5.12



Софт для теста: ab.
3000 запросов к скрипту в 10 потоков.

Чистый hhvm 13.665 seconds

Concurrency Level: 10
Time taken for tests: 13.665 seconds
Complete requests: 3000
Failed requests: 0
Total transferred: 2142000 bytes
HTML transferred: 1842000 bytes
Requests per second: 219.54 [#/sec] (mean)
Time per request: 45.549 [ms] (mean)
Time per request: 4.555 [ms] (mean, across all concurrent requests)
Transfer rate: 153.08 [Kbytes/sec] received



nginx-fastcgi-php 31.406 seconds

Concurrency Level: 10
Time taken for tests: 31.406 seconds
Complete requests: 3000
Failed requests: 0
Total transferred: 2328000 bytes
HTML transferred: 1842000 bytes
Requests per second: 95.52 [#/sec] (mean)
Time per request: 104.688 [ms] (mean)
Time per request: 10.469 [ms] (mean, across all concurrent requests)
Transfer rate: 72.39 [Kbytes/sec] received



Вывод: hhvm быстрее в 2.29 раза.

Замеры фрагментов кода внутри скрипта:

b12d9ce2f6eb472a78b75edc38561ad9

69f7ea409e4e17c31cb3f2ad993b56bd

Графики построены по средним показателям за 1000 замеров.

По итогам замеров фрагментов кода видно что HHVM быстрее в 2,77 раза чем NGINX-FASTCGI-PHP. 
На графике синим отмечен наиболее ускоренный участок кода (масса регулярок), он был ускорен в 113 раз!

Практическое применение



Задача: У нас есть проект, который обрабатывает очень много запросов. По этому проекту — около 10 серверов. Нужно в несколько раз сократить ресурс – либо меньше серверов, либо меньше данных.

Решение: Виртуальная машина для ускорения производительности HHVM устанавливается на сервер и через неё можно прогонять выполнение php скриптов. Результат: необходимое ускорение.

Подобный способ решения тем больше подходит, чем больше масштаб: если это большой проект в масштабах Facebook (создатели HHVM), в котором задействованы десятки тысяч серверов – сокращение их в два-три раза даёт ощутимый результат. По результатам нашего тестирования – на некоторых участках кода можно разогнать его в 113 раз – но об этом позже. 

Конечно, у всего есть свои плюсы и минусы, HHVM не исключение, поэтому целесообразно сразу их обозначить:

Плюсы: 
• ускорение выполнения PHP (в моём тесте на крупном блоке регулярок было ускорение в 113 раз, в целом же тестовый скрипт был ускорен в ~2 раза по причине большего количества обращений к бд.).

Минусы: 
• не поддерживает php-mysqli (нужно использовать mysql или PDO)
• наблюдались падения сервера с PHP ошибкой о неожиданной встрече конца файла (после перезапуска сервера он продолжал работу).

Внедрение: Установка и настройка HHVM PHP (hip-hop) на Fedora 20



24aec0a2e836959173ff8cf97b7dfe75

Конечно, применить HHVM для ускорения PHP — штука довольно очевидная и наверняка кто-то это уже делал, даже для Fedora. Но в русских источниках по этой теме информации значительно меньше, чем хотелось бы, поэтому делюсь сегодня небольшим, но вполне самодостаточным tutorial, от начала и до конца, как установить это на Fedora и проверить работу. 

Я использовал Fedora 20, однако настройка для других ОС в принципе похожа, а ссылку на англоязычный источник для них можно найти в конце поста. Удобно то, что сейчас готовые пакеты ставятся одной командой – их не надо собирать в ручную. «На заре» HHVM открытые исходники было сложно устанавливать, но сейчас это, к счастью, уже в прошлом: теперь, если действовать по мануалу, можно установить всё и проверить, в принципе, за час. Настройка и установка укладывается в 6 последовательных шагов.

Шаг 1: Добавление репозитория в систему



Первым делом, добавляем репозиторий в нашу систему. Для этого создадим и откроем файл на редактирование /etc/yum.repos.d/hhvm.repo

Это можно сделать например так:
vi /etc/yum.repos.d/hhvm.repo 

Запишем в него следующие строки:

[hhvm]
name=HHVM for Fedora $releasever - $basearch
baseurl=http://dl.hhvm.com/fedora/$releasever/$basearch/



Если вы пользуетесь редактором vi то после открытия файла нажмите “i” затем введите строки, далее нажмите Esc и после нажмите Shift+z+z.

Затем устанавливаем HHVM:
rpm --import http://dl.hhvm.com/conf/hhvm.gpg.key yum install hhvm

Во во время установки возникнет диалог о инсталляции требуемых компонентов (Is this ok [y/d/N]:). Отвечаем — “да”, командой:
y

После этого мы видим список установленных компонентов и в конце строку “Complete!”.

Далее идём править конфиг — /etc/hhvm/config.hdf.

Например так:

vi /etc/hhvm/config.hdf 

Вот пример рабочего конфига (скорей всего в нём вам нужно будет изменить только корневой путь):

Log {
 Level = Error
 UseLogFile = true
 File = /var/log/hhvm-error.log
 Access {
   * {
     File = /var/log/hhvm-access.log
     Format = %h %l %u %t \"%r\" %>s %b
   }
 }
}
MySQL {
 TypedResults = false
}
Server {
Port = 4849     #порт на котором будет работать hhvm
SourceRoot = /home/www/site/public_html     #путь к корню ваших php файлов
Type = fastcgi
#ThreadCount = 50
}
Eval {
  # set to true to enable JIT compiler
  # If hhvm crashes you can turn this off to see if the problem
  # is in the JIT.
  Jit = true
}



Заменяем конфиг по умолчанию на тот, что предложен выше, и правим корневой путь.

Шаг 2: запуск HHVM



Теперь мы можем запустить HHVM. Здесь у нас два варианта – запуск в моде сервера или в моде демона.

Запуск в моде сервера — будет вывод прямо в консоль ошибок и прочего: hhvm -m server -c /etc/hhvm/config.hfd 

Запуск в моде демона — фоновая работа: hhvm -m daemon -c /etc/hhvm/config.hfd

Если вы в конфиге hhvm закомментируете — Type = fastcgi (#Type = fastcgi), то можно прям сейчас проверить его работу. После правки конфига нужно перезапустить hhvm.

Чтобы перезапустить hhvm в режиме демона вводим:
netstat -lnp 

Видим список программ и их pid, находим hhvm, копируем его pid, вводим команду. kill pid В этой команде pid заменяем на найденный в списке номер процесса. Вводим повторно netstat -lnp для того чтобы убедится в смерти процесса. Далее запускаем hhvm в любом из модов.

Чтобы перезапустить hhvm в режиме сервера просто нажимаем Ctrl+c и далее запускаем hhvm в любом из модов.

Шаг 3: Добавляем PHP скрипт



После этих манипуляций положим любой php скрипт в корневой каталог указанный в конфиге hhvm.

Обращаемся к нему следующим образом:
http://поменяй_на_свой_домен:4849/имя_php_скрипта.php

Если обработанного php скрипта не видим то смотрим лог ошибок в консоли (в случае hhvm -m server), либо в файле лога ошибок командойtail /var/log/hhvm-error.log (в случае hhvm -m daemon).

Далее, если вы тестировали hhvm и закомментировали Type = fastcgi в конфиге, то раскомментируем его и перезагружаем hhvm. Если вы этого не делали то оставляем всё как есть и идём дальше.

Шаг 4: Настройка NGINX



Настроим nginx для проброса fastcgi в hhvm. Для этого модифицируем конфиг nginx, он тут /etc/nginx/nginx.conf. Там должна появиться следующая запись:

location ~ \.php$ {
    #Не забудьте поправить пути на ваши (/home/www/site/public_html).
           root           /home/www/site/public_html;
           fastcgi_pass   127.0.0.1:4849; # проброс запроса к hhvm
           fastcgi_index  index.php;
           fastcgi_param  SCRIPT_FILENAME  /home/www/site/public_html$fastcgi_script_name;
           include        fastcgi_params;
       }



Остальные настройки nginx по вкусу (главное чтобы он слушал 80 порт — server {listen 80;} ). После этого перезагружаем nginx командой:
nginx -s reload

Теперь мы имеем связку nginx — впереди на 80 порту, hhvm — позади на 4849 порту.

Шаг 5: Проверка работы HHVM + NGINX + FASTCGI



Запрашиваем адрес: поменяй_на_свой_домен/имя_php_скрипта.php
Должны увидеть обработанный php скрипт. 
Не забываем что nginx и hhvm должны быть включены.
Если скрипта не видим идём смотреть лог ошибок. В случае hhvm -m server, прям в консоли, в случае hhvm -m daemon в файле лога ошибок например так:
tail /var/log/hhvm-error.log

Вот на всякий случай рабочий конфиг nginx для связки c hhvm:

user  apache;
worker_processes  10;
events {
   worker_connections  1000;
}
worker_rlimit_nofile 50000;
http {
   include       mime.types;
   default_type  application/octet-stream;
   log_format  my_combined  '$remote_addr - $remote_user [$time_local] '
   '"$request" $status $body_bytes_sent '
   '"$http_referer" "$http_user_agent" '
   '$upstream_response_time "$host"'
   sendfile        on;
   keepalive_timeout  10;
   limit_zone   lconn  $binary_remote_addr  10m;

   server {
       client_max_body_size 1000k;
       fastcgi_read_timeout 1m;
       listen       8080;
       listen       80;
       server_name  site.ru; #меняем на свой домен
       access_log  /var/log/nginx/site.ru-access_log my_combined; #меняем на свой домен
       error_log  /var/log/nginx/site.ru-error_log; #меняем на свой домен
       limit_conn   lconn  100;
       root   /home/www/site/public_html; #меняем путь на свой
       index  index.php index.html index.htm;
       error_page   500 502 503 504  /50x.html;
       location = /50x.html {
           root   html;
       }
       location ~ \.php$ {
           root           /home/www/site/public_html; #меняем путь на свой
           fastcgi_pass   127.0.0.1:4849;
           fastcgi_index  index.php;
           #меняем путь на свой
           fastcgi_param  SCRIPT_FILENAME  /home/www/site/public_html$fastcgi_script_name; 
           include        fastcgi_params;
       }
   }
}



Шаг 6: Добавление HHVM в автозагрузку



Если вы будете использовать hhvm постоянно вам нужно будет добавить его в автозагрузку. 

Открываем файл — /etc/init.d/hhvm на редактирование например так:

vi /etc/init.d/hhvm 

Заменяем всё его содержимое на следующее:

#! /bin/sh
#
# hhvm Daemon for HHVM
#
# chkconfig: 2345 20 20
#
# description: HHVM is an open-source virtual machine designed for executing programs written in Hack and PHP

test -x /usr/bin/hhvm || exit 0

case "$1" in
 start)
       /usr/bin/hhvm --config /etc/hhvm/config.hdf --mode daemon
       ;;
 stop)
       start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/hhvm/pid
       ;;

 reload|force-reload|restart|try-restart)
       $0 stop
       $0 start
       ;;

 status)
       echo "No status"
       ;;

 *)
       echo "Usage: /etc/init.d/hhvm {start|stop|restart|status}"
       exit 1
esac

exit 0



Сохраняем.
Затем вводим команду:
chkconfig hhvm on

Готово! Демон hhvm будет запускаться при старте системы.

Конечно, у каждого свой путь – как конкретно это интегрировать, каждый решает сам. Тем не менее здесь всё работает именно так и собралось за минимальное количество времени — думаю, вполне можно исппользовать в живых условиях, когда нужно неплохо так сэкономить на количестве серверов, тем более если сделать это можно на основе решения с открытым кодом.

Тут об этом уже писали ранее:
Обзор
Установка HHVM на Nginx 
Тест: сравнение HHVM с нативным интерпретатором 

Тут можно взять HHVM в открытом доступе:
Github
Facebook 
Сообщество

Тут можно почитать про технологию:
Википедия на английском
Википедия на русском