Миллион посетителей на WordPress против сервера

в 14:50, , рубрики: Apache, nginx, wordpress, метки: , ,

Мой сервер, который и будет героем последующего повествования — это обычный арендованный у FirstDedic сервер среднего класса с процессором DualCore Xeon E3110 3.00Ghz. Оперативной памяти было установлено 4 Гб, жесткий диск 500 Гб. На сервере был установлен nginx 1.01 в качестве frontend, и apache 2 в качестве backend, с запуском скриптов в режиме CGI.

История приключилась с сайтом, который был размещен на моем сервере, собственно, не сайт, а чужой личный блог. Ранее на блоге наблюдались пики трафика до 10000 в сутки, но с подобной нагрузкой сервер справлялся на ура абсолютно без оптимизации на стандартных файлах конфигурации.

И вот, в один прекрасный «Женский день», утром, приходит SMS от сервиса мониторинга сайтов, что сервер недоступен. Естественно, от такой новости мгновенно просыпаюсь, и пробую пинговать сервер. Пинг присутствовал, но очень вялый. Соединение по SSH установить невозможно, потому что все ресурсы сервера отданы неизвестному процессу, или процессам.

Соединившись по KVM, я отправил сервер в перезагрузку, и сразу после загрузки соединился по SSH. В процессах, я увидел страшную картину: запущено около 1000 процессов php от имени автора блога, кроме того, Load averages больше сотни. Очень страшный показатель, который показывает, сколько приходится ожидать процессу своей очереди на порцию ресурсов.

Естественно, времени мне хватило только чтобы это увидеть, запустив команду top. Уже через минуту сервер перестал отвечать на запросы, и пришлось его вновь перезагрузить, и сразу после перезагрузки выключить apache. Теперь я гарантированно получил сервер, который не израсходует все ресурсы. Начал проводить анализ, я вывел число открытых соединений командой netstat и ужаснулся. Было более 10000 установленных соединений с nginx. Это значит, что за последнюю минуту было 10 тысяч попыток зайти на сайт клиента – хорошая нагрузка.

Попытавшись порыться в настройках WordPress, естественно с согласия клиента, Я обнаружил, что был активирован плагин для кэширования WP Super Cache, который я выключил, потому что при выполнении самую большую нагрузку на файловую систему давал именно он. Выключив плагин, сайт стал выполнять очень много запросов в базу данных – неудивительно. Поэтому первым делом я включил систему кэширования запросов в MySQL, так как нагрузку давала всего одна страница, на которую и было множество переходов. После включения кэширования запросов, база данных вздохнула свободнее, но не настолько, насколько хотелось бы, притом, что основную нагрузку теперь давал сам WordPress.

Выключив все возможные плагины и переписав тему с наименьшим количеством запросов, нагрузка не уменьшалась. Пришлось идти на крайние меры — я включил принудительное кэширование проксированных запросов в nginx. Для этого я прописал в секции http следующую строку

proxy_cache_path /path/to/cache levels=1:2 keys_zone=wpblog:10m max_size=10m;

В нужную нам секцию server прописываем:

proxy_cache_valid 200 3m;
proxy_cache wpblog;
proxy_pass http://127.0.0.1:8080;
proxy_cache_valid 200 3m;

Как только я это сделал, нагрузка на сервер резко упала. Однако мы получили множество неудобств, связанных с администрированием и комментированием. Несмотря на неудобство, проблема была решена. Однако сознание подсказывало, что включать вручную такое кэширование не всегда будет время и возможность, а оставлять как есть не вариант для автора блога. Таким образом, пришлось запрещать кэширование для авторизованных пользователей, и пользователей, оставивших свои комментарии. В итоге получается примерно такая секция server:

proxy_cache_valid 200 3m;
location / {
if ($http_cookie ~* "comment_author_|wordpress_(?!test_cookie)|wp-postpass_" ) {
		set $do_not_cache 1;
	}
	proxy_no_cache $do_not_cache;
	proxy_cache_bypass $do_not_cache;
	proxy_cache wpblog;
	proxy_pass http://127.0.0.1:8080;
	proxy_cache_valid 200 3m;
}
location ~* wp-.*.php|wp-admin {
	proxy_pass http://127.0.0.1:8080;
}
location ~* ^.+.(jpg|jpeg|gif|png|svg|js|css|mp3|ogg|mpe?g|avi|zip|gz|bz2?|rar)$ {
root /path/to/static;
	access_log off;
	expires max;
	add_header Last-Modified: $date_gmt;
}
location ~* /[^/]+/(feed|.xml)/? {
	proxy_pass http://127.0.0.1:8080;
}

После этого неудобства в работе полностью компенсируются бесперебойностью.

Как итог ко всему вышеописанному, сервер был недоступен в течение 2 часов, за это время поток трафика значительно уменьшился, но после этого случая были и другие подобные праздничные всплески посещаемости, которые сайт успешно выдержал, не дав ощутимой нагрузки на сервер. С тех самых пор стараюсь на все размещенные сайты на WordPress ставить такую конфигурацию.

Google Analytics на сайте клиента, после того, как сервер окончательно поднялся, показывал 6000 посетителей онлайн. Эта цифра быстро падала, потому что актуальность запроса, по которому сайт был в топе всех поисковых систем, терялась каждую минуту. К концу дня, количество посетителей стало семизначным, но владелец ресурса до сих пор смотрит на меня волком, потому что цифра могла быть в разы выше, как и его доход.

Автор: fenixru

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js