«Ура, нас зафичерили!» или Как сменить дата-центр под нагрузкой и без даунтаймов, когда всё летит к чертям

igorskikh 1 февраля в 13:10 7,3k


Пару лет назад мы располагались в самом cost-effective (читай: «дешевом») дата-центре в Германии. Чтобы вы понимали условия — роутинг мог сбоить от стойки к стойке или внутри неё; свитч в стойке перегружался или зависал; сам дата-центр постоянно ддосили; жесткие диски выходили из строя; материнские платы и сетевые карты сгорали; сервера произвольно выключались, перезагружались, а сетевые кабели выпадали как осенние листья во время урагана.

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

Наступила точка кипения и мы решили переезжать. Хотя в какой-то момент даже казалось, что дешевле нанять больше обслуживающего персонала, чтобы менеджерить ситуации в вышеупомянутом ДЦ. Но в итоге, чтобы «стало более лучше жить» — мы выбрали стабильность.
Выбор остановился на дата-центре в Голландии, в Амстердаме. А вот тут самое интересное: к тому времени у игры уже был приличный DAU, переезд нужно было осуществить онлайн, без даунтаймов, одновременно на обе платформы (Android и iOS). Мало того, мы получили фичеринг на Google Play, маркетинг еще и запустил рекламную кампанию. Как понимаете, дополнительного трафика стало очень и очень много.

В общем, задачка не самая обыденная и вот как мы с ней справлялись.

Общая архитектура


Первый мобильный синхронный PvP-шутер для компании, которая занималась преимущественно казуальными играми для соцсетей — это как шаг в неизвестность. О том, как эволюционировала архитектура проекта War Robots в самом начале, наши ребята уже написали, ну а у нас — команды разработки и системных администраторов — были свои челенджи.

Итак, наша общая архитектура:



По порядку:

  • Фронтенд-Бэкенд. Frontend: nginx; Backend: apiserver (tomcat) + hazelcast.
  • Отказоустойчивость. Мы могли (до переезда) и можем сейчас потерять только две ноды кассандры из кластера без последствий. Имели от 20 до 30 нод на платформу.
  • Репликейшен фактор. RF = 5.

Цели переезда


Во-первых, мы хотели сменить ДЦ, чтобы сделать игру более качественной. Доступность и отзывчивость сервисов — это один из самых важных компонентов надежности. Ну а во-вторых, пора было обновлять железо.

А вот достичь второстепенной цели — переехать на свежую кассандру — к сожалению, так и не удалось. Версии 2.1.13 и 2.1.15 в тестовых условиях не хотели нормально общаться друг с другом. Проводилось расследование, попытки понять почему, но сроки поджимали, поэтому оставили версию как есть. Собственно, поэтому на более свежие версии кассандры вообще не замахивались.

С чем столкнулись


Так как этап подготовки и тестирования затянулся и мы попали под увеличенную нагрузку (фичеринг со стороны Google Play и запуск маркетинговой кампании), поэтому необходимо было обеспечить супернадежность операции.


Рост DAU во время переезда в новый ДЦ с одновременным проведением рекламных кампаний и фичерингом.

По своей сути переезд — это сначала добавление второго ДЦ в кластер, переключение трафика, а затем удаление первого. Мы перевозили не только код, но и все данные игроков. Расстояние от приложения до БД должно быть минимальным. Для консистентности нужно постоянно писать в оба кольца, выбрав оптимальный consistency level, что накладывает на время ответа транспортные расходы на передачу данных в удаленный ДЦ. Нужно было обеспечить хорошую скорость доступа к БД в новом ДЦ (широкий и надежный канал связи между ДЦ).

Старый ДЦ имел весьма стабильные проблемы с железом и сетью. RF должен был спасти от внезапного выхода из строя железа. С возможностью развала кластера из-за сети можно было бороться тем, что мониторить процесс перегона данных, и в случае чего перекачивать данные несколько раз.

Что касается выбора нового дата-центра, то, вкратце, он должен был быть стабильнее в плане внутренней сети и связи с внешним миром и надежнее в плане железа. Мы готовы были платить больше за лучшее качество и настоящую, а не мнимую, доступность серверов 24/7.

Подготовка к переезду


Для этого нам нужно было сделать довольно много, а именно:

  • Были сервера, на которых одновременно крутился и код и ноды Cassandra. Нужно было разгрузить сервера, где крутились одновременно бэкенд и ноды кассандры, оставить только томкаты на тех машинах, декоммишнуть ноды кассандры там, и вместо них развернуть ноды на отдельных машинах (цель: в случае нагрузок на кассандру в ходе переезда и наплыва игроков может подскочить использование ресурсов, нужно отдать БД все, что есть на машине).
  • К сожалению, так сложилось, что старое кольцо работало на SimpleSnitch. Он не гибок, не позволяет использовать несколько DC в полной мере (в терминах кассандры). Для продуктива со своим железом рекомендуется GossipingPropertyFIleSnitch. Он позволяет динамически управлять кольцом через настройки и протокол gossip-ера. Сменить snitch (SimpleSnitch -> GossipingPropertyFileSnitch) и topology (SimpleStrategy -> NetworkTopologyStrategy). Инструкции по добавлению ДЦ и смене конфигурации БД не изобретались, все уже давно есть в документации.
  • Протестировать переезд, т.к. до этого ничего такого не делали. Для этого взяли отдельно сервера, написали код, который создает нагрузку, и во время нагрузки меняли настройки, добавляли ДЦ в кассандру, перекачивали данные, включали нагрузку на новый ДЦ и проверяли данные в новом кольце. На этом этапе мы пробовали обновлять кассандру, но после обновления кольца переставали видеть друг друга и плевались ошибками. Причем пробовалось обновить оба кольца. Засада была где-то в этой версии кассандры. Также тут мы пробовали ломать связь между кольцами и наблюдать, как поведет себя кластер и ребилд. После этого отдельный код проверял, что мы затянули все данные.
  • Подумать над вариантами отката и запасными вариантами, когда наступает стадия невозврата.
  • Взять свежее и мощное железо, т.к. планировалось увеличение нагрузки (тут же, кстати, под кассандры поставили SSD). Нужно было посчитать объемы данных и взять диски с запасом, т.к. кассандра требует X2 и более места для ребилда. Все зависит от выбранной стратегии компакшна. Всегда нужно считать, чтобы было не меньше, чем X2.
  • Подготовить настройки для новых машин. Одновременно с переездом в другой ДЦ мы решили переехать с Puppet на Ansible. В рамках этого же пункта мы планировали навести порядок в инфраструктуре, отточить конфигурирование серверов и быстрое добавление нового железа в строй. Также нужно было улучшить мониторинг.

Как надо было сделать


*DC1 — старый ДЦ, DC2 — новый ДЦ.

  • Развернуть бэкенд в DC2 в отключенном видe, с write CL=EACH_QUORUM. Почему EACH_QUORUM? Если придется возвращаться в DC1, то так меньше шанс, что потеряются данные, т.к. они попадут в оба ДЦ.
  • Развернуть пустые кассандры проставить настройки:
    auto_bootstrap = false
    seeds = пока что список сидов из старого ДЦ
    endpoint_snitch = GossipingPropertyFileSnitch
    dc = DC2
  • Запустить кольцо нового ДЦ, проверить, что nodetool status в обоих ДЦ показывает, что все хорошо: все ноды подняты (UN), в логах БД ошибок нет.
  • Настроить keyspace (объявляем, что данные будут в DC1, DC2):
    UPDATE KEYSPACE WarRobots with placement_strategy = 'NetworkTopologyStrategy'
    and strategy_options = {'dc1': 5, 'dc2': 5};
  • Включить EACH_QUORUM на запись в бэкенде DC1.
  • Запустить ребилд данных на DC2 с указанием, откуда брать данные для DC2:
    nodetool rebuild dc1
  • После окончания ребилда нужно запустить код в DC2, подключиться клиентами и протестировать.
  • Последовательно под наблюдением перекинуть трафик nginx-ом на API в DC2.
  • Понаблюдать и перекинуть DNS.
  • Дождаться полного перевода трафика на DC2, выключить бэкенд на DC1, перевести бэкенд DC2 на writeCL=LOCAL_QUORUM (точка невозврата).
  • Отключить DC1 от keyspace War Robots.
  • Декомишнуть кольцо DC1.

Как сделали мы и почему


  • Развернули бэкенд (в отключенном видe, с write CL=EACH_QUORUM).
  • Развернули пустые кассандры, сконфигурировали.
  • Запустили кольцо DC2.
  • Настроили keyspace.
  • Выполнили полный ребилд данных на DC2 с указанием источника DC1.
  • Запустили бэкенд на DC2.
  • Подключились клиентом, проверили, что все хорошо.
  • Включили EACH_QUORUM на запись в бэкенде DC1.
  • Запустили еще раз ребилд данных на DC2 с указанием брать данные из DC1. У нас были проблемы с сетью и железом в процессе переезда, поэтому провести второй ребилд посчитали необходимым.
  • После окончания ребилда последовательно перекинули трафик nginx-ом на DC2.
  • Понаблюдали и перекинули DNS.
  • Дождались полного перевода трафика на DC2, выключили бэкенд на DC1, перевели бэкенд DC2 на writeCL=LOCAL_QUORUM (точка невозврата)
  • Отключили DC1 от keyspace War Robots.
  • Декомишнули кольцо DC1.

Риски при нашей реализации

Мы могли уйти в даунтайм из-за высокой нагрузки на базу на старом кольце (честно говоря, оно было не в лучшем состоянии). Мы также могли потенциально что-то потерять в ходе переноса данных в случае сбоев в сети — отчасти поэтому мы решили перестраховаться и провести два ребилда.

Положительные стороны

Мы могли переключиться назад в старый ДЦ в любой момент вплоть до точки невозврата. После точки невозврата тоже могли бы, но тогда бы мы потеряли прогресс по игрокам за несколько дней. Хотя мы могли бы его перелить обратно с DC2 в DC1.

Мы также имели возможность протестировать, что все хорошо с обоими DC кассандры и данные перетекают в обе стороны.

Какие моменты мы не рассчитали и как боролись с последствиями

В процессе переезда упала нода на DC1 (посыпался винт, закорраптились локальные данные ноды), пришлось ее вырубить и переезжать с одной запасной нодой в кольце.

Также для повторного ребилда у нас не хватило места для платформы iOS, пришлось оперативно докупать и расширять диски. Мы пробовали использовать сервера с HDD, чтобы размазать данные кольца DC2 и не докупать диски (покупка дисков — это время), но это катастрофически снизило скорость перегона данных. Поэтому пришлось все же дождаться поставки дисков.

Результат


В качестве результата наиболее наглядно будет привести графики (резкое падение на графиках связано с кратковременными проблемами с аналитикой, а не даунтайм, как может показаться):


Среднее время ответа на клиентский запрос загрузки профиля игрока.


Среднее время ответа БД.

К сожалению, показатели нагрузки железа не сохранились. По памяти, кассандры ели около 60% CPU в старом ДЦ. На данный момент значение держится на 20% (с тем, что DAU, в периоды высокого DAU и нагрузке может подниматься до 40%).

Итоги


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

На текущий же момент доступность и надежность игрового мира и данных игроков существенно выросла:

  • мы ускорили работу сервисов за счет более мощного, надежного железа и переноса данных БД на SSD;
  • снизили задержки в ответах клиенту за счет размещения серверов БД и кода как можно ближе друг к другу в пределах ДЦ;
  • заменили систему управления инфраструктурой, усовершенствовали мониторинг;
  • получили бесценный опыт по управлению кластером Cassandra и миграции данных в боевых условиях в другой дата-центр;
  • ну и конечно же, привели в норму количество часов ночного сна у серверных разработчиков и системных администраторов.
Проголосовать:
+30
Сохранить: