Нормально делай — нормально будет

Безусловно, хотя бы небольшим гарантом того, что вы не столкнетесь с потоком проблем после изменения кода, является его тестирование. Одним из видов является unit-тесты, в рамках которых мы проверяем функции на разные типы входов и смотрим, насколько это адекватно происходит. К сожалению, такая методика не очень прижилась во «ВКонтакте». Все знают, что это нужно делать, но никто этого не делает. Зато большинство команд в обязательном порядке делает code review. Это в первую очередь механизм, который помогает выявить частые ошибки и дурацкие оплошности, которые можно отследить в коде. Важно понимать, что он существует не для того, чтобы «задолбать» своих коллег стайл-гайдами, указаниями на количество пропущенных строк и так далее. Ставьте на первое место исправление багов. Далее — интеграционное тестирование (одна из фаз тестирования программного обеспечения, при которой отдельные программные модули объединяются и тестируются в группе — прим. ред.). Это, пожалуй, лучший закрепляющий предыдущие действия способ проверить, все ли у вас порядке. Бытует мнение, что программисты «ВКонтакте» не тестируют свой код, что у нас нет отдела тестирования. Это неправда. У нас есть отдел тестирования — очень хорошие люди, мы их очень любим.

Стоит, однако, понимать, что ни одна система тестирования не заменит живых людей, которые придут и все вам сломают. Практика показывает, что, как бы тщательно вы все ни тестировали, какой-то баг все равно может просочиться в продакшен. Не тешьте себя надеждами: у вас обязательно что-то сломается.

Найти проблему в «стоге» кода

Как узнать о том, что что-то сломалось? Особенно, если у вас сервис такого масштаба, как «ВКонтакте».

Конечно, масштаб ресурса иногда играет на руку: в целом, если отвалится какой-то функционал и вы быстро «пофиксите» проблему, 70% пользователей ничего и не заметят. Поэтому скорость — главное. Для поиска ошибок необходимо использовать всяческую статистику. У нас есть различные графики, которые отражают критерии работы того или иного раздела — например, по времени ответа на запрос пользователя. Если на более-менее стабильном графике появляется какое-то пиковое значение, значит, велика вероятность поломки — нужно чинить. Если сразу на нескольких графиках появились такие «пики» совсем все плохо. Очень полезно сравнивать графики между собой: это помогает правильно реагировать на скачки и не трубить ложную тревогу. Наиболее показательные графики мы объединяем в дэшборды, которые анализируют специалисты.

Графики. Источник: github.com/Termina1/toobigtofail-presentation
Графики. Источник: github.com/Termina1/toobigtofail-presentation

Мы также уделяем внимание статистике обращения в техподдержку. Наши пользователи, вообще, любят обращаться в техподдержку. В обычной ситуации мы получаем порядка шестидесяти обращений в пятиминутку в духе «Зачем вы меня заблокировали» или «Удалите мои голые фотографии со страницы такого-то человека». Однако, когда случается реальная проблема, количество обращений возрастает до 400 за пятиминутный период.

Также мы используем и нестандартные подходы к анализу ситуации, отслеживая пользующийся популярностью хэштег «вкживи» в Twitter.

Многие слышали, что «ВКонтакте» использует самописные базы данных, которые быстро работают и оптимизированы под конкретную задачу. Один из плюсов этого подхода заключается в том, что у нас унифицированные протоколы общения. Это позволяет нам иметь одну точку входа ко всем базам данных и при необходимости блокировать абсолютно все запросы.

Коллекционеры ошибок

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

Исследуйте коммиты (сохранение изменений в программном коде — прим ред.) на графике. Собственно, если вы видите, что у вас на одном из графиков вылез «пик» и там пачка коммитов, то, скорее всего, они и привели к проблеме. Если там не сотни строчек кода, то вы довольно быстро найдете ошибку. Также у нас есть специальный чат, в который вбрасываются сообщения при каждом деплое вместе со списком коммитов, которые его сопровождают. Это довольно часто помогает.

Коммиты на графике. Источник: github.com/Termina1/toobigtofail-presentation
Коммиты на графике. Источник: github.com/Termina1/toobigtofail-presentation

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

Тесты на людях

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

Как мы поступаем в таких случаях? Что делаем, чтобы пользователи не страдали? Мы очень любим в компании простые решения. В данном случае таким решением стал «if и рандом». Допустим, у нас есть старый код и новый код. Каждый раз, когда приходит запрос от пользователя, вы «подкидываете монетку» и отправляете его либо на старый код, либо на новый. Определяя процент «испытуемых» (тех, кого будете перенаправлять на тестирование нового кода), вы ограничиваете количество пользователей, которые столкнутся с проблемами в случае какой-либо ошибки. И этот способ отлично работает. С инфраструктурными изменениями примерно то же самое. Чтобы у вас не случилось падение всех серверов, доступ к этим изменениям есть только у части пользователей. Если что-то пойдет не так, то «крашнутся» от одного до десяти серверов. Это, конечно, не очень приятно, но пережить можно.

Источник: github.com/Termina1/toobigtofail-presentation
Источник: github.com/Termina1/toobigtofail-presentation

Помните, что, когда у вас Highload (высокая степень нагрузки на ресурс — прим. ред.), все плохое, что может произойти, обязательно случится. Теория вероятности работает против вас. У вас сотня миллионов запросов в секунду, так что, даже если вероятность какой-то проблемы составляет 1% или 0,1%, будьте уверены, что что-то сломается, причем с минуты на минуту. Код нам ошибок не прощает, так что «забивать» на них нельзя. Мне кажется, это одно из самых важных правил для Highload-проектов.

Подводя итог, сформирую несколько советов. Помните, что люди ошибаются гораздо чаще, чем машины. Так что старайтесь автоматизировать все, что только можно автоматизировать. Человек — это просто непрерывный генератор багов, поэтому старайтесь поменьше использовать эту ненадежную систему.

Обложитесь статистикой по полной. Используете любые индикаторы неполадок, в том числе самые нестандартные.

Обеспечьте себе быстрые «роллбэки» (rollback — откат какого-либо изменения — прим. ред.). Это позволит вам сэкономить нервы: просто откатитесь назад и спокойно изучайте проблему, пытаясь найти решение. Если вы сделаете это быстро, большинство пользователей даже не заметят проблемы.

Коммуникации. Нужно быть командой, чтобы решить проблему.

Ну, и главное — не паникуйте.

Лекция Вячеслава Шебанова прошла в рамках конференции IT Hardcore, 8 октября.