Pokémon GO в 2016 году: как игра получила в 50 раз больше трафика, чем планировали, и что сделали Niantic и Google
Команда KAI Lab · · 9 мин чтения
Летом 2016 года Pokémon GO получила в 50 раз больше трафика, чем закладывала в план студия Niantic, и в 10 раз больше её худшего сценария. Игру удержали на Google Container Engine (GKE): на ходу обновили кластер Kubernetes, чтобы добавить в него больше тысячи узлов, и заменили сетевой балансировщик на глобальный HTTP(S) Load Balancer.
Сам переход на новый балансировщик вызвал каскадный сбой. Клиенты игры повторяли запросы синхронно, всплески дошли до 20× прошлого пика, и ёмкость балансировщиков Google по всему миру фактически упала вдвое. Эту историю рассказал сам Google: в блоге Google Cloud и в книге The Site Reliability Workbook.
Главное о запуске в одной таблице
| Вопрос | Ответ |
|---|---|
| Когда | июль 2016: Австралия и Новая Зеландия, на следующий день США, через две недели Япония |
| План | 1X трафика, худший сценарий — примерно 5X. Нагрузочные тесты — до 5X самых оптимистичных оценок |
| Факт | 50X плана, в 10 раз больше худшего сценария |
| Где работала игра | логика — в GKE на Kubernetes, основная база — Cloud Datastore, всего больше десятка сервисов Google Cloud |
| Масштаб | десятки тысяч ядер, крупнейшее на тот момент развёртывание Kubernetes в GKE |
| Что меняли на ходу | версию GKE ради тысячи с лишним новых узлов; Network Load Balancer на HTTP(S) Load Balancer |
| Каскадный сбой | спрос на 200% выше наблюдаемого, синхронные повторы до 20× прошлого пика, ёмкость балансировщиков в мире −50% |
| Итог | запуск в Японии прошёл без инцидентов, хотя новых игроков было втрое больше, чем при запуске в США |
Хронология запуска Pokémon GO
| Когда | Что произошло |
|---|---|
| до запуска | Niantic тестирует стек на нагрузку до 5X самых оптимистичных оценок |
| запуск в Австралии и Новой Зеландии | Через 15 минут трафик уходит далеко за ожидания. Niantic зовёт на помощь команду Google CRE: запуск в США — на следующий день |
| запуск в США | Трафик растёт до 50X плана. График транзакций Cloud Datastore — главной базы игры — становится прямым показателем её популярности |
| следующие недели | Google выделяет десятки тысяч ядер. Кластер обновляют до новой версии GKE, в которую можно добавить больше тысячи узлов |
| перед запуском в Японии | После крупной SYN-флуд-атаки Network Load Balancer заменяют на HTTP(S) Load Balancer. Через два дня Pokémon GO — самый большой сервис на нём |
| после переезда | Каскадный сбой: балансировщики Google теряют половину ёмкости, страдают все их клиенты |
| через две недели после США | Запуск в Японии без инцидентов, регистраций втрое больше, чем при запуске в США |
50X — это не «просто добавить подов»
Команды Google и Niantic планировали 1X и держали в уме худший сценарий в 5X. Реальность оказалась в 50X. Google выделил под кластер Niantic десятки тысяч ядер. По словам Google, это было крупнейшее развёртывание Kubernetes в Container Engine за всю его историю.
Добавить реплик мало, если упираешься в потолок самого кластера. Чтобы добавить больше тысячи узлов, кластер пришлось обновить до новой версии GKE прямо под нагрузкой. Google сравнивает это с заменой двигателя у самолёта в полёте: делали осторожно, чтобы не задеть игроков, которые уже в игре.
Ёмкость в Kubernetes многослойная. Поды упираются в узлы, узлы — в лимиты кластера и облачные квоты, всё вместе — в балансировщик и базу. Когда кончаются узлы, новые поды просто висят в статусе Pending, как в разборе ошибки Pod Pending. В июле 2016 года Niantic прошла все эти слои по очереди.
Новый балансировщик и каскадный сбой
Как было
Трафик принимал региональный Network Load Balancer и раскидывал его по кластеру Kubernetes. В кластере работали поды с Nginx. Они завершали SSL — это две сетевые поездки от телефона до прокси — и буферизовали HTTP-запросы, из-за чего на прокси кончались ресурсы. Защиты от низкоуровневых сетевых атак у этой схемы не было, и крупная SYN-флуд-атака сделала переезд срочным.
Что дал GCLB
В глобальном балансировщике Google (GCLB) SSL завершают Google Front End (GFE) — серверы на границе сети Google, как можно ближе к пользователю. К бэкендам GFE держат постоянные соединения, а трафик между GFE распределяет Maglev. Через два дня после переезда Pokémon GO стала самым большим сервисом GCLB.
Как всё сломалось
- Спрос оказался больше, чем думали. Раньше прокси Niantic не успевали принять все соединения, а отказанные соединения не попадали в мониторинг входящих запросов. После переезда выяснилось, что реальный спрос на 200% выше наблюдаемого.
- Бэкенды стали медленными, а не отказывали. Перегруженные бэкенды не отвечали отказом, а тормозили. Запросы упирались в таймауты, и балансировщик повторял GET-запросы, добавляя нагрузку.
- Пострадал сам балансировщик. Код GFE, который переподключался по SSL к зависшим бэкендам, получил небывалую нагрузку. Производительность GFE просела так, что ёмкость GCLB по всему миру фактически упала на 50%.
- Клиенты пришли толпой. Приложение при ошибке делало один мгновенный повтор, потом ждало фиксированное время. Когда общие бэкенды падали и перезапускались, клиенты повторяли запросы практически одновременно. Google называет это «thundering herd»: всплески дошли до 20× прошлого мирового пика запросов в секунду.
Очереди и высокие задержки получили все сервисы на GCLB, а не только игра.
Как остановили
Команда Traffic SRE отделила GFE, которые обслуживали Pokémon GO, от общего пула и расширяла этот пул, пока он не начал выдерживать пиковый трафик. Затем поставила административный лимит на скорость трафика, который балансировщики принимали для игры, чтобы Niantic восстанавливалась и наращивала бэкенды постепенно.
После сбоя Niantic добавила в клиент джиттер и ограниченную экспоненциальную задержку повторов. Google ввёл нагрузочные тесты, которые ловят деградацию GFE из-за медленных бэкендов.
Уроки для DevOps
1. Худший сценарий — это ещё не худший сценарий
Niantic тестировала нагрузку до 5X, а пришло 50X. Не существует запаса, который гарантированно хватит. Поэтому, кроме запаса, нужны способы деградировать управляемо: лимиты, очереди, отключаемые функции.
2. Мерьте нагрузку как можно ближе к клиенту
Это главный вывод Google из case study. Если прокси отбрасывает соединения, в логах приложения их нет, и вы видите не спрос, а ту часть, которую успели принять. На Linux часть потерь видна в счётчиках ядра:
# соединения, отброшенные из-за переполненной очереди accept, — в логах nginx их не будет
nstat -az TcpExtListenOverflows TcpExtListenDropsРастущие значения значат, что клиенты стучатся, а сервер их не пускает. Метрики доступности, которые считают со стороны клиента, мы разбирали в статье про SLO, SLI и бюджет ошибок.
3. Медленный отказ опаснее быстрого
Перегруженный бэкенд, который отвечает за 30 секунд, держит соединения, съедает ресурсы балансировщика и провоцирует повторы. Быстрый отказ с кодом 503 и коротким таймаутом дешевле для всех. Отдавайте ошибку сразу, когда очередь переполнена.
4. Повторы — с экспоненциальной задержкой и джиттером
Мгновенный повтор и фиксированная пауза синхронизируют клиентов: все упали вместе и вместе вернулись. Задержка должна расти, иметь потолок и случайную часть:
# повтор с экспоненциальной задержкой, потолком и «полным джиттером»
max_delay=30
for attempt in 1 2 3 4 5 6; do
curl -fsS --max-time 5 https://api.example.com/v1/status && break
delay=$(( 2 ** attempt )); (( delay > max_delay )) && delay=$max_delay
sleep $(( RANDOM % delay + 1 )) # случайно от 1 до delay секунд
doneТо же относится к ретраям в сервис-мешах, клиентских библиотеках и джобах CI: везде, где повтор настроен по умолчанию, проверьте, есть ли у него задержка и джиттер.
5. Выкатывайтесь волнами
Австралия и Новая Зеландия оказались канарейкой для США, США — для Японии. Каждая волна показала узкие места до следующей. Регион за регионом — тот же принцип, что поэтапная выкатка релиза.
6. Держите аварийный тормоз
Административный лимит трафика вернул систему под контроль. У вашего сервиса должен быть заранее отрепетированный рычаг: rate limit на входе, отключение тяжёлых функций, страница «мы перегружены» вместо зависания.
Что проверить у себя завтра:
- какой потолок у вашего кластера: узлы, квоты облака, лимиты балансировщика;
- видите ли вы отказанные соединения, а не только обработанные запросы;
- как ваши клиенты и сервисы повторяют запросы при ошибке;
- есть ли рычаг, который ограничит входящий трафик за минуту.
Реши сам
Два вопроса по этому сбою. Ответы — под спойлером.
Вопрос 1. Почему повторы запросов из приложения усилили сбой?
- Приложение не повторяло запросы вообще
- Один мгновенный повтор и фиксированная пауза синхронизировали клиентов, и они возвращались толпой
- Повторы шли через другой балансировщик
- Повторы блокировал антивирус
Показать ответ
Верный ответ — 2. Когда бэкенды падали и поднимались, клиенты повторяли запросы одновременно, и всплески доходили до 20× прошлого пика. Niantic добавила джиттер и ограниченную экспоненциальную задержку.
Вопрос 2. Почему после переезда на GCLB реальный спрос оказался на 200% выше наблюдаемого?
- Игроков стало втрое больше за два дня
- Раньше прокси отбрасывали часть соединений, и эти отказы не попадали в мониторинг входящих запросов
- GCLB считает запросы дважды
- Мониторинг был выключен
Показать ответ
Верный ответ — 2. Мониторинг видел только принятые запросы. Новый балансировщик принимал больше соединений и показал настоящий спрос. Отсюда вывод Google: мерить нагрузку как можно ближе к клиенту.
Частые вопросы
Во сколько раз трафик Pokémon GO превысил план? В 50 раз. Команды планировали 1X, худший сценарий оценивали примерно в 5X, так что реальный трафик оказался в 10 раз больше худшего сценария.
На чём работала Pokémon GO? Логика игры работала в Google Container Engine (сегодня Google Kubernetes Engine) на Kubernetes. Основной базой был Cloud Datastore, а всего игра использовала больше десятка сервисов Google Cloud.
Что такое Google CRE? Customer Reliability Engineering — команда Google, которая работает внутри команд клиентов и делит с ними ответственность за надёжность важных приложений. Niantic позвала CRE через 15 минут после запуска в Австралии и Новой Зеландии.
Зачем меняли балансировщик посреди кризиса? Старая схема завершала SSL на подах Nginx, тратила на это лишние поездки по сети и не защищала от низкоуровневых атак. После крупной SYN-флуд-атаки переезд на глобальный HTTP(S) Load Balancer стал приоритетом.
Пройти похожий сбой самому
В симуляторе DevOps KAI Lab седьмой месяц посвящён переезду в Kubernetes. В нём есть разбор запуска Pokémon GO и тикет про автомасштабирование checkout перед ростом нагрузки. Как обновление Kubernetes может уронить весь сайт, показывает сбой Reddit 2023, а все разборы собраны в подборке 18 сбоев, которые должен знать DevOps-инженер.
Начать можно бесплатно: тест навыков и первые задания первого месяца.
Источники
- Google Cloud Blog, Luke Stone. Bringing Pokémon GO to life on Google Cloud, 30.09.2016 — план 1X, худший сценарий 5X, факт 50X, обновление GKE, замена балансировщика, запуск в Японии.
- Google. The Site Reliability Workbook, глава 11 «Managing Load», раздел Case Study 1: Pokémon GO on GCLB — схема до переезда, SYN-флуд, каскадный сбой, 200%, 20×, −50%, выводы.
- Linux man-pages. nstat(8) — счётчики сетевого стека ядра.