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

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

В частности, это выражается в том, что в микросервисы я выношу только большие, логически обособленные фрагменты ядра

Как то не очень вяжется с названием микросервисы. Это тогда скорее уже макросервисы.

Микро в MSA — это не про размер, а про ответственности.

VolCh ответил совершенно точно, но хочу дополнительно пояснить на примере: допустим надо писать что-то в БД, при этом данные не критичны — пересчет каких-то кешей по истории действий пользователя. Чуть раньше они пересчитаются или чуть позже — не важно. И таких процессов пересчета несколько и организовать их последовательное выполнение одним cron-ом затруднительно. По факту имеем периодически «проседающую» под нагрузкой БД. Решение в таком случае — отдельный сервис, который занимается пересчетом. А по cron-у только постановка задач этому сервису. Результат: все пересчеты идут строго последовательного по одному, БД не «напрягается».
В моей системе реализован сервис чуть более низкого уровня — «Отложенная запись в БД». Я в него отправляю непосредственно запросы. Очень маленькая по размеру, но важная по смыслу штука получилась. И эффект дает огромный.
Но при этом вот эти кэши хранятся в той же БД? Или выносятся в отдельную, привязанную к этому микросервису?
В идеале — должны храниться отдельно и заправшиваться через «обращение к внешнему сервису». На практике — поскольку с железом не богато и для всех БД все-равно один сервер используется, смысла отделять полностью не было. Хранятся в той же. Поэтому, с одной стороны, с точки зрения чистоты подхода — это не совсем внешний сервис, но с точки зрения «работает вне ядра, отдельно» — все-таки да.
Я просто не понимаю, в чем тогда выигрыш был по производительности.
По факту имеем периодически «проседающую» под нагрузкой БД

Можно было организовать такую же очередь и планировщик просто внутри монолита (вместо cron'а) и нагрузка на БД была бы такая же.
Предмет разговора — сайт на PHP. Я не нашел эффективного способа организовать очередь запросов в монолите. В приложении на C++/Delphi — запросто. А тут — нет. Как ее сделать? Эмулировать через ту же БД, записывая в нее сами запросы? Или Redis задействовать? А как выполнять? И вот продумывая варианты, я пришел к выводу, что самый простой способ и с точки зрения реализации и с точки зрения логики — просто вынести функционал записи «во вне», переложив всю организацию очереди на специализированный софт.
По производительности, вот с чем я боролся:
1. Запускается один процесс обработки данных. Он делает «тяжелые» запросы на выборку, а потом много «легких» на запись.
2. Запускается второй процесс, которому наоборот надо много выбрать и редко, но «сильно» записать.
3. Еще один процесс делает частые-частые маленькие запросы на запись. Логирует.
Что в итоге: создается значительная нагрузка на HDD сервера с СУБД. И он полностью начинает тормозить. Просто потому, что HDD с такой интенсивностью не справляется. А это сказывается на всей системе в целом.
Варианты: вложиться в железо или ограничить нагрузку. Я пошел по второму пути.
Основной вопрос насколько важна эта очередь заданий и насколько ее можно «потерять». Делать через БД как минимум дает несколько преимуществ:
  • При падении сервиса очередь останется в базе
  • Есть история и возможность просмотра и аналитики выполнения задач

Так что, можно было бы делать через БД. Если на PHP, то наверное писать cron'ом задачи в БД, а отдельным cron'ом — считывать и выполнять по очереди.
Полностью согласен с аспектом критичности данных. Поэтому все важные вещи пишутся, как раньше — сразу в БД без всяких очередей. А вот менее важные — через очередь, хотя сама по себе она обеспечивает очень хороший уровень безопасности, сохраняя данные «для сервиса» у себя локально на диск до тех пор, пока сервис не подтвердит, что он полностью все обработал.
Да, использовать посредника для записи в БД субъективно страшнова-то. Но объективно, риск в этом случае всего лишь удваивается, по сравнению с риском в варианте «пишем сразу». Тут много надо говорить, так что, наверное, напишу об этом отдельную статью потом.
Так ведь вынос хранения очереди в отдельное, специальное место — стандартное решение. Есть же всякие специально для этих целей предназначенные кролики, кафки, beanstalkd, Amazon SQS. В итоге получаем не только хранимую очередь вне зависимости от падений приложения, но и возможность легко масштабироваться добавлением воркеров работающих с этой очередью. Воркеры эти могут жить на разных машинах, причем хоть в монолите, хоть отдельно и на другом ЯП.
Все верно. В чем суть вашего вопроса? Почему просто монолит на новой ноде не подняли?
Отвечаю: чтобы поднять полноценную ноду с монолитом, надо дополнительно установить и настроить десяток утилит; при запуске монолит устанавливает кучу коннектов и производит много действий по инициализации — надо существенно его переработать, чтобы делал это не при каждом обращении, а один раз при старте; дополнительные работы по настройке обновлений; сохранение всех зависимостей монолита; многократно выше требования к железу. Это — большой пласт работ по подготовке к «run as node» + дополнительные сложности в сопровождении. Зачем? Когда можно сделать маленький сервис без лишних подключений, монструозного кода и прочих проблем.
C «копированием всего себя» хорошо работают системы, которые изначально ориентированы на подобный тип масштабирования. Моя — нет.
Поэтому вместо «возить Белазом по одному кирпичу» я сконструировал быструю «тележку с выделенной полосой движения».
Вопроса не было. Просто хотел сказать, что правильнее было бы отделить брокера очереди от воркеров. Кстати, возможно, конечно, в вашем случае есть какие то сложности с тем чтобы сделать так, но php монолит может вполне себе на той же ноде гоняться и как воркер (не подходит если нод с воркерами нужно больше, чем есть нод с приложением).

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

«Бизнес-логика в монолите». О, такие задачи уже были. И применено два типа решений — конвеер и обратное обращение. Но подробно я опишу это отдельно.
А, ясно, ну тогда ждем статьи!
сохраняя данные «для сервиса» у себя локально на диск до тех пор, пока сервис не подтвердит, что он полностью все обработал.
Да, использовать посредника для записи в БД субъективно страшнова-то. Но объективно, риск в этом случае всего лишь удваивается, по сравнению с риском в варианте «пишем сразу».

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

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

Микросервисы все таки подразумевают разделение системы на изолированные части, отвечающие за различные задачи. Так то и монолитное решение (если оно позволяет), может быть децентрализованным до тех пор, пока у вас не возникает проблем с CAP. Ну и статья с заголовком не совсем вяжется. Это скорее "Как и во что я начал переделывать централизованный монолит"

Да, смысл заголовка не совсем «склеился» с текстом. Но ничего точнее не придумалось. Зачем вообще взялся: много материалов про монолиты, много — про микросервисы. Каждый агитирует за свое. И разработчики часто (все, кого я опрашивал) начинают противопоставлять подходы. И никто не пытается взять из обоих лучшее. Хотелось обратить внимание на то, что однобокий подход, хоть и дает иногда очень хорошие результаты, но именно лишь иногда. А на практике очень часто лучший результат достигается «сбалансированной смесью» подходов и технологий.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации