Pull to refresh
48
-8
Pavel Pritchin @pritchin

CTO Dodo Engineering

Send message

именно одной причины не было. если прям супер коротко, то:

  1. система не стартовала, потому что кэши базы не могли все вгрузить

  2. рассылка пушей была первопричиной, начавшей все падение

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

Тут много тем.

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

  2. В самом начале была перезагрузка базы. И была она именно потому, что мы туда ресурсов накидали. Дальше по нашему мониторингу в базе, мы не могли задетектить детально проблемы.

  3. Рестарт базы нам точно не помог. Мы фактически задестроили систему.

Он никак в итоге и не помог. Просто к моменту полного отката спал трафик. И фактически откат просто перезапустил всю систему с дефолтными настройками.

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

  1. Сам постмортем мы писали около 3х недель. 1 неделя после сбоя ушла на отработку гипотезы с "косячным" релизом, потом подбивали детали, еще гоняли нагрузку, определили проблемы с кэшом в базе. Долго переносил в статью.

  2. Ога, DBA нет. Тоже проблема. Я не написал, но мы в конце года как раз нашли именно DBA себе.

  3. Закрыли в конце декабря,

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

Старый сайт dodopizzastory открывался не очень быстро. Поэтому теперь мы его переписали на новый сайт dodobrands.io Там все побыстрее.
Тут все просто. RMQ у нас уже был к этому моменту, мы его пробовали в предрасчетах и реализации CQRS на учете. Там надо было обрабатывать расход и списания ингредиентов. Я об этом не упоминал, чтобы не усложнять. Тогда показалось, что он вполне неплох. Кафку мы не хотели дополнительно привносить, она еще тогда не была в Azure как managed service.
MySql был с самого начала, выбор в пользу массовой, простой и условно бесплатной базы. Отсюда такое странное сочетание .net + mysql.
Вопрос один, а стоит ли овчинка выделки?

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

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

Для меня они были и там и там. Монолит(а скорее единая база) сам по себе стопорил и не позволял развиваться.
Например, использование одной большой базы приводит к сложностям в обслуживании. Недавно мы перетаскивали монолитную базу в полностью managed mysql(т.е. как saas, вместо iaas) и это заняло более 6 месяцев, причем большая часть работы была по устранению различных плохо написанных и старых вещей. Когда их писали, причем, они вполне могли не быть плохо написанными.
Еще одна большая база приводила к тому, что вертикально ее масштабировать мы в какой-то момент просто не могли. Стоимость сервера была слишком большая для нас.
Сейчас монолитная база, которая остается, тоже вызывает проблемы. Происходят вынужденные даунтаймы системы из-за обслуживания при рестартах. При отдельных хранилищах у сервисов локальные даунтаймы не сказываются на работе всей системы.

Зачем в БД хранить все поля заказа в одной таблице? Что мешает разделить их по таблицам и джойнить в нужных сервисах нужные таблицы?

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

большинство проблем с БД решаются увеличением RAM на СУБД. Делается партишенинг, нужный партишен должен быть полностью в оперативной памяти

Уперлись в размеры базы. В какой-то момент стоимость следующего по мощности сервера была бы выше месячных трат на разработку в IT. Партишенинг пробовали, как раз по заказу. В MySql он не дал ожидаемого эффекта. Производительность базы не изменилась. Тогда мы сидели на 5.6, может сейчас что-то лучше стало, не могу сказать. ForeighKey тоже не использовали.
EF не было, писали запросы сами на sql и маппили их через простые мапперы.

Если у вас с десяток локальных хранилищ заказов, то нужно их синхронизировать. Чтобы их синхронизировать, нужны очереди. Очереди должны быть отказоустойчивыми с гарантией доставки

Да, в итоге так и сделали. Не сразу догадались до этого, но сейчас эта система работает надежно. Потребовала использования паттерна локальных очередей. Т.е. перед отправкой события мы его сохраняем в таблиц local_queue, а если в rmq событие не отправилось, то у нас оно прикопано в своей базе. В rmq же очереди с durable все. Есть еще механика redelivery, если подписчик не готов принять событие. Когда это все сделали, то поняли, что какая-нибудь Кафка для такого подходил лучше. Ну чтож, пока живем на RMQ.

Напоследок про облака. Находясь там мы резко снижаем проблему «нужно админить», поэтому дальше только в облаке, никакого своего железа не планируем делать.
Наверное не стоило начинать не с начала, а где-то с середины. Отсюда тема проблем не совсем раскрыта, согласен. Я постараюсь в следующих статьях эту тему объяснить более подробно.
Пока вот примерно так:
  1. Сначала была именно база редиса, она была маленькая и оттуда весь трекер считывал. Потом по надежности редис нам не подошел. Отказались от него в пользу реляционной базы.
  2. Кэш в памяти есть и используется для редко меняющихся данных, типа справочников. Данные по состоянию заказа должны быть максимально актуальны. Еще до выделения отдельной базы мы проводили работы по созданию кэшей и по выделению реплик(они были на рисунках). Это сильно помогло, но данные трекера по статусам заказа нельзя было перевести на на кэш, не обеспечив его инвалидацию. А это не тривиальная задача. При этом у нас балансировка идет на N серверов, никаких sticky session нет и не хотелось делать
В целом, отдельные хранилища и синхронизация через RMQ вполне хорошо работает. Все плюсы не буду расписывать, напишу только минусы:
  1. Работать разработчикам с этим стало сложнее. И дело не в понимании общих концепций, в в том, что все эндпойнты должны быть коммутативны и идемпотентны. Это трубует хорошей проработки взаимосвязи событий между собой. Удлинняет разработку, приводит в сложным ошибкам
  2. Избыточность хранения данных. Да, тот же Заказ хранится в нескольких базах и от этого он независим и удобен в использовании по месту. Но как только надо сделать новый сервис сразу встает вопрос про хранение этого Заказа в нем. А есть мелкие сервисы, которые даже не модифицируют особо Заказ, а просто должны его корректно отобразить, обогатив теми или иными данными. Это приводит к созданию хранилищ, в дополнительным тратам времени и денег на них.
  3. Локальные проблемы: использование RMQ не позволит масштабироваться по количеству подписчиков и паблишеров. При росте этого количества, надо будет больше мощности. Redis в Azure оказался проблемным и мы его теперь не используем. Это скорее конкретные сервисы и тулы, не особо влияющие на архитектуру

Получается хорошо юнит-тестировать при использовании высокоуровневых языков. И та часть инфраструктуры, которая сервисы имеет такие тесты. Но большая часть есть конфигурация или ее разновидности(DSL, templaters), а это не удается проверить качественно тестами. Мы не особо пробовали, но выглядит как много работы при малом выхлопе.
Например, нам надо иметь кол на jsonnet, который генерит терраформ-конфигурацию. Это для поддержки параметров и множества окружений. Там поднимается машинка, в ней при старте выполняется скрипт, который подтягивает скрипты инициализации(скрипт протестирован). И еще при старте начинают работать демоны на машине.
Вот это все проверяется поднятием реального ресурса. Т.е. это интеграционный тест.

Спасибо. Но отчаяния-то и нет. То, что описано выше работает и помогает. А дальше только пробовать еще и еще

Изначально в группу обучения вступили все равно те разработчики, кто занимался близкой тематикой последнее время. К примеру я до этого 2 года занимался так или иначе техническими задачами, а они непременно связаны. Остальные примерно так же.
Еще участие добровольное и те, кто не захотят остаться в инфраструктуре могут выйти.
Плюс прорекламирую непосредственно доклад на эту тему еще от одного члена команды. devopsconf.io/moscow/2019/abstracts/5575
Спасибо! В итоге мы стали писать тесты, поднимающие отдельный терраформ модуль, проверяющие, что там все поднялось корректно и все данные на машине прошли. Мы стали использовать питон, т.к. на нем пишутся скрипты-склейки, так что он уже был в части инфраструктуры.
И пока полет нормальный. Вот что прям не вызывает проблем — так это тесты на питоне и сам питон
Я еще пойму, что риски работы в России накладывают определенные ограничения

Такой риск существует и это одна из причин.
Также, как я уже говорил, часть функций находится в других облаках. Например, на google functions у нас бот для ScaleFT или бот, создающий карточки при инциденте.
Еще один риск — это ценовая политика. Деньги в клауде могут улететь очень быстро, а цены могут отличаться в разы.
т.е. непосредственно тебе идут оповещения от системы мониторинга?

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

Разработчик в команде инфраструктуры должен дежурить, быть на пейджере. Есть расписание, есть процесс дневных вечерних дежурств. Кстати, можно было бы и рассказать про то, как это подробно работает.
Обычные разработчики не дежурят(за исключением некоторых праздников).
Тут скорее про то, что вот есть разработчики(мы) и нас надо подготовить к дежурствам в инфраструктуре, в которых мы не знаем как вести себя, не обладаем изначально нужными знаниями.
При дежурствах ты становишься уже первой линией, должен первым реагировать на инциденты и если необходимо, то уже подключать аналитиков или непосредственно разработчиков, которые и ответственны за сервис.
Мы изначально выбирали именно решение с возможностью работы с несколькими cloud providers. Есть у нас сервисы не только в ажуре, причем в основном именно наши, инфраструктурные.
Про поддержку плагинов — мы частично используем плагин от Jetbrains и соответственно Rider.

Information

Rating
Does not participate
Works in
Date of birth
Registered
Activity