[Перевод] Написание высокодоступного кода: 6 советов от инженера Imgur

168e34417630432a9f313dacc28cfcd8.jpg

Примечание переводчика: В нашем блоге мы много пишем о построении облачного сервиса 1cloud, но немало интересного можно почерпнуть и из опыта по работе с инфраструктурой других компаний. Инженер фотосервиса Imgur Джейкоб Гринлиф (Jacob Greenleaf) опубликовл в блоге на Medium материал, в котором изложил несколько советов по созданию высокодоступного кода для отказоустойчивых систем. Мы представляем вашему вниманию адаптированный перевод этой заметки.

Я работаю в Imgur уже больше двух лет и за это время усвоил несколько принципов, которые помогают создавать отказоустойчивые системы. Часто бывает, что какая-то из наших систем «падает», и когда я прихожу утром на работу, то вижу, что сработал заранее предусмотренный «предохранитель» или сервис автоматически перезапустился после сбоя — этого удается достичь с помощью нескольких принципов проектирования. Ниже представлены некоторые из них.

Все нужно ограничивать


Предположим, у вас есть очередь для обработки множества элементов. Но действительно ли она должна быть ничем не ограничена? Можно поставить лимит в 1 млн элементов (чем бы они ни были), и отбрасывать слишком старые или слишком новые элементы. При соединении с сервисом по сети, действительно ли нужно использовать бесконечную блокировку? Можно же добавить таймаут. Должны ли соединения к серверу жить вечно, или хватит и пяти минут, а потом их можно убить? Ну вы поняли суть.

У нас в Imgur есть задача cron, которая называется «убийцей длинных запросов» — она сканирует активные зарпосы в MySQL, которые выполняются от имени запросов пользователей, и проверяет, как долго они выполняются, убивая те, что превышают заданный порог. Учитывая тот факт, что в PHP таймаут (max_execution_time) равняется 30 секундам, то запросы не должны выполняться больше нескольких минут. Этот убийца запросов, вполне вероятно, спас нас от многих бессонных ночей. Если у вас такого нет, создайте. Потом сами же скажете себе спасибо.

Используйте повторный запуск, но ограниченное число раз


Джим Грей написал в книге Why Do Computers Stop and What Can Be Done About It («Почему компьютеры останавливаются, и что с этим можно сделать») такую фразу: «большинство сбоев промышленных систем являются мягкими. Если просто перезапустить не выполнившуюся задачу, то обычно во второй раз сбоя не будет». Бывают баги, которые всплывают лишь время от времени, поэтому повысить доступность систем можно с помощью добавления функции повторного запуска. Однако, тут нужно быть аккуратным, чтобы не устроить DDoS на свои системы собственными руками!

Следует последовать первому совету и использовать ограниченное количество попыток перезапуска и заставлять систему ждать все больше времени при каждой попытке повторного пуска. Это поможет распределить нагрузку.

Нужно использовать контрольные процессы


Для создания софта с высокими требованиями по части доступности часто используется Erlang. В нем есть паттерн контроля (supervisors): каждая задача, которую выполняет программа, структурирована таким образом, чтобы работать под надзором контролирующего процесса (супервизора). Если супервизор обнаруживает неожиданное завершение задачи, он ее перезапускает (как в предыдущем правиле) с известного безошибочного состояния. Нет никакого смысла перезапускать то, что все равно не будет работать. Хорошим средством автоматического перезапуска веб-сервера или процессов-демонов является Monit.

Важно добавлять проверки здоровья и использовать их для перераспределения запросов


Разработчик должен думать о том, как свести всю кучу переменных в коде системе к простому булевому вопросу «здорова ли эта вещь? Работает ли она?» В Imgur используется встроенный в ELB мониторинг здоровья, который проверяет, живы ли сетевые узлы, и автоматически перераспределяет запросы к ним в случае падения.

Избыточность не просто «хорошо бы иметь», она обязательно должна быть


Если вы используете облачные сервисы, то может случиться так, что запущенные инстансы будут время от времени умирать. Так что избыточность в таком случае не просто что-то, что хорошо бы иметь, но требования для создания отказоустойчивых систем.

5148082ba36c496caec8720453504d3a.png

Как-то раз в Imgur пришло уведомление о выключении виртуальных машин в облаке Amazon. Обычно такие алерты приходят заранее, но в тот раз это случилось уже после удаления виртуалок (и после того, как PagerDuty и Nagios предупредили о наличии проблем).

Лучше проверенные временем средства, чем горячие новинки


Противостоять искушению попробовать в деле новые популярные инструменты довольно сложно. К прмиеру, DevOps-сообщество сходит с ума по CoreOS и легким контейнерам «в стиле LXC». Однако когда Джейкоб Гринлиф попробовал с ним работать, выяснилось, что в компоненте ядра (FleetD) содержался баг, затрагивавший работу с планировщиком, который мог повлечь остановку работы системы. Гринлиф смог разобраться с проблемой после многих часов отладки, завершившейся в два часа утра. Новые технологии часто могут содержать никому еще неизвестные ошибки и причины для сбоя.

Кроме того, у более новых проектов есть общая черта — часто они слишком сырые для работы в продакшене. Например, у Golang нет официального отладчика, а альтернативный открытый отладчик появился всего несколько месяцев назад. Также инструменты мониторинга и трассировки языка Go ни в какое сравнение не идут с Java JMX и Erlang.

© Habrahabr.ru