В жизни каждого посещаемого ресурса случаются моменты, когда оборудование не справляется с текущей нагрузкой. Причины могут быть самыми разнообразными, и не всегда их можно кардинально искоренить в разумное время. В таких случаях перед разработчиками встает задача снизить нагрузку с минимальными неудобствами для посетителей.
Не претендую на гениальность своего решения, но надеюсь, кому-нибудь оно поможет.
В моем случае проблема в том, что время от времени резко поднимается нагрузка на базу данных. Как обычно бывает в таких случаях возникала лавина – запросы начинают тормозить, пользователи нервничают и жмут reload, кроновские скрипты тормозят и в результате сервер «подвисает». Кроме того, поисковые роботы добавляют проблем – они имеют свойство вытягивать глубинные страницы с сайта, которые в обычном режиме в кеше не живут. В результате страницы для них генерируются и кеш заполняется ненужными данными. Со второй частью проблемы можно справиться достаточно легко – просто не кешировать обращения к старым страницам, либо обращения роботов. Но вполне можно пойти дальше и снять нагрузку от роботов хотя бы на время когда сервер перегружен.
Передо мной встало две задачи:
1. Как определить момент возникновения повышенной нагрузки
2. Что можно сделать в эти моменты чтобы жить стало легче
Для решения первой задачи я воспользовался знаменитым чудо-инструментом zabbix, благо он давно, активно и успешно используется и позволяет мониторить несколько серверов, а также выполнять на них команды при возникновении нужных условий. Для своего случая я выбрал load average на сервере базы данных. А реагировать мне нужно на другом сервере, на котором живет nginx.
Я создал триггер с условием system.cpu.load[,avg1].last(0)>3.5, навесил на него выполнение удаленной команды
HOST: /path/lowerage.sh {STATUS} {ITEM.LASTVALUE} {TIME}
А на сервере разместил простенький скриптик:
В результате в моменты поднятии нагрузки создавался файлик, от которого уже можно плясать дальше.
Плавно переходим собственно к действиям.
Первым делом я ограничил запуск кроновских скриптов в критическое время. Решение тривиальное, просто в крон добавляется условие. Пример:
/bin/test! -r /tmp/cpu_load_high && /usr/bin/fetch -o — site/cron.php
Потом я начал нежно прижимать поисковых роботов. Решил их отсекать во критическое время на уровне nginx. С последним пришлось проявить смекалку, дело в том, что nginx не понимает вложенных if, а мне нужно минимум два условия. Выручил финт ушами. Кусок файла конфигурации, реализующий вышеописанное, привожу ниже:
Кстати, не уверен, что вариант с return 444 оптимален. При этом nginx просто обрывает соединение. Думаю, что роботы не должны сильно обижаться на такое поведение.
Вот собственно и вся недолга. На будущее еще можно в критические времена не обрабатывать какие-то тяжелые запросы – перекидывать пользователя на страницу с извинениями.
Спасибо за внимание.
UPD: в комментах подсказали ссылку googlewebmastercentral.blogspot.com/2006/08/all-about-googlebot.html где гугл рекомендует использовать код 503.
Не претендую на гениальность своего решения, но надеюсь, кому-нибудь оно поможет.
В моем случае проблема в том, что время от времени резко поднимается нагрузка на базу данных. Как обычно бывает в таких случаях возникала лавина – запросы начинают тормозить, пользователи нервничают и жмут reload, кроновские скрипты тормозят и в результате сервер «подвисает». Кроме того, поисковые роботы добавляют проблем – они имеют свойство вытягивать глубинные страницы с сайта, которые в обычном режиме в кеше не живут. В результате страницы для них генерируются и кеш заполняется ненужными данными. Со второй частью проблемы можно справиться достаточно легко – просто не кешировать обращения к старым страницам, либо обращения роботов. Но вполне можно пойти дальше и снять нагрузку от роботов хотя бы на время когда сервер перегружен.
Передо мной встало две задачи:
1. Как определить момент возникновения повышенной нагрузки
2. Что можно сделать в эти моменты чтобы жить стало легче
Для решения первой задачи я воспользовался знаменитым чудо-инструментом zabbix, благо он давно, активно и успешно используется и позволяет мониторить несколько серверов, а также выполнять на них команды при возникновении нужных условий. Для своего случая я выбрал load average на сервере базы данных. А реагировать мне нужно на другом сервере, на котором живет nginx.
Я создал триггер с условием system.cpu.load[,avg1].last(0)>3.5, навесил на него выполнение удаленной команды
HOST: /path/lowerage.sh {STATUS} {ITEM.LASTVALUE} {TIME}
А на сервере разместил простенький скриптик:
if [ "${1}" != "ON" ] ; then
/bin/unlink /tmp/cpu_load_high
else
/usr/bin/touch /tmp/cpu_load_high
fi
echo "lowerage ${1} ${2} ${3}" |/usr/bin/mail -s lowerage tmp@tmpmail.ru
В результате в моменты поднятии нагрузки создавался файлик, от которого уже можно плясать дальше.
Плавно переходим собственно к действиям.
Первым делом я ограничил запуск кроновских скриптов в критическое время. Решение тривиальное, просто в крон добавляется условие. Пример:
/bin/test! -r /tmp/cpu_load_high && /usr/bin/fetch -o — site/cron.php
Потом я начал нежно прижимать поисковых роботов. Решил их отсекать во критическое время на уровне nginx. С последним пришлось проявить смекалку, дело в том, что nginx не понимает вложенных if, а мне нужно минимум два условия. Выручил финт ушами. Кусок файла конфигурации, реализующий вышеописанное, привожу ниже:
if (-f /tmp/cpu_load_high) {
set $troubleflag T;
}
if ($http_user_agent ~ (?:Yandex|Google|Yahoo|Rambler|msnbot) ) {
set $oblomflag Y$troubleflag;
}
if ($oblomflag = YT) {
return 444;
}
Кстати, не уверен, что вариант с return 444 оптимален. При этом nginx просто обрывает соединение. Думаю, что роботы не должны сильно обижаться на такое поведение.
Вот собственно и вся недолга. На будущее еще можно в критические времена не обрабатывать какие-то тяжелые запросы – перекидывать пользователя на страницу с извинениями.
Спасибо за внимание.
UPD: в комментах подсказали ссылку googlewebmastercentral.blogspot.com/2006/08/all-about-googlebot.html где гугл рекомендует использовать код 503.