О переносе CMS 1C:Bitrix на другой хостинг и кешировании


Описанные ниже результаты получены и проверены на "1С-Битрикс: Управление сайтом 15.5.10" Последнее обновление: 07.03.2016 13:29:32.

Проблемы после переезда под nginx+php

При переезде с конфигурации на вебсервере Apache 2.4 + mod_php5 на конфигурацию nginx + php-fpm (файлы php.ini, версии и наборы модулей php идентичны) админы и вебмастера сталкиваются с проблемами самого разного свойства.

Выражаться такие проблемы могут по разному. Например - не редактируются темы и сообщения форума. При попытке редактировать сообщение форума форма редактирования появляется, но все поля пусты, не содержат контента. Связано это с передачей параметров php скриптам, а также с неидеальным переводом правил .htaccess в правила nginx.

В данной статье я привожу правильную конфигурацию с небольшим пояснением, что делают её части,

Правильная конфигурация nginx+php-fpm для Битрикса

Постановка задачи

На сайте, для которого пришлось решать все эти проблемы, есть И ЧПУ, причём как со слешем на конце, так и без оного, И страницы с параметрами в запросе! Это решительно не позволяло применить ни один из встречающихся в сети "готовых конфигов nginx". А весь мой опыт SEO показывает, что старые посещаемые урлы надо беречь как зеницу ока.

Собственно конфиг хоста nginx

# nginx+php-fpm pure, nocache version ========================================
server {
    listen 80;
    charset        windows-1251;
    source_charset windows-1251;
    limit_conn arbeit 32;
    server_name trauma.ru www.trauma.ru trauma.ru.d2.gfns.ru;
    keepalive_timeout 75 75;

    include /usr/local/etc/nginx/mime.types;
    default_type text/html;

    root       /home/www/servers/trauma.ru/html;
    access_log /home/www/servers-logs/trauma.ru/access_log;
    error_log  /home/www/servers-logs/trauma.ru/error_log;

# directories to work with their index files           Чтобы работали index.php
    index      index.php;

# uri /blog/aldid/test and so on works                       Чтобы работали ЧПУ
    error_page 404 /404.php;
    if (!-e $request_filename) {
       rewrite  ^(.*)$  /bitrix/urlrewrite.php last;
    }

# causes /blog and /blog/ uri to be identical    Со слешем и без слеша на конце
    location / {
       try_files  $uri $uri/ =404;
    }

# php-fpm upstream                                     Взаимодействие с php-fpm
    location ~ \.php$ {
        fastcgi_index   index.php;
        fastcgi_param   DOCUMENT_ROOT     $document_root;
        fastcgi_param   SCRIPT_FILENAME   $document_root$fastcgi_script_name;
        fastcgi_param   PATH_INFO         $fastcgi_path_info;
        fastcgi_param   QUERY_STRING      $args;
        fastcgi_param   CONTENT_TYPE      $content_type;
        fastcgi_param   CONTENT_LENGTH    $content_length;
        fastcgi_param   SERVER_NAME       $server_name;
        fastcgi_param   REQUEST_URI       $request_uri;
        fastcgi_param   DOCUMENT_URI      $document_uri;
        fastcgi_param   REQUEST_METHOD    $request_method;
        fastcgi_param   REMOTE_ADDR       $remote_addr;
        fastcgi_param   REMOTE_USER       $http_authorization;
        fastcgi_intercept_errors        on;
        fastcgi_ignore_client_abort     off;
        fastcgi_connect_timeout 60;
        fastcgi_send_timeout 180;
        fastcgi_read_timeout 180;
        fastcgi_buffer_size 128k;
        fastcgi_buffers 4 256k;
        fastcgi_busy_buffers_size 256k;
        fastcgi_temp_file_write_size 256k;

        default_type text/html;

        fastcgi_pass    unix:/var/run/php-fpm.sock;
        }

# all static files quickly return.       Непосредственная отдача статик файлов
# and ask browser to cache them all.     И браусеру говорим кешировать их всех
    location ~* ^.+\.(jpg|jpeg|gif|png|svg|js|css|mp3|ogg|mpe?g|avi|zip|gz|bz2?|rar|swf|xml|txt)$ {
        access_log        /dev/null ;
        expires           max;
    }

#+ Close some uri for security       Закрыть некоторые адреса для безопасности
    location ~ (/\.ht|/bitrix/modules|/upload/support/not_image/|/.svn/) {
        deny all;
    }
}

Установленные модули php

На 6 января 2017 года bitrix работает у меня на сервере при следующем наборе модулей (некоторые из них, правда, поставлены не ради битрикса):
php56-bcmath php56-bz2 php56-calendar php56-ctype php56-curl php56-dba php56-dom php56-exif php56-extensions php56-fileinfo php56-filter php56-ftp php56-gd php56-gettext php56-hash php56-iconv php56-imap php56-json php56-mbstring php56-mcrypt php56-mysql php56-mysqli php56-opcache php56-openssl php56-pcntl php56-pdo php56-pdo_mysql php56-pdo_sqlite php56-phar php56-posix php56-pspell php56-session php56-shmop php56-simplexml php56-soap php56-sockets php56-sqlite3 php56-tokenizer php56-wddx php56-xml php56-xmlreader php56-xmlwriter php56-xsl php56-zip php56-zlib

Критичные параметры php.ini

/usr/local/etc/php.ini отредактирован в соответствии с запросами Битрикса:
short_open_tag = On
output_buffering = Off
realpath_cache_size = 8192k
max_input_vars = 10000
; default_charset = "UTF-8"
cgi.fix_pathinfo=1
upload_max_filesize = 20M
date.timezone = "Europe/Moscow" ; Note! Server works in really GMT/UTC!
pcre.recursion_limit=4000
[opcache]
opcache.max_accelerated_files = 400000
opcache.revalidate_freq = 0

Не удаётся загрузить картинку ни в каком из интерфейсов работы с контентом

Сообщение: "не создан временный каталог для загрузки" на месте картинки.

Все попытки обращаться к техподдержке и поиска в сети приводят к единственному ответу - "сделайте правильными права и владельцев каталогов и файлов". Однако это не помогает! Проблема заключется в том, что абсолютные пути к корневому логу сайта различны на разных хостингах (живой пример ниже), а процедура восстановления из резервной копии (restore.php) не исправляет путей, содержащихся в дампе базы:

  1. /home/t/trauma/public_html/ - корень сайта на старом хостинге
  2. /home/www/servers/trauma.ru/html/ - корень сайта на новом хостинге
Есть два варианта исправления:
  1. Доступный только сисадмину хостингового сервера, зато простой:
    mkdir -p /home/t/trauma
    ln -s /home/www/servers/trauma.ru/html/ /home/t/trauma/public_html
  2. Доступный техподдержке Битрикса: Очень хотелось бы чтобы restore.php:
    1. Выводил на соответствующем экране информацию о том, каков в настоящее время путь DOCUMENT_ROOT, и какой сохранён в резервной копии. Пусть даже они совпадают.
    2. При установке чекбокса автоматически находил и исправлял полные пути к корню сайта, содержащиеся в дампе резервной копии, со старого состояния на новое

Об ускорении работы Bitrix

Если Вы заглянули в панель быстродействия, Вы скорее всего увидели требование Bitrix о быстродействии файловой системы не менее 10000 операций в секунду. В реальности не существует относительно дешёвых хостингов, которые бы удовлетворяли этому дикому требованию, так как кеш дисковой подсистемы чрезвычайно быстро вымывается при работе данной CMS.

Настройка Автокомпозитного сайта при этих условиях не приносит желаемого радикального скачка быстродействия, однако!!!

На самом деле есть очень эффективное решение поднять скорость отдачи страниц, отдав некоторую часть оперативной памяти программе memcached и настроив автокомпозитный сайт на работу именно через memcached. Это уменьшает число обращений к базе данных и делает скорость работы файловой системы не столь критичным параметром, как считают авторы Битрикса.

На сайте МосрентгенЦентра время загрузки HTML страницы с сервера уменьшилось с 1.5-6 секунд до 0.08-1.5 секунд только в результате описанных ниже настроек.

Необходимые для этого действия в FreeBSD (10+ версии)

  1. pkg install pecl-memcached - Установка memcached, libmemcached и интерфейса в php к нему
  2. Настройка автозапуска memcached с 256М памяти отведённой под кеш:
    echo '
    memcached_enable="YES"
    memcached_flags="-d -m 256 -u nobody -l 127.0.0.1"
    '>>/etc/rc.conf
  3. /usr/local/etc/rc.d/memcached start - запуск memcached
  4. Композитный сайт - таб Настройки - внизу механизм хранения кеша - выбрать memcached выбрать адрес localhost и порт 11211 и проверить соединение. После чего нажать кнопку "Сохранить"
  5. Включить Автокомпозит
  6. Наслаждаться

Тестирование других вариантов ускорения

При тестировании применялся плагин просмотра заголовков http к браусеру чтобы убедиться, отдаётся ли страница из кеша, или нет. Для этого в конфиг nginx добавлены строки add_header X-Cache-Engine "Debug: ...";

memcached + nginx

Я попробовал сделать кеширование страниц Битрикса целиком в виде HTML, а отдачу их через nginx.

В сети я находил упоминания, что memcached хранит данные запакованные deflate, и даже если в nginx явно указать add_header Content-Encoding deflate; перед memcached_pass localhost:11211; - memcached не рисует правильного заголовка deflate для браусера, и браусеры показывают или сообщение о инвалид енкодинг, или отображают мусор вместо страницы. Для этого пришлось отключить компрессию самим memcached и упаковывать контент gzencode/gzdecode. Для чего я изменил файл /bitrix/modules/main/lib/data/memcachedconnection.php следующим образом (так выделено добавленное):

	$this->isConnected = $this->resource->addServer($this->host, $this->port);
	$this->isConnected->setOption( Memcached::OPT_COMPRESSION , false ); // Sergej Qkowlew. Turn OFF own deflate
	$this->isConnected->setOption( Memcached::OPT_BINARY , true ); // Sergej Qkowlew. Turn ON binary
...
	return gzdecode($this->resource->get($key));
...
	return $this->resource->set($key, gzencode($value));
и отредактировать довольно сложным способом конфиг nginx'a (напоминаю, на trauma.ru есть И ЧПУ И страницы с параметрами в запросе! Относящиеся к сжатию строки помечены так):
# nginx + php-fpm +memcached via nginx gzip!  ================================
# edited file: /bitrix/modules/main/lib/data/memcachedconnection.php
# (set option nocompression to memcached, but use gzencode/gzdecode instead)
#
server {
    listen 80;
    charset        windows-1251;
    source_charset windows-1251;
    limit_conn arbeit 32;
    server_name trauma.ru www.trauma.ru trauma.ru.d2.gfns.ru;
    keepalive_timeout 75 75;

    include /usr/local/etc/nginx/mime.types;
    default_type text/html;

    root       /home/www/servers/trauma.ru/html;
    access_log /home/www/servers-logs/trauma.ru/access_log;
    error_log  /home/www/servers-logs/trauma.ru/error_log;

# directories to work with their index files
    index      index.php;

# uri /blog/aldid/test and so on works
    error_page 404 /404.php;
    if (!-e $request_filename) {
	rewrite  ^(.*)$  /bitrix/urlrewrite.php last;
    }

gzip off;
gunzip off;

set $storedAuth "";
set $usecache "";

# check all conditions for enable composite
if ( $http_bx_action_type = "" )     { set $usecache "A"; }
if ( $request_method = "GET" ) { set $usecache "${usecache}B"; }
if ( $cookie_BITRIX_SM_NCC = "" ) { set $usecache "${usecache}C"; }
if ( $http_x_forwarded_scheme !~ "https" ){ set $usecache "${usecache}D"; }
if ( $http_accept_encoding ~* "gzip" ){ set $usecache "${usecache}E"; }

# IE9 and above exclude
modern_browser_value "modern";
modern_browser msie 10.0;
modern_browser unlisted;
if ($modern_browser) {
   set $usecache "${usecache}F";
}

# check user auth
if ( $cookie_BITRIX_SM_LOGIN != "" ) { set $storedAuth "A"; }
if ( $cookie_BITRIX_SM_UIDH != "" ) { set $storedAuth "${storedAuth}B"; }
if ( $cookie_BITRIX_SM_CC != "Y" ) { set $storedAuth "${storedAuth}C"; }
if ( $storedAuth !~ "ABC" ) { set $usecache "${usecache}G"; }

memcached_connect_timeout 1s;
memcached_read_timeout 1s;
memcached_send_timeout 1s;

# causes /blog and /blog/ uri to be identical
    location / {
    try_files  $uri $uri/ =404;
    error_page 404 405 412 502 504 = @php;
    if ($usecache != "ABCDEFG" ) { return 412; }
    default_type text/html;
    set $memcached_key "/$host$uri@$args.html";
    if ($uri ~ "/$")
    {
      set $memcached_key "/$host${uri}index@$args.html";
    }
    add_header X-Cache-Engine "Debug: Memchached trying by Nginx; key=$memcached_key; in location /";
    add_header Content-Encoding gzip;
    memcached_pass localhost:11211;
    }

location ~* ^(.*)\.php$ {
   error_page 404 405 412 502 504 = @php;
   if ($usecache != "ABCDEFG" ) { return 412; }

   default_type text/html;
   set $memcached_key "/$host$1@$args.html";
   add_header X-Cache-Engine "Debug: Memchached trying by Nginx; key=$memcached_key; in location .php";
   add_header Content-Encoding gzip;
   memcached_pass localhost:11211;
}

    location @php {
        fastcgi_index   index.php;
        fastcgi_param   DOCUMENT_ROOT     $document_root;
        fastcgi_param   SCRIPT_FILENAME   $document_root$fastcgi_script_name;
        fastcgi_param   PATH_INFO         $fastcgi_path_info;
        fastcgi_param   QUERY_STRING      $args;
        fastcgi_param   CONTENT_TYPE      $content_type;
        fastcgi_param   CONTENT_LENGTH    $content_length;
        fastcgi_param   SERVER_NAME       $server_name;
        fastcgi_param   REQUEST_URI       $request_uri;
        fastcgi_param   DOCUMENT_URI      $document_uri;
        fastcgi_param   REQUEST_METHOD    $request_method;
        fastcgi_param   REMOTE_ADDR       $remote_addr;
        fastcgi_param   REMOTE_USER       $http_authorization;
        fastcgi_intercept_errors        on;
        fastcgi_ignore_client_abort     off;
        fastcgi_connect_timeout 60;
        fastcgi_send_timeout 180;
        fastcgi_read_timeout 180;
        fastcgi_buffer_size 128k;
        fastcgi_buffers 4 256k;
        fastcgi_busy_buffers_size 256k;
        fastcgi_temp_file_write_size 256k;

        add_header X-Cache-Engine "not cached by memcached (in @php location nginx config)";
        fastcgi_pass    unix:/var/run/php-fpm.sock;
        }
# all static files quickly return.
    location ~* ^.+\.(jpg|jpeg|gif|png|svg|js|css|mp3|ogg|mpe?g|avi|zip|gz|bz2?|rar|swf|txt|xml)$ {
        access_log        off;
        expires           max;
    }
#+ Close some uri for security
    location ~ (/\.ht|/bitrix/modules|/upload/support/not_image) {
        deny all;
    }

    location ~ /.svn/ {
           deny all;
    }
Однако сравнение показало, что данный вариант проигрывает предыдущему (Автокомпозит + memcached), то есть отдача страниц nginx не выигрывает у интеллектуального хранения их кусочков в memcached с отдачей через инфраструктуру bitrix. Вот наглядная картинка: Сравнение быстродействия при смене технологии. Bitrix на GFNS

nginx как reverse proxy для Apache

Работа nginx как кеширующего агента в случае применения им файлов на файловой системе оправдано только при намного большем быстродействии файловой системы и диска, нежели имеющиеся у меня (по тестам Битрикса - 600 операций) потому результаты оказались плачевнее, чем "совсем без кеша".

Затраты же оперативной памяти на Apache сделали эту конфигурацию ещё менее желанной.

Проблемы с SSL на PHP 5.6+

В настоящее время я не смог добиться того, чтобы исходящие соединения из НЕИЗМЕНЁННОГО кода PHP битрикса гарантированно работали для SSL соединений (например, с youtube из соотв плагина).

Иными словами, вне зависимости от прописанных в php.ini настроек я получаю: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed при попытке соединения: $data = file_get_contents("https://www.googleapis.com/youtube/v3/playlistItems?...)

Исправить это в PHP коде можно следующим образом (так выделено добавленное):

$arrContextOptions=array(
    "ssl"=>array(
        "verify_peer"=>false,
        "verify_peer_name"=>false,
        "allow_self_signed"=>true,
    ),
);
$data = file_get_contents("https://www.googleapis.com/youtube/v3/playlistItems?...", false,stream_context_create($arrContextOptions));
Однако это надо делать буквально для каждого соединения! Что удручает.