Хакер - Magentная аномалия. Настраиваем ngnix для работы с Magento

Хакер - Magentная аномалия. Настраиваем ngnix для работы с Magento

hacker_frei

https://t.me/hacker_frei

Денис Колисниченко

Содержание статьи

  • Вкратце о сервере
  • Конфигурационные файлы
  • Включение HTTP 2.0
  • OPcache: быть или не быть?
  • Запрещаем доступ ботов
  • Кастомная maintenance-страница для «Мадженты»
  • Настройка пула www
  • Выводы

По нас­трой­ке сер­вера nginx соз­даны тысячи ману­алов, но иног­да слу­чают­ся ситу­ации, не опи­сан­ные ни в одном руководс­тве. Пред­посыл­кой для этой пуб­ликации пос­лужила вов­се не моя пре­дыду­щая статья про «Апач», а реаль­ный кейс: на VDS с 39 Гбайт опе­ратив­ки nginx кушал всю память, пос­ле чего сайт «ложил­ся». Как мне уда­лось спра­вить­ся с этой напастью, я сей­час рас­ска­жу.

ВКРАТЦЕ О СЕРВЕРЕ

Итак, име­ем самый обыч­ный VDS с 39 Гбайт опе­ратив­ки, 12 ядра­ми и «Убун­той» на бор­ту. PHP 7.2, PHP-FPM, MySQL 5.7. Вер­сии ПО, может, нем­ного и древ­ние, но уста­нов­лены нес­прос­та: такая кон­фигура­ция обус­ловле­на тре­бова­ниями CMS Magento 2.3.4. Более новая вер­сия PHP пов­лекла бы за собой обновле­ние вер­сии CMS, а это­го по ряду при­чин делать было нель­зя.

Как обыч­но, все прек­расно работа­ло до одно­го момен­та: пока не начались тра­дици­онные новогод­ние рас­про­дажи и мар­кетоло­ги не при­тащи­ли на сайт кучу тра­фика. Вот тут и начались проб­лемы. Наибо­лее харак­терная из них — про­цесс php-fpm в паре с MySQL выжирал всю опе­ратив­ку. Переза­пуск сер­висов с добав­лени­ем 20 Гбайт сво­па проб­лему решил ненадол­го. Даль­ше пошел про­цесс нас­трой­ки nginx и php-fpm, преж­де все­го — пос­ледне­го, пос­коль­ку имен­но его парамет­ры вли­яют на экс­плу­ата­цион­ные осо­бен­ности CMS. Я не буду рас­смат­ривать уста­нов­ку и нас­трой­ку nginx с самого начала — ско­рее все­го, у тебя уже все нас­тро­ено. Даже если это не так, в сети мож­но най­ти мно­жес­тво ста­тей и руководств на эту тему. Скон­цен­три­руем­ся луч­ше на парамет­рах, непос­редс­твен­но вли­яющих на про­изво­дитель­ность сер­вера.

КОНФИГУРАЦИОННЫЕ ФАЙЛЫ

Преж­де чем прис­тупить к даль­нейше­му чте­нию статьи, нуж­но понимать, что и где и редак­тировать. Кон­фигура­ция nginx хра­нит­ся в катало­ге /etc/nginx. Основной кон­фиг — nginx.conf, но вре­мена одно­го боль­шого фай­ла уже дав­но прош­ли, и в зависи­мос­ти от содер­жимого nginx.conf кон­фигура­ция веб‑сер­вера может быть раз­бро­сана по всей фай­ловой сис­теме.

Как пра­вило, кон­фиги сай­тов хра­нят­ся в катало­ге /etc/nginx/conf.d. Для каж­дого сай­та при­нято соз­давать отдель­ный кон­фиг. Далее нуж­но про­ана­лизи­ровать содер­жимое фай­лов кон­фигура­ции на пред­мет дирек­тивы Include. Если пер­воначаль­ную нас­трой­ку выпол­нял не ты, поищи во всех фай­лах катало­га nginx фай­лы с дирек­тивой Include — так ты пой­мешь, что и отку­да берет­ся. Нап­ример, в моем слу­чае кто‑то до меня добавил дирек­тиву include /var/www/www/nginx.conf, что­бы некото­рые парамет­ры мож­но было вынес­ти в каталог докумен­тов веб‑сер­вера и редак­тировать их без редак­тирова­ния основной кон­фигура­ции сер­вера. Что‑то вро­де .htaccess в «Апа­че», вот толь­ко пос­ле изме­нения это­го фай­ла все рав­но при­дет­ся делать reload сер­вису.

Да­лее перей­дем к парамет­рам PHP. У него есть нес­коль­ко кон­фигура­ций. Преж­де все­го вве­ди коман­ду php –v, что­бы выяс­нить номер вер­сии. Так вот, кон­фигура­ция тво­ей вер­сии PHP хра­нит­ся в катало­ге /etc/php/<номер версии>. В этом катало­ге ты най­дешь четыре под­катало­га. Да, это три раз­ные кон­фигура­ции и спи­сок модулей:

  • apache2 — кон­фиг для модуля mod_rewrite «Апа­ча». Если у тебя «Апач», то нас­трой­ки PHP хра­нят­ся здесь;
  • cli — парамет­ры кон­соль­ной вер­сии PHP, они всту­пают в силу, если ты запус­каешь выпол­нение скрип­та с кон­соли коман­дой php <имя_скрипта>;
  • fpm — наш слу­чай, а имен­но кон­фигура­ция сер­виса php-fpm и самого PHP, работа­юще­го в связ­ке nginx, PHP-FPM и PHP;
  • mods-available — дос­тупные рас­ширения PHP. Здесь хра­нят­ся .ini-фай­лы, по одно­му для каж­дого уста­нов­ленно­го рас­ширения. Заком­менти­ровав строч­ку extension внут­ри это­го фай­ла, ты можешь вык­лючить рас­ширение.

Что­бы узнать, какой имен­но файл кон­фигура­ции PHP исполь­зует­ся, помес­ти в корень сер­вера PHP-скрипт, вызыва­ющий php_info(). Эта фун­кция и покажет (кро­ме все­го про­чего) локацию и имя фай­ла кон­фигура­ции.

ВКЛЮЧЕНИЕ HTTP 2.0

Ес­ли не счи­тать ста­тичес­кого кеша, то самое кру­тое, что ты можешь сде­лать в нас­трой­ках nginx, — это вклю­чить HTTP 2.0. Некото­рые адми­ны почему‑то забыва­ют об этом. В моем слу­чае так и было: я уже получил пред­нас­тро­енный под­рядчи­ком сер­вер, в котором почему‑то забыли вклю­чить вер­сию 2.0 про­токо­ла HTTP. Думаю, не нуж­но говорить о том, как мед­ленно работа­ла Magento.

Боль­ше дела, мень­ше слов: открой кон­фигура­цию сай­та в катало­ге /etc/nginx/conf.d/<имя_сайта>.conf. Най­ди блок server и добавь (если это­го еще не сде­лано) http2 в дирек­тиву listen. Дол­жно получить­ся так:

server {

listen 443 ssl http2;

ssl on;

...

}

Но­мер пор­та и SSL уста­нови по сво­ему усмотре­нию, но пос­коль­ку при­мер реаль­ный, то SSL уже есть на тво­ем сай­те, так как это стан­дарт по умол­чанию.

OPCACHE: БЫТЬ ИЛИ НЕ БЫТЬ?

OPcache исполь­зует­ся для кеширо­вания ском­пилиро­ван­ного байт‑кода PHP-скрип­тов в опе­ратив­ной памяти. С одной сто­роны, при исполь­зовании OPcache повысит­ся про­изво­дитель­ность и сни­зит­ся наг­рузка на сер­вер — PHP уже не будет соз­давать байт‑код при выпол­нении скрип­та, а ста­нет исполь­зовать откомпи­лиро­ван­ную вер­сию из кеша. С дру­гой сто­роны, в про­цес­се исполь­зования слож­ных CMS вро­де Magento могут воз­никнуть проб­лемы. При уста­нов­ке рас­ширения это­го движ­ка про­исхо­дит так называ­емая переком­пиляция Magento. Луч­ше эту про­цеду­ру про­изво­дить при вык­лючен­ном кеше, а затем сно­ва его вклю­чить.

Для это­го редак­тиру­ется кон­фиг, перезаг­ружа­ется сер­вис php-fpm, про­изво­дят­ся необ­ходимые дей­ствия, а потом сно­ва все пов­торя­ется — редак­тирова­ние кон­фига и переза­пуск сер­виса. Так­же воз­никнут проб­лемы при исполь­зовании собс­твен­ной сис­темы кеширо­вания Magento. Здесь поможет исполь­зование Varnish. В общем, резюми­ровать мож­но сле­дующее: если ты решишь вклю­чить OPcache, то в слу­чае с Magento тебе при­дет­ся отка­зать­ся от исполь­зования собс­твен­ной сис­темы кеширо­вания и раз­бирать­ся с нас­трой­ками Varnish. Уста­нов­ка рас­ширений дос­тавля­ет мень­ше неудобств, пос­коль­ку выпол­няет­ся не так час­то.

Для вклю­чения OPcache нуж­но открыть кон­фигура­цию PHP, в нашем слу­чае это /etc/php/7.2/fpm/php.ini, и добавить в него все­го одну строч­ку:

opcache.enable = 1

Этим ты акти­виру­ешь opcache с нас­трой­ками по умол­чанию. Как минимум мож­но задать параметр opcache.memory_consumption, который регули­рует раз­мер памяти (в мегабай­тах), выделя­емый для OPcache. Зна­чение по умол­чанию — 128, минималь­но допус­тимое зна­чение — 8:

opcache.memory_consumption = 256

С осталь­ными нас­трой­ками OPcache мож­но озна­комить­ся здесь. На сво­ем сер­вере я отклю­чил OPcache по двум при­чинам. Во‑пер­вых, сайт активно допили­вает­ся, из‑за чего очень час­то при­ходит­ся добав­лять в него новые фун­кции или изме­нять уже име­ющиеся, что при вклю­чен­ном OPcache не сов­сем удоб­но. Во‑вто­рых, пока нет никако­го желания уста­нав­ливать Varnish, хотя в ско­ром вре­мени это при­дет­ся сде­лать. На дан­ный момент исполь­зует­ся штат­ная сис­тема кеширо­вания.

ЗАПРЕЩАЕМ ДОСТУП БОТОВ

Бо­ты во вре­мя сво­его обхо­да сай­та рас­ходу­ют дра­гоцен­ные ресур­сы. При неб­лагоп­рият­ном сте­чении обсто­ятель­ств (нап­ример, слу­чай­ные или намерен­ные визиты нес­коль­ких ботов сра­зу) сайт может упасть, не выдер­жав наг­рузки. Каж­дый GET-зап­рос стра­ницы тянет за собой исполь­зование ресур­сов сер­вера: заг­рузка эле­мен­тов стра­ницы (кар­тинки, CSS-таб­лицы и про­чее), обра­щение к базе дан­ных и, воз­можно, к сто­рон­ним ресур­сам. Бот — это не поль­зователь, который откро­ет одну стра­ницу и изу­чает ее кон­тент, бот откры­вает стра­ницу за стра­ницей, что может выз­вать негатив­ные пос­ледс­твия.

К сожале­нию, не все боты чита­ют содер­жимое robots.txt. Изба­вить­ся от ботов мож­но в кон­фиге nginx. Открой файл кон­фигура­ции тво­его сай­та, оты­щи блок server и добавь в него сле­дующие стро­ки:

if ($http_user_agent ~* SemrushBot|semrush|PetalBot|petalbot|MJ12Bot|AhrefsBot|bingbot|DotBot|LinkpadBot|SputnikBot|statdom.ru|WebDataStats|Jooblebot|Baiduspider|openstat.ru) {

return 403;

}

Ду­маю, смысл этих строк понятен всем: мы смот­рим на http_user_agent и, если агент поль­зовате­ля содер­жит одну из зап­рещен­ных строк, воз­вра­щаем ошиб­ку 403. Это не весь спи­сок ботов, ты можешь допол­нить его. Узнать имя бота мож­но из access.log — в логе сох­раня­ется вся нуж­ная инфа.

КАСТОМНАЯ MAINTENANCE-СТРАНИЦА ДЛЯ «МАДЖЕНТЫ»

При перево­де в режим обслу­жива­ния Magento отоб­ража­ет неп­римеча­тель­ное сооб­щение о том, что сайт зак­рыт. Выг­лядит очень неп­резен­табель­но. Мы можем соз­дать кас­томную стра­ницу, которая будет отоб­ражать­ся, ког­да сайт зак­рыт на обслу­жива­ние. Прос­то добавь в кон­фиг тво­его сай­та сле­дующие стро­ки (внут­ри бло­ка server):

set $MAGE_ROOT /var/www/www;

set $maintenance off;

if (-f $MAGE_ROOT/maintenance.enable) {

set $maintenance on;

}

if ($remote_addr ~ (188.xx.yy.zz|188.aa.bb.cc)) {

set $maintenance off;

}

if ($maintenance = on) {

return 503;

}

location /maintenance {

}

error_page 503 @maintenance;

location @maintenance {

root $MAGE_ROOT;

rewrite ^(.*)$ /maintenance.html break;

}

Ра­ботать будет так:

  • пе­ремен­ная $MAGE_ROOT уста­нав­лива­ет каталог, в котором уста­нов­лено при­ложе­ние;
  • по умол­чанию режим обслу­жива­ния вык­лючен — set $maintenance off;
  • ре­жим обслу­жива­ния вклю­чает­ся, если в кор­невом катало­ге при­ложе­ния есть файл maintenance.enable;
  • ре­жим обслу­жива­ния не работа­ет для IP-адре­сов 188.xx.yy.zz и 188.aa.bb.cc. Здесь ты можешь ука­зать свои адре­са;
  • ес­ли режим обслу­жива­ния вклю­чен, воз­вра­щает­ся стра­ница maintenance.html, находя­щаяся в кор­не (MAGE_ROOT). Имен­но сюда сле­дует помес­тить стра­нич­ку с нуж­ным тек­стом и офор­мле­нием. Офор­мле­ние (CSS) луч­ше рас­положить внут­ри это­го фай­ла, как и кар­тинки (в SVG), — сайт в режиме обслу­жива­ния дол­жен минималь­но наг­ружать сер­вер.

НАСТРОЙКА ПУЛА WWW

Те­перь перей­дем к опци­ям PHP-FPM. Как пра­вило, зна­чимые парамет­ры хра­нят­ся в кон­фиге пула — в катало­ге /etc/php/версия/fpm/pool.d/. В нем есть один или нес­коль­ко кон­фигов. Далее при­веден при­мер моего фай­ла:

[www]

user = www-data

group = www-data

listen = /var/run/php/php7.2-fpm.sock

listen.owner = www-data

listen.group = www-data

php_admin_value[disable_functions] = exec,passthru,shell_exec,system

php_admin_flag[allow_url_fopen] = on

php_value[max_input_vars] = 300000

pm = dynamic

pm.max_children = 259

pm.start_servers = 48

pm.min_spare_servers = 24

pm.max_spare_servers = 248

pm.max_requests = 2000

request_terminate_timeout = 6000

php_admin_value[memory_limit] = 8192M

chdir = /

slowlog=/var/log/php-slow.log

request_slowlog_timeout=30s

Не нуж­но сле­по копиро­вать все зна­чения — они уста­нов­лены для моего сер­вера и на тво­ем могут сде­лать толь­ко хуже. Поп­робу­ем разоб­рать­ся, что к чему.

Па­рамет­ры, которые непос­редс­твен­но вли­яют на про­изво­дитель­ность, начина­ются с pm. В боль­шинс­тве слу­чаев исполь­зует­ся динами­чес­кая кон­фигура­ция (pm = dynamic), при которой количес­тво про­цес­сов PHP-FPM меня­ется динами­чес­ки, в зависи­мос­ти от количес­тва зап­росов. При этом име­ется минималь­ное количес­тво про­цес­сов, которые будут запуще­ны при стар­те FPM-сер­виса. Осталь­ные парамет­ры трак­туют­ся так:

  • pm.max_children — мак­сималь­ное количес­тво дочер­них про­цес­сов, которые будут соз­даны, по сути это мак­сималь­ное количес­тво зап­росов, которые может обслу­жить пул. Ана­лог ApacheMaxClients для «Апа­ча»;
  • pm.start_servers — чис­ло дочер­них про­цес­сов, которые будут соз­даны при запус­ке пула, исполь­зует­ся толь­ко в динами­чес­кой кон­фигура­ции;
  • pm.min_spare_servers — минималь­ное количес­тво дочер­них про­цес­сов в ста­тусе Idle;
  • pm.max_spare_servers — мак­сималь­ное количес­тво дочер­них про­цес­сов в ста­тусе Idle;
  • pm.max_requests — мак­сималь­ное количес­тво зап­росов, которое дол­жен обра­ботать про­цесс FPM перед его переза­пус­ком (помога­ет избе­жать уте­чек памяти). Здесь нуж­но экспе­римен­тировать, для кого‑то подой­дет зна­чение 1000, для кого‑то зна­чение нуж­но уве­личи­вать.

Мож­но экспе­римен­тировать с эти­ми зна­чени­ями вруч­ную, а мож­но вос­поль­зовать­ся скрип­том php_settings.sh. На вся­кий слу­чай код скрип­та:

#!/usr/bin/env bash

if [[ -z ${1} ]] || [[ -z ${2} ]]; then

echo -e "Run script: ./php_settings.sh <Memory size MB> <PHP-FPM version>\n./php_settings.sh 1024 7.4"

exit 1

fi

_php_version=${2}

_cpu_cores=$(( $(lscpu | awk '/^Socket/{ print $2 }') * $(lscpu | awk '/^Core/{ print $4 }') ))

_mem_usage=${1}

_average_proc_mem=$(ps --no-headers -o "rss,cmd" -C php-fpm${_php_version} | awk '{ sum+=$1 } END { printf ("%d\n", sum/NR/1024) }')

echo -e "average_proc_mem=${_average_proc_mem}\n#################"

echo pm.max_children=$(awk "BEGIN { printf ${_mem_usage} / ${_average_proc_mem} }")

echo pm.start_servers=$(awk "BEGIN { printf ${_cpu_cores} * 4 }")

echo pm.min_spare_servers=$(awk "BEGIN { printf ${_cpu_cores} * 2 }")

echo pm.max_spare_servers=$(awk "BEGIN { printf ${_cpu_cores} * 4 }")

Ис­поль­зовать скрипт прос­то: зада­ешь объ­ем (в мегабай­тах) опе­ратив­ки и вер­сию PHP, затем получа­ешь стро­ки, которые нуж­но ско­пиро­вать в www.conf (кон­фигура­ция пула). Исполь­зуя код скрип­та, мож­но все пос­читать и вруч­ную, одна­ко авто­мати­зация еще никог­да не мешала. Вывод скрип­та может быть таким:

average_proc_mem=159

#################

pm.max_children=251.17

pm.start_servers=48

pm.min_spare_servers=24

pm.max_spare_servers=48

В кон­фиг нуж­но ско­пиро­вать не все, а толь­ко стро­ки пос­ле ###. Пер­вая стро­ка намека­ет на при­мер­ный объ­ем про­цес­са, который у тебя дол­жен получить­ся. Если max_children не целое чис­ло, его мож­но округлить до бли­жай­шего целого.

Ис­поль­зование скрип­та

С при­веден­ными нас­трой­ками сер­вак был перезаг­ружен (перезаг­ружать вооб­ще не нуж­но было, но для чис­тоты экспе­римен­та это необ­ходимо). Спус­тя девять часов работы в обыч­ном режиме рас­ход памяти не пре­высил 11 Гбайт, что не может не радовать.

Пот­ребле­ние ресур­сов пос­ле нас­трой­ки парамет­ров

Так­же не забудь вклю­чить slow-лог:

slowlog=/var/log/php-slow.log

request_slowlog_timeout=30s

Ес­ли какой‑то скрипт выпол­няет­ся боль­ше 30 секунд, то инфа о нем будет помеще­на в файл /var/log/php-slow.log. Это поможет при выяв­лении узких мест на сай­те.

ВЫВОДЫ

По боль­шому сче­ту каж­дая CMS име­ет свои инди­виду­аль­ные осо­бен­ности и может пот­ребовать собс­твен­ных нас­тро­ек сер­вера. Для Magento опти­маль­ная кон­фигура­ция nginx опи­сана в этой пуб­ликации. Статья хоть и не рас­кры­вает всех тон­костей нас­трой­ки nginx, одна­ко при­веден­ных в ней инс­трук­ций впол­не дос­таточ­но, что­бы сде­лать сущес­твен­но «луч­ше, чем было».

Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei



Report Page