Как стать автором
Обновить

История архитектуры Dodo IS: путь бэкофиса

Время на прочтение11 мин
Количество просмотров34K
Всего голосов 39: ↑34 и ↓5+29
Комментарии35

Комментарии 35

По-моему это объяснение необходимости микросервисов какое-то странное. В плане трекера вы получили бы абсолютно то же быстродействие просто используя кэш в оперативке. 5 тысяч планшетов делают обновление раз в 10 секунд, то есть 500 запросов в секунду. Это же ни о чём. Увеличив количество планшетов в 10 раз получите 5000 запросов в секунду всего-то (ну то есть с огромным запасом). Просто банальная выборка из ОЧЕНЬ маленькой базы Редиса или чего-то ещё. Где тут какие-то нагрузки вы нашли? По-моему вы или велосипед ради велосипеда написали, либо причины всё-таки другие.
Тоже очень удивился такой мотивации. И переход на микросервисы кажется надуманным. Типа, «чтобы было, потому что сейчас так модно». Еще всегда задавался вопросом: «Зачем сети пиццерий команда в почти полторы сотни разрабов?!».
НЛО прилетело и опубликовало эту надпись здесь
В плане трекера вы получили бы абсолютно то же быстродействие просто используя кэш в оперативке

Но трекер нельзя кэшировать, ему нужны самые оперативные данные

Просто банальная выборка из ОЧЕНЬ маленькой базы Редиса

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

«Редис подходит только для кэша, который вы не боитесь потерять — он не гарантирует сохранность всех данных, которые содержит. Пиццерии нельзя терять заказы и продукты в заказах. Да и в сам Редис данные должны сначала попасть :-)»
и в чём проблема? Мастер-данные храните где-угодно, по мере изменения данных делаете кэши протухшими и обновляете данные.

Кэш, даже, допустим, в 5 сек. + обновление раз в 10 сек может привести к тому, что продукт не выйдет на нужный трекер в течение 20 сек. Умножаем на кол-во планшетов в пиццерии и получаем 100 сек промедления только на стороне Dodo IS. На кухне за это время можно приготовить парочку пицц. А для пользователя это будет выглядеть как "пицца не протыкивается" — не переходит с одного планшета на другой. Кроме того, если заказ отменяют, кухне надо знать об этом максимально быстро, ччтобы лишнего не наготовить.
В комментарии ниже автор статьи говорит о том, что инвалидация кэша была нетривиальной задачей. Без разматывания клубка тут как-то сложновато.
Кэш в памяти в распределенной системе без инвалидации — отсутствие консистентности. На одной машине кэш обновился, на другой еще нет, в итоге получаем, что пицца на планшете скачет — то есть, то нет. Это очень критичная проблема для кухни.
Использование рэдиса в качестве распределенного кэша приводит к проблемам производительности. Если рэдис заэвиктит еще актуальную запись (а он это делает регулярно), снова начинаются скачки, но теперь уже лейтенси.
Но рэдис тут больше по надежности не подходит.

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

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

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

Кстати, от Редиса, который у нас используется повсеместно (на картинках в статье далеко не все уместилось), мы в последнее время отказываемся, т.к. с ним внезапно всплывает много проблем: SLA в Ажуре всего 99.9, высокая стоимость, плюс куча способов выстрелить себе в ногу, чем регулярно пользуются разработчики (например случайно засовывая туда большие объекты в перемешку с мелкими).

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

Полностью согласен. Вопрос один, а стоит ли овчинка выделки?

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

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

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

Как вы написали, любое усложнение архитектуры увеличивает требования к разработчикам и создают проблемы гораздо более высокого уровня, часть из которых решить надежно вообще сложно. Если у вас с десяток локальных хранилищ заказов, то нужно их синхронизировать. Чтобы их синхронизировать, нужны очереди. Очереди должны быть отказоустойчивыми с гарантией доставки. Т.е. вместо того, чтобы оптимизировать структуру данных в БД и переписать говнокод, вы создали кучу новых проблем, добавив в систему новых элементов, каждый из которых может отказать, которые нужно админить и с которыми также нужно уметь работать.

Ну и напоследок. Я бы для небольшой компании размещаться в облаке не стал. Мой опыт говорит, что физический инстанс БД работает минимум в 3-4 раза быстрее и есть возможность сконфигурить его под себя, например, добив оперативы до 768ГБ или поставив быстрые SSD. И да, обслуживание железных серверов будет дешевле, чем специалисты по Azure.
Вопрос один, а стоит ли овчинка выделки?

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

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

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

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

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

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

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

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

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

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

Лично мой опыт говорит, что до 2-3k RPS держит любое более-менее правильно написанное решение. Лично с MySql не работал, но MS Sql, Oracle или Postgres справляются.

Более того, масштабировать, особенно с учетом, что у Додо франшизы и облако вообще легко — крупные тинанты крутятся в своем спейсе отдельно. Данные за прошедшие периоды лишь реплицируются в основную БД.

Но даже если это и не так, то я лично работал на проекте, где в БД было больше 10 млрд. записей, и он работал. А мне кажется, что вряд ли у вас в день бывает миллион заказов?

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

Ну и напоследок. Я не знаю какие у вас представления о своем железе. Обслуживание десятка серверов, опять таки из практического опыта вам обойдется в 60 тыс рублей в месяц. Аренда сервера вида 2 × Intel Xeon Gold 6240R 2.4ГГц, 48 ядер 384 ГБ RAM 60 тыс. рублей. Azure MySql 32 ядра 320 Гб будет стоить под 200 тысяч, при этом эти 32 ядра можно смело делить на 3. Да, геморроя может и побольше, но экономия на лицо и производительность в разы выше.
Здравствуйте!
Приятно снова читать комментарии матерого архитектора! (если что, ни разу не сарказм)

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

— объем кода, завязанного на эти поля. чтобы свести таблицу до рабочего состояния надо переписать пол системы. и это при том, что большая часть разработчиков продолжает писать в ней код с бизнес-фичами. Если всех бросить на переписывание, бизнес взвоет — он не может себе позволить не делать новых фич так долго.
— Был определенный технический дедлайн, особенно на выделение трекера — к лету 2017 база перестала бы справляться, а скейлить вверх машины под ней было уже некуда. Оценка выделения сервиса из монолита более предсказуема и надежна, чем оценка рефакторинга того же монолита, поэтому сделали, что успели.
— это же не спасет от тяжелых операций — придется джойнить все ту же гигантскую таблицу с заказами на такие же по размеру таблицы с другими полями. Тут надо скорее паттерн использования полей менять, а это значит, что надо проектировать всю систему или значительную ее часть заново.
— отказоустойчивость системы — очень плохо когда слишком жирный отчет (для этого, конечно, есть АХД) или ошибка в коде какого-нибудь экрана выдачи заказов кладут мастер базу и перестает работать вся система. Если же экран выдачи заказов выделен в отдельный сервис, то его баги влияют только на него и позволяют пиццерии и дальше обрабатывать заказы. Маленькие сервисы и откатывать проще в случае проблем. Большой монолит деплоится и откатывается сильно дольше.

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

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

вместо того, чтобы оптимизировать структуру данных в БД и переписать говнокод, вы создали кучу новых проблем

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

и с которыми также нужно уметь работать.

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

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

Почему? Разве это не то же самое + накладные расходы на то, что с сервисом надо учитывать все особенности сетевого взаимодействия?

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

А где тут "сетевое взаимодействие"? Этот отдельный домен может быть модулем, а не сервисом. Если никто не знает всех нюансов, то как они потом переключат использование на сервис — там будут абсолютно те же самые проблемы что и в случае использование отдельного модуля + дополнительные проблемы связанные с сетевым взаимодействием.


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


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


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

А где тут «сетевое взаимодействие»

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


Логические проблемы будут примерно такие же

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

Это места стыковки с остальной системой. Само по себе взаимодействие клиента с сервером не изменилось.

То есть при выделении сервиса никаких новых сетевых взаимодействий не возникло?


Чтобы выделить сервис, вовсе не обязательно выковыривать код его бизнес-логики из старой системы.

Попробуйте заменить в этих рассуждениях "сервис" на "модуль" или "сборку" — получится то же самое, нет?


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


Но логически можно выделить отедльный модуль и без выделения в сервис. Кроме, того, что сетевое взаимодействие накладывает дополнительные ограничения на связанность (например, в DDD есть правило, что нельзя делать ссылки внутрь агрегатов, но, насколько я знаю, нет способа проверять это правило. В случае сервисов не получится его не соблюдать так как нельзя делать ссылок внутрь сервиса)


Я пытаюсь понять, что для вас было главным — технические проблемы или логические.


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

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


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

Оценка выделения сервиса из монолита более предсказуема и надежна, чем оценка рефакторинга того же монолита, поэтому сделали, что успели

Мой 15 летний опыт работы говорит о том, что так думают только оптимисты.

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


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

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

Тут также вопросы. Отчеты никогда не должны строится извините за расизм с мастер-реплики. Также вообще непонятно, как ошибка в коде бизнес-логики влияет на падение базы. Я вижу вариант только дедлоков, но откуда у вас гонки за ресурсами в простой как апельсин ERP?
Опять таки возвращаемся в архитектуру

в свежем стартапе на 3-5 пиццерий никто не задумывается, как это будет работать на 100 пиццериях. Отсюда проблемы с архитектурой. У монолита с архитектурой плохо, и это одна из главных проблем. Если бы первоначальные авторы системы могли придумать сходу архитектуру, рассчитанную на 600 пиццерий, то они бы не были разработчиками для маленького стартапа — таких людей только в больших корпорациях найдешь. Но даже если бы они, все же, писали ее для Федора в далеком 2011 году, они бы не успели ее в срок. Тогда скорость разработки была сильно важнее задела на будущее.

Мой 15 летний опыт работы говорит о том, что так думают только оптимисты.

А мы оптимисты! Вот как оценивать рефакторинг монолита с высокой связностью кода и кучей мест, в которых даже старожилы уже не разбираются? Может, у вас есть проверенный подход, занимающий не больше недели?

обычно используют фильтры, ограничивая выборку

Посыл был в том, что загруженность БД не принципиально меняется, если после разделения таблицы джойнить все обратно — фильтровать по 1кк заказам с 30 столбцами или фильтровать 10 табличек по 1кк строк и 3 столбцами каждая и джойнить результат друг на друга.

Также вообще непонятно, как ошибка в коде бизнес-логики влияет на падение базы

плохой запрос в базу, ошибка в политике ретраев, ддосящая базу, и да, дедлоки

Отчеты никогда не должны строится извините за расизм с мастер-реплики

да, тут разночтений нет, но отдельная БД появилась не сразу
У монолита с архитектурой плохо

Еще раз. У монолита с архитектурой все прекрасно. Плохо с архитектурой у плохого монолита. В монолите также прекрасно присутствуют сервисы, которые могут пилиться отдельными командами. В монолите никто не мешает использовать несколько источников данных и прочее. Единственное, что плохо делает монолит — это скейлится, но, повторюсь это играет роль на уровне десятков тысяч запросов в секунду.
И то, если писать нормальный код, то у меня на локальном компьютере связка .Net Core + EF Core держала под 10к запросов. А с учетом того, что в нормальном проде надо бы сервера 4, то 20-30к запросов вполне достижимо.

Посыл был в том, что загруженность БД не принципиально меняется, если после разделения таблицы джойнить все обратно — фильтровать по 1кк заказам с 30 столбцами или фильтровать 10 табличек по 1кк строк и 3 столбцами каждая и джойнить результат друг на друга.


Вы не совсем правы. Наймите себе DBD/DBA, он вам поможет. Серьезно.
Если кратко. Наивысшая производительность — когда вся таблица в памяти. Очень сложно запихивать в память таблицы с кучей столбцов, которые редко используются. Особенно, если там еще и варчары. Соответственно данные делятся. Часто используемые остаются в основной таблице. Редко используемые — выносятся в свои таблицы. В результате эти дополнительные данные будут джойнится редко и в самый последний момент. Более того, 1кк записей не в отчетах — это ахтунг. Если такое нужно в логике (непонятно зачем), то это не должно покидать СУБД, иначе невозможно говорить о производительности вообще.
Может быть у вас еще и SELECT * используется?

плохой запрос в базу

Как может быть плохой запрос в базу, если он зашит в систему? Или у вас можно было дать доступ для аналитики в боевой инстанс?
Единственное, что плохо делает монолит — это скейлится

Причем в данном случае масштабируется довольно хорошо — под каждую пиццерию выделенная виртуалка с копией монолита. Тем самым решается куча вопросов:
  • Отказоустойчивость — упавшая одна виртуалка никак не влияет на все остальные 599
  • Надежность — все обращения в рамках одного «физического» компьютера, нет обращений по сети. Опционально можно разве что разбить сервер-приложений и сервер-БД
  • Распределение нагрузки — думаю такой выделенный монолит легко выдержит нагрузку с одной пиццерии
  • Своего рода CDN — для Владивостока виртуалка поднимается в дата центре во Владивостоке
  • Тестировать обновления — можно только на одной машине, опять же все остальные спокойно работают
  • Можно вообще подумать в сторону копии в самой пиццерии с синхронизацией в облако — тогда отсутствие интернета не застопорит работу пиццерии. Но тут конечно больше вопросов, чем ответов
  • Можно даже распределить финансовые затраты — стоимость аренды сервера вешается на пиццерию


Проблем сходу видно три:
  • Пользователи — должны иметь сквозной идентификатор, потому что один и тот же человек может приехать в другой город и заказать пиццу там — вот для них надо выделить общую базу
  • Консолидированные отчеты по всем пиццериям — но тут достаточно сливать все данные из всех мастеров в одну отдельную БД с такой же структурой и поменять строку подключения в админке
  • Обновление всех этих монолитов, но с микросервисами такая же фигня
1. Это очень дорого. 600 виртуалок с полноценной системой, пусть даже маленьких, против 3-4 пожирнее сейчас.
2. Как вписать в вашу модель сайт и мобильное приложение, раз уж всё — один сплошной монолит?
3. Конкретно в нашем случае система не сможет так работать, под это надо затачивать
4. Чисто по бизнес-логике многими настройками пиццерии заведует Управляющая Компания централизованно, а если делить настройки, то постоянно придется тасовать их туда-сюда — накладно в разработке
5. Сейчас при ошибках в релизе или от падения мы можем руками быстренько подхачить данные сразу во всех пострадавших пиццериях. Если будет по виртуалке на пиццерию, это превратится в неподъемную задачу.
6. Ну очень долгий релиз, да к тому же с даунтаймом (если по одной виртуалке на пиццерию).
7. Обслуживать такое кол-во виртуалок надо уметь. Мы пока не готовы.

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

У нас проблемы очень редко связаны с сетью, чаще с БД или ресурсами на самой виртуалке. К тому же сеть останется, бэкэнд же не прямо на планшете загружен — за ним еще по сети сходить надо.
У монолита с архитектурой все прекрасно

Это у нашего монолита все плохо, а не у у монолита как класса

Наивысшая производительность — когда вся таблица в памяти

Это возможно реализовать с managed базами? Что-то мне подсказывает, что не будет нужного уровня управляемости…

Как может быть плохой запрос в базу, если он зашит в систему

Ошибка разработчика — не учел размеры таблицы, индексы, в назании поля ошибся, да мало ли что — Со всяким бывает.

Или у вас можно было дать доступ для аналитики в боевой инстанс

До разделения базы на мастер, рид и АХД и такое бывало. Но это не относится к вопросу разделения на сервисы
Еще раз повторю, Azure это для либо маленьких компаний, с платой 30 баксов в месяц, либо для очень больших, для которых 100к баксов в месяц лишних на сервера — не деньги.

В случае средних компаний нет никакого смысла иметь облако. Нет таких нагрузок, где нужно масштабирование уровня поднять быстро 100 инстансов. А переплата гигантская, на более-менее вменяемых инстансах переплата будет раз в 10-15. А экономии нет, так как человек с хорошими знаниями Azure стоит дороже чем админы на аутсорсе (ну или свой в штате).

Если уж совсем хотите заморочиться — ну поднимите себе HyperV Server и устройте себе свое облако.

а почему именно выбрали RabbitMQ и MySQL?
Тут все просто. RMQ у нас уже был к этому моменту, мы его пробовали в предрасчетах и реализации CQRS на учете. Там надо было обрабатывать расход и списания ингредиентов. Я об этом не упоминал, чтобы не усложнять. Тогда показалось, что он вполне неплох. Кафку мы не хотели дополнительно привносить, она еще тогда не была в Azure как managed service.
MySql был с самого начала, выбор в пользу массовой, простой и условно бесплатной базы. Отсюда такое странное сочетание .net + mysql.
Я конечно не знаю, как сейчас живет MySql, но мой опыт говорит, что в более-менее нагруженных проектах MySql ломается чаще, чем работает.
а ZeroMQ и PostgreSQL не пробовали?
Расскажите какие железки под базы данных сейчас выделены.
И если не секрет, какой примерно объем данных в целом.
Очень интересно, огромное спасибо за материал.

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


Не очень понятна роль (1) здесь. Все равно мимо (2) не пройти — ну так сразу и посылать туда куку.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий