Роковые 43 секунды, которые вызвали суточную деградацию сервиса

На прошлой неделе в GitHub произошёл инцидент, который привёл к деградации сервиса на 24 часа и 11 минут. Инцидент затронул не всю платформу, а только несколько внутренних систем, что привело к отображению устаревшей и непоследовательной информации. В конечном счете данные пользователей не были потеряны, но ручная сверка нескольких секунд записи в БД выполняется до сих пор. На протяжении почти всего сбоя GitHub также не мог обрабатывать вебхуки, создавать и публиковать сайты GitHub Pages.

Все мы в GitHub хотели бы искренне извиниться за проблемы, которые возникли у всех вас. Мы знаем о вашем доверии GitHub и гордимся созданием устойчивых систем, которые поддерживают высокую доступность нашей платформы. С этим инцидентом мы вас подвели и глубоко сожалеем. Хотя мы не можем отменить проблемы из-за деградации платформы GitHub в течение длительного времени, но можем объяснить причины произошедшего, рассказать об усвоенных уроках и о мерах, которые позволят компании лучше защититься от подобных сбоев в будущем.

Предыстория


Большинство пользовательских сервисов GitHub работают в наших собственных центрах обработки данных. Топология ЦОД предназначена для обеспечения надёжной и расширяемой граничной сети перед несколькими региональными ЦОД, которые обеспечивают работу вычислительных систем и систем хранения данных. Несмотря на уровни избыточности, встроенные в физические и логические компоненты проекта, по-прежнему возможна ситуация, когда сайты не смогут взаимодействовать друг с другом в течение некоторого времени.

21 октября в 22:52 UTC плановые ремонтные работы по замене неисправного оптического оборудования 100G привели к потере связи между сетевым узлом на Восточном побережье (US East Coast) и основным дата-центром на Восточном побережье. Подключение между ними восстановилось через 43 секунды, но это короткое отключение вызвало цепочку событий, которые привели к 24 часам и 11 минутам деградации сервиса.


Высокоуровневая сетевая архитектура GitHub, включая два физических центра обработки данных, 3 POP и облачные хранилища в нескольких регионах, подключённые через пиринг

В прошлом мы обсуждали, как используем MySQL для хранения метаданных GitHub, а также наш подход к обеспечению высокой доступности MySQL. GitHub управляет несколькими кластерами MySQL размером от сотен гигабайт до почти пяти терабайт. В каждом кластере десятки реплик чтения для хранения метаданных, отличных от Git, поэтому наши приложения обеспечивают пул-реквесты, тикеты (issues), аутентификацию, фоновую обработку и дополнительные функции за пределами хранилища объектов Git. Различные данные в разных частях приложения хранятся в различных кластерах с помощью функционального сегментирования.

Для повышения производительности в большом масштабе приложения направляют записи на соответствующий первичный сервер для каждого кластера, но в подавляющем большинстве случаев делегируют запросы на чтение подмножеству серверов-реплик. Мы используем Orchestrator для управления топологиями кластеров MySQL и автоматической отработки отказов. В ходе этого процесса Orchestrator учитывает ряд переменных и собран поверх Raft для согласованности. Orchestrator потенциально может реализовать топологии, которые приложения не поддерживают, поэтому необходимо следить за соответствием конфигурации Orchestrator ожиданиям на уровне приложений.


В обычной топологии все приложения выполняют чтение локально с низкой задержкой

Хроника инцидента


21.10.2018, 22:52 UTC


Во время упомянутого разделения сети Orchestrator в основном дата-центре начал процесс отмены выбора руководства согласно алгоритму консенсуса Raft. Дата-центр Западного побережья и узлы Orchestrator публичного облака на Восточном побережье сумели достичь консенсуса — и начали отработку отказа кластеров для направления записей в западный дата-центр. Orchestrator начал создавать топологию кластера БД на Западе. После восстановления подключения приложения сразу направили трафик по записи на новые основные сервера в US West.

На серверах БД в восточном дата-центре остались записи за краткий период, которые не реплицировались в западный ЦОД. Поскольку кластеры БД в обоих ЦОД теперь содержали записи, которых не было в другом ЦОД, мы не смогли безопасно вернуть первичный сервер обратно в восточный дата-центр.

21.10.2018, 22:54 UTC


Наши внутренние системы мониторинга начали генерировать оповещения, указывающие на многочисленные сбои в работе систем. В это время несколько инженеров отвечали и работали над сортировкой входящих уведомлений. К 23:02 инженеры первой группы реагирования определили, что топологии для многочисленных кластеров БД находятся в неожиданном состоянии. При запросе API Orchestrator отображалась топология репликации БД, содержащая только серверы из западного ЦОД.

21.10.2018, 23:07 UTC


К этому моменту группа реагирования решила вручную заблокировать внутренние средства развёртывания, чтобы предотвратить внесение дополнительных изменений. В 23:09 группа установила жёлтый статус работоспособности сайта. Это действие автоматически присвоило ситуации статус активного инцидента и отправило предупреждение координатору инцидентов. В 23:11 координатор присоединился к работе и через две минуты принял решение изменить статус на красный.

21.10.2018, 23:13 UTC


На тот момент было понятно, что проблема затрагивает несколько кластеров БД. К работе привлекли дополнительных разработчиков из инженерной группы БД. Они начали исследовать текущее состояние, чтобы определить, какие действия необходимо предпринять, чтобы вручную настроить базу данных Восточного побережья США в качестве основной для каждого кластера и перестроить топологию репликации. Это было непросто, поскольку к этому моменту западный кластер баз данных принимал записи с уровня приложений в течение почти 40 минут. Кроме того, в восточном кластере существовало несколько секунд записей, которые не были реплицированы на запад и не позволяли реплицировать новые записи обратно на восток.

Защита конфиденциальности и целостности пользовательских данных является наивысшим приоритетом GitHub. Поэтому мы решили, что более 30 минут данных, записанных в западный ЦОД, оставляют нам только один вариант решения ситуации, чтобы сохранить эти данные: перенос вперёд (failing-forward). Однако приложения на востоке, которые зависят от записи информации в западный кластер MySQL, в настоящее время не способны справиться с дополнительной задержкой из-за передачи большинства их вызовов БД туда и обратно. Это решение приведёт к тому, что наш сервис станет непригодным для многих пользователей. Мы считаем, что длительная деградация качества обслуживания стоила того, чтобы обеспечить согласованность данных наших пользователей.


В неправильной топологии нарушена репликация с Запада на Восток, а приложения не могут считывать данные из текущих реплик, поскольку зависят от низкой задержки для поддержания производительности транзакций

21.10.2018, 23:19 UTC


Запросы о состоянии кластеров БД показали, что необходимо остановить выполнение заданий, которые пишут метаданные типа пуш-запросов. Мы сделали выбор и сознательно пошли на частичную деградацию сервиса, приостановив вебхуки и сборку GitHub Pages, чтобы не ставить под угрозу данные, которые уже получили от пользователей. Другими словами, стратегия заключалась в расстановке приоритетов: целостность данных вместо удобства использования сайта и быстрого восстановления.

22.10.2018, 00:05 UTC


Инженеры из группы реагирования начали разрабатывать план устранения несогласованности данных и запустили процедуры отработки отказа для MySQL. План состоял в том, чтобы восстановить файлы из бэкапа, синхронизировать реплики на обоих сайтах, вернуться к стабильной топологии обслуживания, а затем возобновить обработку заданий в очереди. Мы обновили статус, чтобы сообщить пользователям, что собираемся выполнить управляемую отработку отказа внутренней системы хранения данных.


План восстановления предполагал перенос вперёд, восстановление из бэкапов, синхронизацию, откат назад и отработку просрочки, прежде чем вернуться на зелёный статус

Хотя резервные копии MySQL делаются каждые четыре часа и сохраняются в течение многих лет, но они лежат в удалённом облачном хранилище блоб-объектов. Восстановление нескольких терабайт из бэкапа заняло несколько часов. Долго шла передача данных из службы удалённого резервного копирования. Основная часть времени ушла на процесс распаковки, проверки контрольной суммы, подготовки и загрузки больших файлов бэкапа на свежеподготовленные серверы MySQL. Эта процедура тестируется ежедневно, поэтому все хорошо представляли, сколько времени займёт восстановление. Однако до этого инцидента нам никогда не приходилось полностью перестраивать весь кластер из резервной копии. Всегда работали другие стратегии, такие как отложенные реплики.

22.10.2018, 00:41 UTC


К этому времени был инициирован процесс резервного копирования для всех затронутых кластеров MySQL, и инженеры отслеживали прогресс. Одновременно несколько групп инженеров изучали способы ускорения передачи и восстановления без дальнейшей деградации сайта или риска повреждения данных.

22.10.2018, 06:51 UTC


Несколько кластеров в восточном ЦОД завершили восстановление из резервных копий и начали реплицировать новые данные с Западным побережьем. Это привело к замедлению загрузки страниц, которые выполняли операцию записи через всю страну, но чтение страниц из этих кластеров БД возвращало актуальные результаты, если запрос чтения попадал на только что восстановленную реплику. Другие более крупные кластеры БД продолжали восстанавливаться.

Наши команды определили способ восстановления непосредственно с Западного побережья, чтобы преодолеть ограничения пропускной способности, вызванные загрузкой из внешнего хранилища. Стало практически на 100% понятно, что восстановление завершится успешно, а время для создания здоровой топологии репликации зависит от того, сколько займёт догоняющая репликация. Эта оценка была линейно интерполирована на основе доступной телеметрии репликации, и страница состояния была обновлена, чтобы установить ожидание в два часа в качестве расчётного времени восстановления.

22.10.2018, 07:46 UTC


GitHub опубликовал информационное сообщение в блоге. Мы сами используем GitHub Pages, и все сборки поставили на паузу несколько часов назад, поэтому публикация потребовала дополнительных усилий. Приносим извинения за задержку. Мы намеревались разослать это сообщение гораздо раньше и в будущем обеспечим публикации обновлений в условиях таких ограничений.

22.10.2018, 11:12 UTC


Все первичные БД вновь переведены на Восток. Это привело к тому, что сайт стал гораздо более отзывчивым, так как записи теперь были направлялись на сервер БД, расположенный в том же физическом ЦОД, что и наш уровень приложений. Хотя это существенно повысило производительность, всё ещё остались десятки реплик чтения БД, которые отставали от основной копии на несколько часов. Эти отложенные реплики привели к тому, что пользователи видели несогласованные данные при взаимодействии с нашими службами. Мы распределяем нагрузку чтения по большому пулу реплик чтения, и каждый запрос к нашим службам имеет хорошие шансы попасть в реплику чтения с задержкой в несколько часов.

На самом деле время догона отстающей реплики сокращается по экспоненте, а не линейно. Когда проснулись пользователи в США и Европе, из-за увеличения нагрузки на записи в кластерах БД процесс восстановления занял больше времени, чем предполагалось.

22.10.2018, 13:15 UTC


Мы приближались к пику нагрузки на GitHub.com. В команде реагирования прошло обсуждение дальнейших действий. Было ясно, что отставание репликации до согласованного состояния увеличивается, а не уменьшается. Ранее мы начали подготовку дополнительных реплик чтения MySQL в общедоступном облаке Восточного побережья. Как только они стали доступны, стало легче распределять поток запросов на чтение между несколькими серверами. Уменьшение средней нагрузки на реплики чтения ускорило догон репликации.

22.10.2018, 16:24 UTC


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

22.10.2018, 16:45 UTC


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

Когда мы повторно включили обработку этих данных, то обработали около 200 000 полезных задач с вебхуками, которые превысили внутренний TTL и были отброшены. Узнав об этом, мы остановили обработку и запушили увеличение TTL.

Чтобы избежать дальнейшего снижения надёжности наших обновлений статуса, мы оставили статус деградации до тех пор, пока не завершим обработку всего накопившегося объёма данных и не убедимся, что сервисы чётко вернулись к нормальному уровню производительности.

22.10.2018, 23:03 UTC


Все незавершённые события вебхуков и сборки Pages обработаны, а целостность и правильная работа всех систем подтверждена. Статус сайта обновлён на зелёный.

Дальнейшие действия


Устранение несоответствия данных


Во время восстановления мы зафиксировали бинарные логи MySQL c записями в основном ЦОД, которые не реплицировались на западный. Общее число таких записей относительно невелико. Например, в одном из самых загруженных кластеров всего 954 записи за эти секунды. В настоящее время мы анализируем эти логи и определяем, какие записи могут быть автоматически согласованы, а какие потребуют содействия пользователей. В этой работе участвует несколько команд, и наш анализ уже определил категорию записей, которые пользователь затем повторил — и они успешно сохранились. Как указано в этом анализе, нашей основной целью является сохранение целостности и точности данных, которые вы храните на GitHub.

Коммуникация


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

Технические меры


В ходе этого анализа был выявлен ряд технических мер. Анализ продолжается, список может быть дополнен.

  • Отрегулировать конфигурацию Orchestrator, чтобы запретить перемещение первичных БД за границы региона. Orchestrator работал в соответствии с настройками, хотя уровень приложений не поддерживал такое изменение топологии. Выбор лидера внутри региона обычно безопасен, но внезапное появление задержки из-за передачи трафика через весь континент стало основной причиной этого инцидента. Это эмерджентное, новое поведение системы, ведь раньше мы не сталкивались с внутренним разделом сети такого масштаба.
  • Мы ускорили миграцию на новую систему отчётности по статусам, которая предоставит более подходящую площадку для обсуждения активных инцидентов более чёткими и ясными формулировками. Хотя многие части GitHub были доступны на протяжении всего инцидента, мы могли выбрать только зелёный, жёлтый и красный статусы для всего сайта. Признаём, что это не даёт точной картины: что работает, а что нет. Новая система будет отображать различные компоненты платформы, чтобы вы знали статус каждой службы.
  • За несколько недель до этого инцидента мы запустили общекорпоративную инженерную инициативу для поддержки обслуживания трафика GitHub из нескольких ЦОД по архитектуре active/active/active. Цель данного проекта — поддержка избыточности N+1 на уровне ЦОД, чтобы выдерживать отказ одного ЦОД без вмешательства со стороны. Это большая работа и займёт некоторое время, но мы считаем, что несколько хорошо связанных дата-центров в разных регионах обеспечат хороший компромисс. Последний инцидент ещё сильнее подтолкнул данную инициативу.
  • Мы займём более активную позицию в проверке своих предположений. GitHub быстро растёт и накопил немалую долю сложности за последнее десятилетие. Становится всё труднее уловить и передать новому поколению сотрудников исторический контекст компромиссов и принятых решений.

Организационные меры


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

Вывод


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

Комментарии (26)


  1. robert_ayrapetyan
    31.10.2018 19:18
    +1

    Кстати, никто не в курсе: сделка с MS — завершена?


    1. baldr
      31.10.2018 20:46
      +6

      Если вы пытаетесь тонко намекнуть что MS успела поменять архитектуру сети и инструментов развертывания, то, мне кажется, вы неправы. Все эти решения, похоже, были внедрены уже довольно давно.


      1. robert_ayrapetyan
        31.10.2018 20:49
        -10

        Ну что вы, конечно же не успела еще. Но каким-то необъяснимым образом им всегда достаточно самого факта приобретения.


      1. Krypt
        01.11.2018 06:27

        С неделю назад я заметил некоторые деградации в функциональности гитхаб: в частности, не работает поиск по коду в форках. Вот только не понятно, это последствие аварии или нет. Не работает до сих пор. Так что какие-то изменения всё же проводятся.


        1. Source
          01.11.2018 09:42

          А он когда-то работал? Во всяком случае, года 2 точно поиск по коду в форках не работает.


      1. igor_suhorukov
        01.11.2018 10:33
        +1

        Может это стало причиной что уволились(ли) люди, которые были в курсе как действовать в подобной ситуации, а поделиться в общую knowledge base не успели или уже не захотели. Это лишь догадки как может быть связано с поглощением MS.
        Запасаемся попкорном и ждём проблем от продуктов/ RedHat...



  1. staticlab
    31.10.2018 19:22
    +1

    GitHub опубликовал информационное сообщение в блоге. Мы сами используем GitHub Pages, и все сборки поставили на паузу несколько часов назад, поэтому публикация потребовала дополнительных усилий.

    Кажется, dogfooding здесь был не к месту.


    1. Alexsey
      01.11.2018 00:08
      +3

      Что-то мне сразу вспомнилось как AWS хостил свой Status Page у себя же. И когда пару лет назад AWS капитально упал вместе с ним слег и их Status Page.


      1. edwardspec
        01.11.2018 11:25

        Не слёг, а показывал, что всё в порядке. Т.к. список проблем хранился на S3, а сбой был в S3.
        image


  1. baldr
    31.10.2018 20:47
    +6

    Это же типичный split brain? Получается что виноват тот, кто не предусмотрел что «плановые ремонтные работы» приведут к падению сети и не обеспечил резервный канал.


    1. Hixon10
      31.10.2018 23:04

      А ещё можно поговорить про выбор MySQL для HA-хранилища. Я вообще не знаю, как там устроено в MySQL, но в случае PostgreSQL я бы только поставил на шардирование, где выход из строя одного из шардов — это всего-лишь Х%-процентная потеря на запись.


      1. miga
        01.11.2018 00:32
        +3

        Поцгрес точно так же далек от HA как и мускуль :)

        Шардирование тут никак не помогло бы, потому что вылетел не какой-то один сервер, а весь ДЦ.
        Собственно, тут есть два противоречивых требования — с одной стороны, избежать трансконтинентальной латенси и соблюдать строгую консистентность с другой стороны. Как ни крути, но всегда будет какое-то количество недоехавших до слейвов транзакций, которые так и не будут реплицированы в случае аварийной смены мастера. В принципе, есть та же Galera, можно было бы перевезти часть критичных к консистентности кластеров мускуля на нее; но опять же, это автоматом добавит RTT ко всем операциям записи.

        Я б сказал, проблема тут вот в чем:

        приложения на востоке, которые зависят от записи информации в западный кластер MySQL, в настоящее время не способны справиться с дополнительной задержкой из-за передачи большинства их вызовов БД туда и обратно

        Сразу возникает вопрос — а зачем содержать ДЦ, в который нельзя полноценно переключиться? Надо либо допиливать эти приложения, либо сделать так, чтобы приложения бежали рядом со своими данными: переключился мастер базы — балансеры переключили юзерский трафик на новое место.


        1. Hixon10
          01.11.2018 00:36

          Шардирование тут никак не помогло, потому что вылетел не какой-то один сервер, а весь ДЦ.

          Мм, а почему нельзя ключ шарда привязать к региону. Вроде бы в этом случае просто пропадет запись только в один из ДЦ, к которому был привязан данный регион.


          1. miga
            01.11.2018 00:40
            +2

            Можно, только это будет значить, что записи в этот шард пойдут на другое побережье, чему местные программы не обучены


            1. Hixon10
              01.11.2018 00:49

              Извини, я не придераюсь, просто хочу разобраться)

              Вот у нас есть ключ шардирования, который делит пользователей на:

              • User1- East
              • User2- East
              • User3- East
              • User4- West
              • User5- West


              (Ситуация очень упрощенная, ведь среди мета-данных гитхаба есть проекты, задачи и прочее, что не относится к одному пользователю).

              Пусть упал East DC. В этой ситуации пользователи User1, User2 и User3 не могут ничего записывать. А пользователи User4 и User5 — могут.

              Не очень понимаю, откуда тут появится запись в шард на другое побережье? Вижу в этом примере только чтение из реплики данных пользователей User1, User2, User3 из другого побережья.


              1. miga
                01.11.2018 01:11
                +1

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


  1. pronvit
    01.11.2018 03:29
    +3

    Странно это все. Без всяких оркестраторов у них был бы даунтайм 43 секунды. Смысл в этих наворотах, если они не выполняют единственную свою задачу? Было ли тестирование такого сценария? Почему при небольшом рассогласовании данных нет другого механизма, кроме как восстановление из бэкапа?


    1. tcapb1
      01.11.2018 07:04

      Это напомнило проблему месячной давности на Selectel. Отказ коммутатора вызвал выход кластера дисков из сбалансированного состояния. Сеть довольно скоро заработала, однако перезапуск кластера и балансировка данных заняли 12 часов, всё это время виртуалки клиентов не работали. Строим более сложные системы вроде как для более высокой надёжности, однако последствия выхода их из строя порой оказываются даже более серьёзными.


  1. Nookie-Grey
    01.11.2018 08:26

    Началось)


  1. ggo
    01.11.2018 10:22

    Жизнь всегда немного сложнее самых смелых предположений, поэтому собственно

    Эта работа включает умышленное внесение неисправностей и применение инструментов хаос-инжиниринга.


  1. namikiri
    01.11.2018 10:57
    +1

    Радует, что GitHub не отмолчался в духе «We were experiencing techincal issues», а подробно расписал что случилось и как исправили. Все бы так делали.


  1. tangro
    01.11.2018 12:24

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


  1. NiniCassini
    01.11.2018 13:49
    +2

    В такие моменты я почему-то всегда думаю о людях, которым приходится срочно, быстро и долго(как для рабочего дня) это все фиксить.


  1. GilevVyacheslav
    01.11.2018 13:49
    +1

    люблю истории где 99,999% надежность декларируется, но ни кто даже не проигрывает сценарии на практике, против которых вбухиваются огромные деньги в отказоустойчивость


  1. uhf
    01.11.2018 15:05

    Когда в восточном ДЦ между двумя узлами кратковременно пропала связь, orchestrator решил, что «шеф, всё пропало, упал primary кластер БД» — и сделал ведущим западный кластер (чего никто не ожидал, в том числе приложения). В принципе, правильно сделал, но не в этом случае. Мораль проста — не стоит полагаться на дефолтные настройки.