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



В последние годы микросервисы стали очень популярной темой. «Микросервисное безумие» выглядит примерно так:

«Netflix хороши в DevOps. Netflix делают микросервисы. Таким образом, если я делаю микросервисы, я хорош в DevOps».

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

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

Что такое микросервисы и почему они так популярны?


Начнём с основ. Вот пример возможной реализации гипотетической платформы шаринга видео: сначала в монолитном представлении (один большой блок), а затем — в микросервисном.



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

Когда схема представлена на таком уровне детализации, легко увидеть её привлекательность. Тут целый набор из потенциальных плюсов:

Независимая разработка. Маленькие независимые компоненты могут создаваться маленькими независимыми командами. Группа может работать над изменениями в сервисе Upload, не затрагивая сервис Transcode и даже не зная о нём. Объём времени, необходимого для изучения компонента, значительно снижается, и разрабатывать новые функции становится проще.

Независимое развёртывание. Каждый отдельный компонент можно деплоить независимо. Это позволяет выпускать новые фичи быстро и с меньшими рисками. Исправления или фичи для компонента Streaming можно деплоить без необходимости в деплое других компонентов.

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

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

На таком уровне детализации преимущества микросервисной модели над монолитной кажутся очевидными. Если всё так, то почему паттерн вошёл в моду только теперь? Где же он был всю мою жизнь?

Если всё так здорово, то почему никто так не делал раньше?


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

Когда я начал подготовку ответа на этот вопрос, получилось длинное описание, поэтому лучше выделю его в отдельную статью и опубликую её чуть позже. Здесь же будут опущены путь от одной программы ко множеству, ESB (enterprise service bus, т.е. «сервисная шина предприятия» — прим. перев.) и SOA (service-oriented architecture, т.е. «сервис-ориентированная архитектура» — прим. перев.), проектирование компонентов и bounded contexts («ограниченный контекст» — паттерн из Domain-Driven Design — прим. перев.) и т.п.

Вместо всего этого напишу, что во многих смыслах мы уже делали всё это некоторое время, но только с недавним взрывным ростом контейнерных технологий (в особенности — Docker) и технологий оркестровки (таких, как Kubernetes, Mesos, Consul и др.) паттерн стал гораздо более целесообразным в реализации с технической точки зрения.

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

В чём проблема микросервисов?


Если микросервисы так прекрасны, в чём дело? Вот некоторые из самых значимых проблем, что мне довелось увидеть.

Возросшая сложность для разработчиков


Жизнь разработчиков может стать значительно тяжелее. Если разработчик захочет поработать над фичей, затрагивающей множество сервисов [journey], ему придётся запускать все их на своей машине и подключаться к ним. Зачастую это сложнее, чем просто запустить одну программу.

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

Возросшая сложность для эксплуатации


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

Возросшая сложность для DevOps


Глядя на два предыдущих пункта, может показаться ­— особенно из-за популярности DevOps как практики (большим сторонником которой я являюсь), — что эксплуатация и разработка рассматриваются отдельно. Так вот не становится ли всё лучше благодаря DevOps?

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

Для организаций, уже применяющих DevOps, всё тоже не так просто. Быть одновременно и разработчиком, и сисадмином уже тяжело (но критично для создания хорошего программного обеспечения), а с необходимостью также понимать нюансы систем оркестровки контейнеров и в особенности систем, которые стремительно развиваются, ещё тяжелее. Так я прихожу к следующему пункту.

Необходима серьёзная компетентность


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

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

Реальные системы обычно не имеют чётко определённых границ


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

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

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

Сложности stateful часто игнорируются


В предыдущем примере упомянута иногда возникающая необходимость одновременного выката множества версий множества сервисов при деплое фичи. Хочется сказать, что продуманные техники деплоя облегчат жизнь: например, сине-зелёный деплой [blue/green deployments] (требуют минимальных усилий в большинстве платформ для оркестровки сервисов) или параллельный запуск множества версий сервиса с возможностью выбора подходящей на стороне их пользователя.

Эти техники устраняют многие препятствия, если сервисы — stateless. Но работать со stateless-сервисами вообще-то довольно просто. Собственно, если у вас stateless-сервисы, рекомендую подумать о том, чтобы пропустить все эти микросервисы и использовать модель serverless.

В реальности же многим сервисам требуется хранить состояние [state]. Примером для платформы шаринга видео может служить услуга подписки. Пусть новая версия сервиса подписки хранит данные в БД нового вида. Если оба сервиса запущены в параллель, то у вас система, одновременно использующая две схемы. Если вы делаете сине-зелёный деплой, а другие сервисы зависят от данных в новом виде, их необходимо обновить в то же самое время. Если деплой сервиса подписки прошёл неудачно и откатывается, то скорее всего необходимо откатить и эти сервисы тоже, и далее «по каскаду».

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

Сложности взаимодействия часто игнорируются


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

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

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

Когда в микросервисной системе используются очереди сообщений для межсервисного взаимодействия, у вас по сути работает большая база данных (очередь сообщений или брокер), склеивающая все сервисы. Опять же, хоть всё это поначалу и не кажется проблемой, схема догонит вас и напомнит о себе. Сервис версии X может писать сообщения в определённом формате, поэтому сервисы, зависящие от такого сообщения, тоже необходимо обновить, когда сервис-отправитель меняет что-то в своём сообщении.

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

Этим снова подтверждается мысль, что, если вдаваться в детали, то независимые развёртывания не всегда работают, как предполагалось.

Версионность может быть сложной


Для преодоления упомянутых препятствий необходимо очень осторожно управлять версиями. Опять же, есть тенденция полагать, что следование стандарту вроде semver решит проблему. Это не так. Semver — соглашение, которое целесообразно использовать, но вам всё равно придётся следить за версиями сервисов и API, которые могут взаимодействовать.

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

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

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

Распределённые транзакции


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

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

Микросервисы могут быть замаскированными монолитами


Да, отдельные сервисы и компоненты могут деплоиться изолированно, однако в большинстве случаев будет запускаться какая-то платформа для оркестровки вроде Kubernetes. Если же вы пользуетесь управляемым сервисом вроде GKE от Google или EKS от Amazon, большая часть сложностей управления кластером решена за вас.

Однако, если вы сами управляете кластером, то работаете с большой, сложной и критически важной системой. Хоть у отдельных сервисов и могут быть все преимущества, описанные выше, необходимо очень вдумчиво управлять кластером. Развёртывание такой системы может быть сложным, обновления — сложными, failover — сложным и т.п.

Во многих случаях общие преимущества остаются, однако важно не упрощать и не недооценивать дополнительную сложность, вызванную управлением ещё одной большой и сложной системой. Управляемые сервисы способны помочь, но зачастую они слишком молоды (например, Amazon EKS был анонсирован лишь в конце 2017 года).

Смерть микросервисного безумия!


Избегайте безумия, принимая осмотрительные и обдуманные решения. А в помощь для этого я подготовил несколько вопросов, которые вы можете задать себе, и пояснений к ответам на них. Прим. перев.: оригинальное изображение-схема переведено и представлено в текстовом виде ниже.

1. Размер команды


Можно ли усадить всю вашу команду за один большой стол?

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

2. Stateless/stateful


Ваша система является преимущественно stateless?

  • Да! Рассмотрите serverless. Если ваша система в основном stateless, вероятно, вы можете пропустить этап микросервисов и сразу перейти к serverless — по крайней мере, частично.
  • Нет! Микросервисы принесут сложности. Это не означает, что использовать микросервисы не стоит, но помните, что непросто их реализовать и ими управлять — особенно из-за того, что система со временем меняется.

3. «Пользователи» системы


Вы собираете решение для одного приложения или сервиса?

  • Да! Будьте осторожны — могут встречаться «размытые» предметные области. Если всё, что вы собираете, предназначено одному и тому же приложению-пользователю, может выясниться, что сборка фич потребует одновременного обновления множества сервисов. Микросервисы могут быть уместны, однако будьте очень осторожны с проектированием предметных областей.
  • Нет! Микросервисы могут оказаться очень полезными. Если вы проектируете систему, которой будут пользоваться разные приложения, микросервисы могут оказаться очень уместным паттерном, чтобы быстро доставлять новые фичи новым приложениям-«пользователям».

4. Зависимости


У вас есть монолитные зависимости?

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

5. Компетентность


Есть ли у вас эксперты по контейнерам, оркестровке, DevOps?

  • Да! Микросервисы могут оказаться очень полезными. При наличии соответствующих кадров стоит изучить микросервисы. Имеющиеся навыки позволят разобраться с потенциальными трудностями и воспользоваться преимуществами.
  • Нет! Сначала прощупайте почву! При отсутствии должной компетентности или в случае уже имеющихся трудностях с DevOps вы можете прыгнуть выше головы. Рассмотрите возможность адаптации одного простого сервиса в качестве доказательства концепции. Получите первый нужный опыт на проектах, которые не являются критичными для бизнеса.

Скачать оригинальный PDF со всеми вопросами-ответами (на английском языке) можно здесь.

Последние мысли: не путайте микросервисы с архитектурой


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

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

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

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

P.S. от переводчика


Читайте также в нашем блоге:

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


  1. acmnu
    29.01.2018 10:04

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


    • Версионность API. Да проблемы переходного периода довольно сложны. Но нужно учитывать несколько правил. Во-первых, в системе не может быть больше одной версии запущенного софта на постоянной основе (две версии только в момент обновления/черрипиков). Во-вторых, если в API добавилась новая функция, то сначала полностью обновляется сервис предоставляющий API и только потом обновляются клиенты. В-третьих, разумеется обратная совместимость и тестирование регрессий.
    • Statefull проблемы в соответствующей литературе описаны. Да, они тоже сложны. Но пример написанный в статье мне просто не понятен. Что значит "новая версия сервиса подписки хранит данные в БД нового вида"? Если там на столько разрушительное изменение, то только полная остановка, как и в монолите.

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

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


    1. Skerrigan
      29.01.2018 10:24

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

      Вот сам этого не умел, однако как усилилась разработка вплотную с драйверами под браузеры и платформа (Automated System for Tests) приобрела свой первый «сервер инстансов» на базе Jersey glassfish, так очень быстро усвоил уроки жизни.


      1. acmnu
        29.01.2018 10:42

        Тут же не вопрос "не умел", а в том, что многие "не хотят".


        1. Skerrigan
          29.01.2018 10:50

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

          P.S. Изначально, когда только все стартовало, AST не несла такой важной роли — сейчас ответственность и критичность резко возросла. И сложность софта так же стала совсем иной.


    1. SirEdvin
      29.01.2018 10:35

      большинство проблем описанных связаны с низким качеством разработки

      Я думаю, это в целом подходит всей IT сфере)


      1. acmnu
        29.01.2018 10:46

        Ну в общем да. Но мысль в том, что команды уже умеющие работать правильно внезапно имеют тенденцию дрейфовать в сторону микросервисов (разумеется не всегда). А те, кто до сих пор даже пользу тестирования не понимает, пытаются сделать "как в Netflix" и естественно проваливаются.


        1. aGGre55or
          29.01.2018 11:29

          работать правильно — это уже настолько неконкретная формулировка, что выводить из неё истории успеха представляется затруднительным.


          1. acmnu
            29.01.2018 12:16

            Ну да, размыто. Но микросервисы не работают как минимум без регрес тестирования API и без людей которые умеют проектировать сложные системы.


    1. kozzztik
      29.01.2018 14:21

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


    1. VolCh
      29.01.2018 17:16

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


    1. andrey_ps
      30.01.2018 06:25

      Statefull проблемы в соответствующей литературе описаны.

      А можете порекомендовать что почитать для перехода на SOA?


      1. acmnu
        30.01.2018 11:03

        Эм. Ну вообще-то микросервисы != SOA. SOA более общая концепция. Это очень важно понять. И книг именно по SOA я не читал, а вот если нужно введение в микросервисы, то хорошая книга есть у O'Reilly: Building Microservice автор Sam Numan. Издательство Питер делало перевод. Там не обсуждаются частности, а скорее модели взаимодействия. Много обсуждают как разорвать связи в монолитной базе и надо ли это делать вообще.


        1. andreycha
          30.01.2018 12:33

          Не читайте перевод от «Питера». Он ужасен и изобилует ошибками.


        1. andrey_ps
          30.01.2018 13:22

          Хм, я, признаться, думал, что одно строится на другом. То есть сначала изучаются более базовые вещи, которые диктует SOA, а потом просто уже адаптируем какие-то конкретные аспекты под микросервисы.


          1. acmnu
            30.01.2018 13:25

            Сложно сказать. Это же очень расплывчатые понятия. Как ООП, например.


          1. VolCh
            30.01.2018 14:31

            Можно с любой стороны связки SOA-MSA начинать.


  1. kkirsanov2
    29.01.2018 10:40

    > Если разработчик захочет поработать над фичей, затрагивающей множество сервисов [journey], ему придётся запускать все их на своей машине и подключаться к ним. Зачастую это сложнее, чем просто запустить одну программу.

    У меня прямо противоположный опыт. Запустить монолит такая сложная история что виртуалка, передаваемая от одного поколения другому, ценится как артефакт из фентези.

    В то время как микросервисы с docker-compose и четко очерченным avro-схемами API разворачиваются довольно просто. А т.к. микросервисы взаимодействуют между собой только через кафку (есть особые исключения, но это другая история) — то запускать их можно последовательно (по пути на графе) по одному.


    1. acmnu
      29.01.2018 10:43

      А т.к. микросервисы взаимодействуют между собой только через кафку

      А подробнее об опыте работы через кафку можете рассказать? Как устойчивость, какие подводные камни?


      1. kkirsanov2
        29.01.2018 11:18

        Я думал про это отдельно написать в Хабр.

        Если коротко:

        0) По производительности и надежности наши потребности перекрываются многократно.

        1) Кафка передает байтики, схему нужно делать самостоятельно. Мы делаем вот так — habrahabr.ru/post/346698

        2) Кафка pub-sub, и вопросы повторов нужно решать с особой щепетильностью.
        Если есть цепочка на графе процесса вида: A->B и A->C и в С произошёл сбой, тогда нельзя так просто повторить сообщение из А, т.к. его поймают и B и С.
        Вариантов борьбы — масса, начиная с проверкой уникальности и заканчивая внутр. очередями.

        Мы сейчас выбрали такую стратегию — обработка очереди приостанавливается до решения проблемы. Но это потребовало ввести классификацию ошибок на требующие остановки и не требующие.

        3) Кафка отдельно хранит поток данных и отдельно — позицию читателя на этом потоке. Так же у читателя есть стратегия чтения в случае, если он не знает откуда читать. Он может начать с новых данных (конец потока), а может со старых (начало).

        Мы как то увеличили время жизни данных до недели, а время жизни информации о позиции — нет, при этом несколько разрабатываемых читателей были настроены на чтение с начала. В результате переукладки в докер\номад они **заново** обработали недельный массив данных.

        4) У нас получился граф с циклами, в узлах которого сервисы, а ребра — кафочные топики.
        Чтобы как то восстановить путь сообщения я при прохождении каждого узла дописываю в сообщениях метаинформацию о локальном времени прохода и uuid процесса в данном узле. В результате на конечном узле можно понять в результате каких процессов это сообщение вообще сюда пришло, и как долго оно шло.


        1. acmnu
          30.01.2018 11:06

          Я думал про это отдельно написать в Хабр.

          Это было бы неплохо. По Кафке вообще мало хороших историй, не синтетических.


          Кафка pub-sub, и вопросы повторов нужно решать с особой щепетильностью.

          Во-во. Именно такие проблемы и вызывают интерес. А то многие воспринимают такие вещи как магические коробки, которые все, всегда делают правильно.


    1. mayorovp
      29.01.2018 10:43

      Запустить монолит такая сложная история что виртуалка, передаваемая от одного поколения другому, ценится как артефакт из фентези.

      Да, бывает такое. Но эта проблема обычно связана не с монолитами, а со сторонним ПО. Если разбить подобный монолит на микросервисы — то наверняка появится 2-3 "артефакта", по количеству стороннего ПО.


    1. kozzztik
      29.01.2018 14:24

      Кто мешает запилить docker-compose для монолита? Да и можно включать отключать компоненты через конфиг, дело вроде не хитрое.


      1. kkirsanov2
        30.01.2018 09:46

        То что dokcer-compose решит лишь одну проблему из десятка.

        За 10 лет бизнес сильно поменялся, а ядро нет. Так что всё равно нужно переделывать практически всё, исходя из новых реалий.


    1. commanderxo
      29.01.2018 19:57

      В то время как микросервисы с docker-compose и четко очерченным avro-схемами API разворачиваются довольно просто.

      Использование докера намекает, что новой красивой системе всего года три-четыре от роду, так что нужно помнить, что:
      1. Через 15 лет докер вполне может стать дремучим legacy, к которому не притронется ни один хипстер, а ваша система ещё будет жить (мы ведь рассуждаем об удавшихся, а не провальных проектах)
      2. Легко написать первую версию новой системы, да и вторую нетрудно. На любом языке, да хоть на Фортране. Сложности начинаются когда система становится успешной, на ней основываются основные процессы предприятия, и к вам приходят с предложением «чуть-чуть подправить» функциональность чтоб получить ещё больще прибыли. И так 30 раз в течение десяти лет, причём приходят разные люди из разных отделов, да и у вас уже два раза сменился состав команды.
      3. Сложные проблемы требуют сложных решений — всё простое уже было автоматизировано в прошлом веке. В микросервисах сложность прячется в конфигах и схемах взаимодействий между сервисами, особенно при реакции на ошибки и нестандартные ситуации.

      Кто знает, может в 2030 году будут передаваться от одного поколения к другому магические скрипты на экзотическом к тому времени DSL, которые как-то связывают зоопарк сервисов в нечто рабочее.


      1. Paskin
        30.01.2018 00:03

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


        1. SPAHI4
          30.01.2018 02:04

          Для этого есть специальные ос, в которых все по-минимуму.
          Например, alphine.


        1. wmns
          30.01.2018 06:25

          Путаете с виртуализацией. Docker использует ядро хостовой системы.


        1. Ksoo
          30.01.2018 06:25

          Докер это не виртуализация, накладные расходы на контейнер минимальны.


          1. Regis
            30.01.2018 12:28

            Справедливости ради нужно отметить, что эти расходы минимальны пока вы не начинаете делать очень активное IO. При очень высоком IO докер может добавлять прилично дополнительных расходов.


        1. VolCh
          30.01.2018 12:39

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


      1. kkirsanov2
        30.01.2018 09:42

        > 1) Через 15 лет докер вполне может стать дремучим legacy,
        > а так же 2 и 3

        Увы, но это применимо ко всему. У нас тут государсва очертания чаще меняют.
        Через 15 лет вообще всё что угодно будет, начиная от массового MIPS вместо X86 и кончая втрожением инопланетян.

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


  1. vba
    29.01.2018 11:22

    В заметке от переводчика говорится что это опытный разработчик, у меня возникли в этом сомнения так как неоднократно в статье речь заходила о stateful и distributed transaction. Хотя можно наверное быть опытным и любить боль.


    1. SirEdvin
      29.01.2018 11:53

      А вы где-то видели большие приложения без состояния?)


      1. vba
        29.01.2018 12:17
        +1

        В самом начале статьи автор говорит про Netflix. Которые вовсю проповедуют stateless. Таких примеров достаточно много.


        1. SirEdvin
          29.01.2018 12:50
          -1

          Ну вот не знаю, мой аккаунт как-то хранится в netflix, какой тут stateless? То, что какие-то компоненты не имеют локального состояния не означает, что у всей системы нет состояния. И так же не означает, что stateless приложения всегда легко деплоить, особенно если кто-то поменял формат хранения состояния.

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


          1. vba
            29.01.2018 13:04

            То что вы описываете есть результат какой то обработки, если у вас есть хранилище данных то это не значит что вы храните состояние между этапами вашего бизнес процесса. Вот например понятие stateless protocol если ваш http сервер ведет логи запросов, от этого протокол HTTP не перестает быть stateless.


            1. SirEdvin
              29.01.2018 14:30

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

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


              1. myrkoxx
                29.01.2018 14:35

                У вас как минимум есть сессия пользователя


                Есть техники позволяющие не хранить сессию на стороне сервера. Недавно читал, как сесии хранят в Json Web Token. Думаю далеко не один способ существует для организации чистого stateless


                1. SirEdvin
                  29.01.2018 14:48

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


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


                  1. vba
                    29.01.2018 15:27

                    Если вы увидели идентификатор сессии в ваших куках, это ничего не значит. Сессии на сервере могут водится из-за конфига по умолчанию, не отключенного в свое время. Для идентификации клиента и контроля его доступа к ресурсам существуют различные стандарты, например OAuth. И ничего лишнего на клиенте не хранится. Да в каждом запросе вы передаете токен и что с того? Если говорить об организации приложений в SPA то тут все ясно, по определению вам никакие сессии не нужны.


                    Я не вижу, и тут я согласен с сообществом, никакого риска использования stateless. Мне кажется что вы не до конца осознаете что есть сервис без состояния.


                    1. SirEdvin
                      29.01.2018 15:47

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


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


                      1. vba
                        29.01.2018 15:54

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


                        1. SirEdvin
                          29.01.2018 16:04
                          -1

                          Простите, но вот тут вы не правы, по крайне мере, если мы говорим о stateless приложениях в том виде, в которым их требует docker, оркестрация и, как я понимаю, автор.

                          Если приложение хранит какую-то информацию в себе (базы данных, картинки, отчеты) — оно stateful, потому что не может быть просто так развернуты где угодно.

                          Возможно, я не прав, но на примере Netflix, вам все равно нужно хранить где-то информацию о моих правах доступа, или хранить какую-то информацию, из которой вы можете получить информацию по мои права доступа. Я не прав?


                          1. vba
                            29.01.2018 16:19

                            Мы здесь говорим не о dataless a о stateless, в первую очередь сервисах, а потом уже и о приложениях.


                            Если приложение хранит какую-то информацию в себе (базы данных, картинки, отчеты) — оно stateful

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


                            Что для вас есть stateful?


                            1. SirEdvin
                              29.01.2018 16:24

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

                              Скажем, сервис, который в любых условиях (если он работает корректно) по ссылке cute.service.com/t1?t2=t2 выдает один и тот же ответ — stateless.
                              А если вы добавите сюда, допустим, хедер авторизации и список пользователей с паролями в файлике, который можно будет менять и это будет влиять на ответы сервиса — он уже stateful.

                              Я не прав?


                              1. vba
                                29.01.2018 16:41
                                +1

                                Нет тут вы не правы. Вы путаете концепцию чистых и не чистых функций с концепцией stateful/stateless. Вот тут есть доходчивое объяснение обоих понятий.


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


                                Так вот понятие stateless это и есть полная и желаемая амнезия вашего сервиса, где при каждом обращении вы должны ему напомнить кто вы и каков ваш контекст. Для облегчения этого дела есть фильтры или цепочки обработки запроса, но в целом это так.


                                1. SirEdvin
                                  29.01.2018 16:52

                                  Возможно, вы правы, но в конечном итоге у вас все равно будет в системе stateful сервис.

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


                                  1. vba
                                    29.01.2018 17:02

                                    Возможно, вы правы, но в конечном итоге у вас все равно будет в системе stateful сервис.

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


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

                                    Если не вдаваться в подробности EventSourcing то вы не храните состояния в БД, вы храните бизнес данные. Если вы используете БД как хранилище сессий то вы stateful.


                                    1. SirEdvin
                                      29.01.2018 17:08
                                      -2

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


                                      Если не вдаваться в подробности EventSourcing то вы не храните состояния в БД, вы храните бизнес данные. Если вы используете БД как хранилище сессий то вы stateful.

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


                                      К сожалению, по "Asynchronous Web" гуглиться в основном именно асинхронная работа, которая никак не связана с тем, есть сессии или нет.


                                      1. mayorovp
                                        29.01.2018 17:09

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

                                        Подписанный токен, включающий срок действия, который передается с каждым запросом.


                                        1. SirEdvin
                                          29.01.2018 17:21

                                          Ну, то есть хранить все на клиенте и надеяться на силу своей криптографии? Ну такое, практика показывается что это всегда плохо.

                                          А если надо сверять токен с чем-то в базе, опять же получается что состояние есть в базе.


                                          1. vba
                                            29.01.2018 17:28

                                            Ну, то есть хранить все на клиенте и надеяться на силу своей криптографии

                                            Клиенту передается лишь временный токен. И да in cryptography we trust. В базе нет состояния, в базе есть информация о токене. И это не stateful, вы статью внимательно читали?


                                            1. SirEdvin
                                              29.01.2018 17:32

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


                                              А если вы сверяете информацию о токене с записью в базе данных, то это уже состояние. Или я не прав?


                                              1. vba
                                                29.01.2018 17:36

                                                А если вы сверяете информацию о токене с записью в базе данных, то это уже состояние. Или я не прав?

                                                Нет вы не правы, это не stateful.


                                          1. mayorovp
                                            29.01.2018 21:07

                                            Ну такое, практика показывается что это всегда плохо.

                                            А можно примеры, когда именно криптография подвела?


                                            1. SirEdvin
                                              29.01.2018 23:52

                                              Вам конкретно при клиентском хранении или вообще? Для вообще есть вот такие штуки, которые меня довольно пугают.


                                    1. VolCh
                                      29.01.2018 17:53

                                      По-моему вы путаете stateless API и stateless сервис. Statefull сервис может обладать stateless интерфейсом. Вы можете делать запросы к нему, содержащие всю информацию необходимую для исполнения, с помощью того же jwt, но результат будет зависеть от начального состояния и всех предыдущих запросов. Не ваших, может быть, но всех изменивших состояние интересующего вас ресурса, если говорить о REST-like API.

                                      Классический пример: REST-like веб-сервис, состоящий из nginx, php-fpm и mysql. Если серверные сессии не используется хоть в каком-то виде, то у вас stateless API, если используются для, например, аутентификации, то у вас statefull API, но в обоих случаях у вас statefull сервис, вы не можете развернуть его на других серверах без потери или переноса данных. Может быть stateless nginx, может быть stateless php-fpm, но mysql stateful (даже не по API, а по своей сути, по своему назначению), а значит и весь сервис в целом statefull, хотя API у него может быть stateless, и сервер или контейнер с nginx и php-fpm могут быть развёрнуты с нуля за минуты, а то и секунды в новом окружении. Но вот базу надо будет переносить, без базы это будет уже новый сервис, а перенесенный старый.


                                      1. vba
                                        29.01.2018 18:43

                                        Это вы что то путаете. API это просто программный контракт, как контракт может иметь или не иметь состояние?


                                        С чего вы взяли что зависимость от бизнес данных хоть как-то влияет на состояние. В случае stateless вы будете чаще обращаться к источникам данных чем в случае с stateful, тут речь не об этом.


                                        Если у вас есть workflow, с этапaми login->choose_item->put_to_cart->purchase где за каждый этап отвечает микросервис. И если от login к choose_item или к put_to_cart у вас сохраняются данные в некой сессии, то у вас stateful. Так как сервер используя механизм сессий сохраняет некоторые данные между запросами HTTP(s). Что тут непонятного, ума не приложу, вам может литературу какую посоветовать по теме? Я там выше ссылку на статью оставлял.


                                        1. SirEdvin
                                          29.01.2018 19:00

                                          Это вы что то путаете. API это просто программный контракт, как контракт может иметь или не иметь состояние?

                                          Не зря же REST так назвали.


                                          Так как сервер используя механизм сессий сохраняет некоторые данные между запросами HTTP(s). Что тут непонятного, ума не приложу, вам может литературу какую посоветовать по теме?

                                          Непонятно то, почему если вы храните токен, то это внезапно становится stateless, хотя вы так же храните информацию о сессии.


                                          1. vba
                                            29.01.2018 19:12

                                            Непонятно то, почему если вы храните токен, то это внезапно становится stateless

                                            Дак никто же не хранит токен нигде, кроме клиента.


                                            Не зря же REST так назвали.

                                            REST-compliant Web services allow requesting systems to access and manipulate textual representations of Web resources using a uniform and predefined set of stateless operations


                                            Термин State здесь не про stateful. И официально на великий и могучий переводится как передача состояния представления. Помните про амнезию.


                                            REST Это архитектурный стиль. API в стиле REST остается всего лишь контрактом, так как контракт может быть stateful или stateless?


                                            1. SirEdvin
                                              29.01.2018 19:16

                                              Дак никто же не хранит токен нигде, кроме клиента.

                                              И мы обратно возвращаемся к тому, что или вы полагаетесь на клиент (что очень не безопасно) или делаете свое приложение таки немного stateful.


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


                                              1. vba
                                                29.01.2018 19:28

                                                И мы обратно возвращаемся к тому, что или вы полагаетесь на клиент (что очень не безопасно) или делаете свое приложение таки немного stateful.

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


                                                1. SirEdvin
                                                  29.01.2018 19:34

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

                                                  Потому что у вас есть проверочная информация на сервере, с которой вы его сравниваете.


                                                  REST по определению не может быть stateful, определение еще раз перечитайте.

                                                  Кто бы еще делал этот REST правильно)


                                        1. VolCh
                                          29.01.2018 19:27

                                          Пример контракта имеющего состояние:


                                          • сначала надо отправить запрос POST /auth с логином и паролем, в ответ придёт кука sessionId
                                          • сервер сохраняет userId в сессии
                                          • на все дальнейшие запросы нужно отправлять эту куку
                                          • сервер будет логировать Userid из сессии и проыерять права доступа.

                                          Пример контракта без состояния:


                                          • сначала надо отправить запрос POST /auth с логином и паролем, в ответ придёт подписанный токен с userId
                                          • на все дальнейшие запросы нужно отправлять этот токен
                                          • сервер будет логировать Userid из токена и проыерять права доступа.

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


                                          Изменение состояния сервиса — суть большинства моделей бизнес-процессов.


                                          1. vba
                                            29.01.2018 19:33

                                            Бизнес-данные, принадлежащие сервису — часть его состояния.
                                            А вот и нет. Бизнес данные отражают состояния ресурсов к которым тот или иной сервис имеет доступ. Состояние ресурса и состояние сервиса это разные вещи.

                                            Если вызов мутирующего запроса или метода требует предварительного вызова других запросов или методов, то интерфейс этого сервиса или объекта является stateful.

                                            Я свои доводы подкрепил ссылками на статьи и даже википедию. Вы чем можете подкрепить свои утверждения?


                                            1. VolCh
                                              29.01.2018 19:49

                                              Например http://whatisrest.com/state_management_explained/types_of_state


                                              Обратите внимание на диаграмму: состояние в stateful сервисах делится на состояние контекста, сессии и бизнес-модели. Вы говорите только о stateless sessions.


                                              1. vba
                                                29.01.2018 20:47

                                                Я вам ответил ниже и по диаграмме и по тексту. Есть только одно понятие stateless. Опровергаете, ссылочку пожалуйста.


                                          1. ggo
                                            30.01.2018 09:39

                                            Извиняюсь, что вклиниваюсь.
                                            Statefull vs Stateless не про контракты, а про особенность обработки запросов конкретно в этом узле. Если какой-либо стороне нужно помнить контекст, чтобы с учетом этого контекста правильно обращаться в следующий раз, то это Statefull. В обратном случае — Stateless.
                                            Например в вашем примере два варианта, с кукой и токеном. В общем случае клиенту, нужно помнить куку или токен. Для него это Statefull. Если он будет забывать куку или токен, то не сможет нормально обращаться к сервису. Т.е. клиент в обоих случаях должен помнить состояние.

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

                                            Вот такой дуализм


                                            1. andreycha
                                              30.01.2018 12:40

                                              Извиняюсь, что вклиниваюсь. Но прекратите уже писать statefull. Нет такого слова. Есть слово stateful.


                                        1. mayorovp
                                          29.01.2018 21:10

                                          Это вы что то путаете. API это просто программный контракт, как контракт может иметь или не иметь состояние?

                                          Очень просто. Stateless контракт выглядит вот так:


                                          login(): token
                                          foo(token)
                                          bar(token)

                                          Statefull же — вот так:


                                          login()
                                          foo*()
                                          bar*()
                                          
                                          * вызывать только после login()


                                          1. vba
                                            29.01.2018 23:16

                                            Если токен передаете через заголовки то у вас никакой разницы в сигнатурах не будет. То что вы пометили звездочкой справедливо для обоих сценариев.


                                            Если следовать вашей логике со счетчиком то любой stateful контракт можно замаскировать под stateless и наоборот.


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


                                            1. mayorovp
                                              30.01.2018 06:16

                                              Не "замаскировать", а "преобразовать". Нет, не любой.


                                              То что вы пометили звездочкой справедливо для обоих сценариев.

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


                                              1. vba
                                                30.01.2018 12:40

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

                                                Не всегда, технически пока "сессия" жива не нужно проходить через логин этап. Иногда куки сессии могут просто угнать.


                              1. Bronx
                                30.01.2018 14:41
                                +1

                                Stateful service — это когда клиент, однажды начавший общаться с одним инстансом сервиса (из десятка-сотни активных), обязан продолжать общаться с этим же инстансом до самого закрытия сессии. Инстанс должен быть умным и обходительным, постоянно помнить о клиенте, о его недавних запросах, о своих недавних ответах и т.п. (has state). Но если на какой-то инстанс вдруг навалилась толпа клентов, то он будет терпеливо обслуживать её пока она не рассосётся, даже если рядом прохлаждается без нагрузки другой инстанс. Так же сервису, чтобы быть таким умным, может быть необходимо хранить много персональной информации в своей БД, что чревато.

                                Stateless service — это когда ни один инстанс ни одного клиента не помнит (has no state), и каждый раз устанавливает его личность заново, глядя в его пропуск (token), в котором написано всё необходимое для работы сервиса (claims: имя, пол, возраст, должность, ...), а подлинность пропуска и написанного в нём устанавливает проверкой подписи выдавшего этот паспорт органа (trusted issuer). Сервис не хранит в своей БД никакой личной информации о клиенте (всё «личное» есть в пропуске) — БД становится деперсонифицированной, что добавляет безопасности при её компроментации. Это добавляет немного расходов, но позволяет футболить клиента от окошка к окошку, распределяя нагрузку и делая узкоспециализированные «тупые» инстансы, работающие по простому шаблону «глянул в пропуск — сверился с инструкциями безопасности и правил доступа — обслужил/отказал — немедленно забыл — NEXT PLEASE!».


                                1. VolCh
                                  30.01.2018 14:55

                                  Если я вместо локальной ФС начну хранить данные сессии на расшаренной ФС, redis или ещё где, неужели мой сервис станет stateless?


                                  1. Bronx
                                    30.01.2018 15:06
                                    -1

                                    Не совсем понятно, каким боком к моему комменту относятся расшаренная ФС, редис и проч?

                                    Но нет, сервис не станет stateless, если он сам лезет за данными сессии, а не клиент ему приносит.


                                    1. VolCh
                                      30.01.2018 15:19
                                      +1

                                      Вы говорите о приклеивании клиента к инстансу как об основном практическом признаке и недостатке stateful. Расшаривание данных сессий между инстансами устранит приклеивание — любой из инстансов апп-сервера может записать и (или) достать данные из сессии.


                                      Собственно, это стандартный способ сделать stateless как можно большее число внутренних подсервисов, чтобы сосредоточить state лишь в нескольких, специально заточенных под хранение state, типа Redis или *SQL


                                      1. Bronx
                                        30.01.2018 16:03
                                        -1

                                        Т.е. каждому инстансу нужно теперь заботиться не только о своих бизнес-делах, но и о том, чтобы делиться сессиями с другими инстансами? И я не могу взять и перенести инстанс туда, где нет быстрого доступа к shared session storage?

                                        Не, я понимаю, что можно говорить о разных градациях statefulness/statelessness, но где-то нужно провести границу, хотя бы для сессий. В моём понимании этой границей является способ распространения shared user data. Либо через клиента (который всё равно сам приходит, и может заодно принести данные) — и тогда у инстанса нет забот, не нужно хранить состояние сессии нигде вообще, только знай проверяй подпись и сверяйся с полиси. Либо состояние есть и передаётся через какой-то back-channel, который нужно позаботиться установить, обезопасить и поддерживать.


                                        1. VolCh
                                          30.01.2018 22:03

                                          Расшарить сессии — часто самый и быстрый и простой способ обеспечить горизонтальную масштабируемость. Особенно, если сервис и так привязан к какому-то shared storage, что часто бывает.


                                          1. Bronx
                                            31.01.2018 09:22

                                            И это превращает сервис в stateless? Ему не нужно теперь заботиться, например, о том, чтобы чистить сессию после ухода клиента (или если он молча пропал на месяц)?


              1. vba
                29.01.2018 15:34

                У вас как минимум есть сессия пользователя, а еще, например, текущая временная точка на ролике.

                Это вовсе не обязательно, технически если вы используете Apache Netty, Sinatra в спец конфигурации или какую-нибудь легковесную имплементацию OWIN, итд, ничего этого у вас нет и быть не может по определению. 9 лет назад впервые начали говорит о понятии async web где внутренней организации чуждо само понятие сессии.


          1. YemSalat
            29.01.2018 16:44

            Ну вот не знаю, мой аккаунт как-то хранится в netflix, какой тут stateless

            То что у них есть база данных где ваш аккаунт лежит — как то влияет на «statefullness» самого приложения?


            1. SirEdvin
              29.01.2018 16:45
              -1

              Ну, значит его откуда-то надо достать в конечном итоге. А значит где-то в их системе таки есть stateful приложение.


              1. powerman
                29.01.2018 19:15

                На самом деле правы и Вы, и Ваши оппоненты.


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


                С другой стороны, когда данные сервиса кладут в MySQL и по этой причине решают что сервис стал stateless — это некорректно. На первый взгляд, если строго формально, у нас получается как бы два сервиса: stateful MySQL с данными, и наш stateless сервис без данных. И наш "stateless" сервис действительно можно запускать в нескольких экземплярах и масштабировать как настоящие stateless сервисы (только все эти экземпляры должны работать с общим MySQL). Но ключевой момент в том, что сервис MySQL не является настоящим "владельцем" хранящихся в нём данных — владельцем данных остался наш "stateless" сервис, т.к. именно он определяет схему данных и его требуется изменять синхронно с изменением схемы данных. Не важно, через какой интерфейс (файловое API OS, сетевой доступ к серверу БД или какому-то другому сервису) сервис получает доступ к данным, важно насколько сильно он связан с этими данными и кто имеет возможность изменять структуру этих данных — именно этим определяется, stateful он или нет.


                В качестве "теста на stateless" можно задаваться простым вопросом: нужно ли изменить код сервиса если незначительно изменится схема данных (например переименовали таблицу в БД). Если да — значит он stateful.


            1. VolCh
              29.01.2018 17:56

              Конечно влияет, это делает само приложение в целом statefull. Stateless может быть веб-сервер, апп-сервер, но в целом приложение будет statefull из-за наличия СУБД.


              1. vba
                29.01.2018 18:48

                Если следовать вашей логике то в природе есть только stateful приложения. Поскольку исходники любого приложения развернуты на сервере и прежде чем обработать запрос в первый раз серверу нужно подгрузить исходники или залить байткод в JIT компилятор или whatever. Следовательно в любом случае нужно куда-то обращаться соу это stateful. Вздор.


                1. VolCh
                  29.01.2018 19:35
                  -1

                  Нет, не следует. Если приложение на все одинаковые запросы отдаёт одинаковые ответы независимо от того, только что оно развёрнуто/запущено или уже обработало миллион запросов, то это стейтлесс. А если на запрос GET /posts/count оно отдаёт количество успешно обработанных запросов POST /posts, то оно stateful.


                  1. vba
                    29.01.2018 19:41

                    Чем подкрепите свое утверждение?


                    1. VolCh
                      29.01.2018 19:49

                      1. vba
                        29.01.2018 20:46

                        Укажите где в источнике на который вы ссылаетесь есть подтверждение тому что вы сказали выше?


                        Я же нашел след формулировку:


                        As you may have guessed, a service that is actively processing or retaining state data is classified as being stateful.

                        Это не соответствует вашему утверждению. Капнем глубже и увидим:


                        A classic example of statelessness is the use of the HTTP protocol. When a browser requests a Web page from a Web server, the Web server responds by delivering the content and then returning to a stateless condition wherein it retains no further memory of the browser or the request.

                        Следовательно, состояние stateless это состояние при котором сервер не удерживает никакой информации о браузере или запросе или прочей под информации. Следуя данной формулировке мой endpoint GET /posts/count, which does not retain neither further memory of the browser nor the request is considered as stateless. То же самое можно сказать про ваш POST.


                        Ну так что же подтвердит ваше утверждение что


                        Если приложение на все одинаковые запросы отдаёт одинаковые ответы независимо от того, только что оно развёрнуто/запущено или уже обработало миллион запросов, то это стейтлесс. А если на запрос GET /posts/count оно отдаёт количество успешно обработанных запросов POST /posts, то оно stateful.


                        1. VolCh
                          29.01.2018 21:08

                          Первая цитата. Почему не соотвествует? Если ответ всегда одинаков, то значит состояние приложения не изменяется. По факту этого состояния и нет. По крайней мере для клиента. Может приложение и пишет активно логи и эти логи можно считать состоянием, но как-то натянуто.


                          По второй цитате — stateless там о протоколе, а не о приложении в целом. Сервер не удерживает никакой информации о текущей сессии, о текущем клиенте, о его предыдущих запросах в рамках протокола. Но вот ваше "или прочей под информации" некорректно. Сервер удерживает информацию из тела некоторых запросов, он может не хранить связь с запросом или хранить, но не использовать для бизнес-логики, но своё состояние изменяет — это изменение цель таких запросов. Хранить он его может в памяти, файлах, встроенной базе данных или сервере баз данных, облачном хранилище — это лишь деталь хранения.


                          1. vba
                            29.01.2018 23:08

                            Но вот ваше "или прочей под информации" некорректно

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


                            Если ответ всегда одинаков, то значит состояние приложения не изменяется.

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


                            По второй цитате — stateless там о протоколе, а не о приложении в целом.

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


                            A classic example of statelessness is the use of the HTTP protocol.

                            Все остальное ваши фантазии.


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

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


                            REST-compliant Web services allow requesting systems to access and manipulate textual representations of Web resources using a uniform and predefined set of stateless operations.


                            1. VolCh
                              30.01.2018 12:47

                              Возьмем к примеру сервис который выдает вам тек время, по вашему выходит что это stateful сервис.

                              Конечно stateful. Есть некое состояние, изменяющееся со временем, и сервис даёт его текущий срез.


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

                              Да, протокол в этом примере свободен от состояния. Про состояние приложения не говорится вообще ничего.


                              Сервер ничего сам по себе удерживать не будет если вы ему не скажете об этом.

                              Ну, условно можно и так считать. Но большинство сервисов как раз и создаются, чтобы удерживать состояние бизнес-модели и им я прямо об этом говорю, например, путём INSERT/UPDATE/DELETE SQL-запросв.


                              Вы выделили "операции" — в REST-сервисе операции должны быть stateless, операции — это интерфейс сервиса, его внешний контракт. Но сам сервис не должен быть stateless.


                              1. vba
                                30.01.2018 13:16

                                Конечно stateful. Есть некое состояние, изменяющееся со временем, и сервис даёт его текущий срез.

                                Чем подкрепите ваше утверждение? Я говорю что этот сервис stateless если не удерживает состояния в виде контекста сессии от предыдущего запроса. Что абсолютно симметрично примеру с HTTP протоколом из вашего источника.


                                чтобы удерживать состояние бизнес-модели

                                Наличие изменения представления ресурса не влияет на statelessness/statefulness сервиса. См определение из вашего источника.


                                Вы выделили "операции" — в REST-сервисе операции должны быть stateless, операции — это интерфейс сервиса

                                А вот и нет, операция это лишь часть интерфейса. REST-сервис может состоять из одной или множества stateless операций. До тех пор пока все операции данного сервиса stateless этот сервис можно считать REST-совместимым. Следовательно REST-сервис это stateless сервис.


                                REST-compliant Web services allow requesting systems to access and manipulate textual representations of Web resources using a uniform and predefined set of stateless operations.

                                Мне кажется то что вы так яро называете состоянием приложения или системы, в данном определении названо представлением ресурса (representation of resource) но увы не его состоянием. Наличие изменяемых или неизменяемых ресурсов в системе делает ее immutable/mutable но не stateful/stateless.


                                1. VolCh
                                  30.01.2018 14:30

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


                                  Наличие изменения представления ресурса не влияет на statelessness/statefulness сервиса.

                                  Наличие операций изменения ресурса точно делает ресурс stateful, даже если клиенты обращаются к нему по stateless протоколу.


                                  А вот и нет, операция это лишь часть интерфейса. REST-сервис может состоять из одной или множества stateless операций. До тех пор пока все операции данного сервиса stateless этот сервис можно считать REST-совместимым. Следовательно REST-сервис это stateless сервис.

                                  REST-сервис является stateless сервисом на уровне своего интерфейса, протокола, но, как правило, он является stateful на уровне бизнес-модели.


                                  Вы ограничиваете характеристику stateful/stateless только на сессию, может ещё на контекст, а я распространяю её на бизнес-данные. Можно говорить, что в многозвенной архитектуре, например, типичной для веб-сервисов трёхзвенке (веб-сервер, апп-сервер, сервер СУБД) только одно звено является stateful, но оно делает весь сервис stateful. Если вы захотите перенести или склонировать сервис, вам понадобится переносить данные. Собственно, это главное практическое отличие stateless от stateful. Не хотите рвать сессию при переносе/масштабировании — делайте приложение session stateless, не хотите терять бизнес-данные — делайте приложение business stateless.


                                  1. vba
                                    30.01.2018 15:43

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

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


                                    Понятия stateless/stateful используются в контексте потоков информации в контексте движения. Ваш БД слой никаких потоков или движения не осуществляет, это такая же абстрактная структура данных только не в памяти.


                  1. Bronx
                    30.01.2018 15:21
                    -1

                    Если приложение на все одинаковые запросы отдаёт одинаковые ответы независимо от того, только что оно развёрнуто/запущено или уже обработало миллион запросов, то это стейтлесс.

                    Тоже stateful, только state в нём immutable :)


  1. nApoBo3
    29.01.2018 11:30

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

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


  1. amarao
    29.01.2018 12:27

    В обсуждении «микросервисной архитектуры» (уберите «микро» — просто «многосервисной») пропускают одну важную деталь. Чем больше у вас компонент, тем сложнее IPC. Исключением может быть приложение, в котором каждая компонента сама по себе и с друг другом они не взаимодействуют (пример: фен для волос и чайник).

    Если же взаимодействие есть, то тут есть простое правило: Inter-process communication сложнее, чем in process Communication. Причём, если ошибка передачи параметров внутри программы часто ловится компилятором/интерпретатором, то ошибки в IPC ловятся в махровом рантайме и погружают администраторов в потрошки внутреннего мира программы.

    Утрируя: если фабрика DSL'ей содержит баг, приводящий в ошибке интерпретации некоторых инструкций некоторых DSL'ей, то это чисто баг в программе.

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

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

    Потому что администратору иногда очень трудно понять какие тараканы были в голове у разработчика, когда он сделал «ТАК» (когда оно работает, то всё сделано хорошо, мы же баг обсуждаем, правда?).


    1. acmnu
      29.01.2018 12:47

      Inter-process communication сложнее, чем in process Communication

      Это конечно верно, но когда в рантайм возникает проблема с in process Communication, для администратора все становится ещё сложнее. Нужен трейсер или дебагер. А побольшому счету обязательно нужен программист. И не факт, что он доступен конкретно сейчас.


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


      1. amarao
        29.01.2018 12:58

        Для борьбы с in process issues существуют более богатые инструменты.

        IPC же может сломаться по совершенно эзотерической причине — превышение unknown unicast лимита на свитче, изменение алгоритма выставления don't fragment на туннелях, etc. Эти штуки требуют отдельной компетенции (не связанной с приложением).

        Получается, что тыкая IPC всюду, возможные баги в приложениях вытаскиваются на тот же уровень, на котором находятся сайд-эффекты внешнего мира. Это не только усложняет отладку, но и резко повышает требования к программисту, который отлаживает свой (кривой) IPC — он должен думать уже не только про структуры данных и архитектуру, но и про посторонние вещи, вроде ERD на роутере, глюков на агрегированных линках, кешей DNS, etc.


        1. acmnu
          29.01.2018 13:02

          Вот для этого и нужны люди, которые в этом понимаю. Плюс админы. Для них вся эта кухня весьма понятна проста (я сам выходец из админов). Т.е. нужно разделение ролей: есть люди которые работают над IPC и понимают его. Они делают удобные инструменты для тех кто пишет бизнеслогику и объясняют последним границы допустимого.


          1. amarao
            29.01.2018 13:11

            Есть альтернативный вариант: уменьшать количество IPC если это возможно. Меньше IPC — меньше моментов, когда очередной программист с удивлением узнаёт, что «гарантированная доставка TCP» не означает гарантированного времени или самой доставки, а гарантируется либо доставка, либо ошибка (в самом конце отправки сообщения длинного).


            1. acmnu
              29.01.2018 13:16

              Ну это в принципе хорошее правило не дробить сервис больше чем надо. Можно еще унифицировать ipc через кафку или кролика.


    1. nApoBo3
      29.01.2018 13:45

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


      1. amarao
        29.01.2018 16:09

        Скажите, а если на сетевом интерфейсе лимит очереди 1000 пакетов, а в какой-то момент времени пришло 1030 и 30 из них дропнулись — это баг в сетевом окружении или в ПО?

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


        1. nApoBo3
          29.01.2018 16:57

          Если UDP пакеты, то приложение должно это пережить без всяких проблем, если TCP, то они должны быть перенаправлены или отправитель должен получить таймаут который должен корректно обработать. В монолите вы тоже можете упереться в проблему внешних ресурсов, только отладить ее будет значительно сложнее, поскольку микросервисы должны быть рассчитаны на такие ситуации и обычно лучше их логируют( и проблема будет изолированной ).


          1. amarao
            29.01.2018 17:41

            Программисты решили проблему: они корректно обрабатывают таймаут. Теперь у нас новая проблема: спорадические таймауты на ровном месте. Кому от этого легче?

            Поскольку IPC по своей сути — это целиком и полностью использование side effect'ов, то перевод из вызова силами языка в IPC, это перевод чистого кода в код с side effect'ами. Что, традиционно, вызывает боль и проблемы.

            Чем более код остаётся в чистом виде (без side effect'ов), тем легче его сопровождать. Чем меньше у кода точек соприкосновения с side effect'ами, тем легче его администрировать.


            1. nApoBo3
              29.01.2018 18:06

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


              1. amarao
                29.01.2018 18:50

                Вот вы и попались. Споратические таймауты от переполнения буфера из-за microbursts «лечить» не получится (см про идеальную инфраструктуру), можно только менять архитектуру, чтобы уменьшать их влияние.

                А в «монолите» таймаутов такого рода не будет, потому что это чистый код. Работа с СУБД — разумеется, да, но это как раз «отдельные места для side effects».


                1. powerman
                  29.01.2018 19:24

                  Микросервисы упрощают разработку за счёт того, что часть сложности переносится в связи между микросервисами. Частично эта новая сложность сказывается на программистах (обработка сетевых ошибок, таймауты, повторы, …), частично на админах/девопсах. Так что да, Вам, как админу, микросервисы проблем только добавили. Так задумано, и во многих случаях оно того стоит. :)


                  1. amarao
                    30.01.2018 10:56

                    Я понимаю, что «иногда оно того стоит». Моя мысль была в том, что мультисервисная архитектура — это не бесплатно, и ожидаемая выгода должна превышать резко увеличивающиеся расходы (времени, внимания) на сопровождение. Если есть причина — да, конечно. Если микросервисы во имя смузи и хайпа — спасибо, нет.


                    1. VolCh
                      30.01.2018 12:49

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


                1. VolCh
                  29.01.2018 20:06

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


                  Грубо, одной из задач админов всегда было минимизировать количество таких проблем, а одной из задач программистов минимизировать последствия проблем, которые админы (ожидаемо) не смогли предотвратить. Ничего качественно нового микросервисы в задачи программистов не внесли в этом плане. Помните же "Abort, Retry, Fail?" Кажется в MS-DOS появилось, а в CP/M просто ждала до бесконечности.


                1. nApoBo3
                  29.01.2018 21:13

                  У вас странный подход:
                  1. Таймауты описанные вами в 99% случаев до приложения не дойдут, только в случае длительной перегрузки каналов. Они обрабатываются на tcp уровне для которого потеря пакетов это часть нормального функционирования, что называется байдизаин, более того, на эту саму потерю он частично завязан и без корректной обработки вообще не может функционировать в более менее сложных сетях.
                  2. Таймауты нужно по возможности устранять, о чем я вам и написал. Это не значит, что их всех можно вывести, но при большом кол-ве таймаутов пользовательский опыт от приложения сильно снизиться.
                  3. Следует сравнивать различные подходы. Недостаток, только тогда становиться недостатком, когда его есть с чем сравнить.
                  Подходы следует сравнивать в равных условиях, мне кажется не корректным сравнение сложной континентально распределенной системы на микросервисах, с монолитом в пределах одной серверной.
                  Если мы говорим о распределенных системах, то проблемы таймаутов будут и там и там, и в микросервисах они решаются проще, если в пределах серверной, то проблем и там и там не будет при условии адекватной инфраструктуры, проблемы с которой являются вполне устранимыми.
                  4. Микросервисы изначально следует проектировать с учетом возможных отказов сетевого уровня. Учитывая требования к сложности отдельно сервиса, это не rocket science.


                  1. acmnu
                    30.01.2018 10:37

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

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


                    1. nApoBo3
                      30.01.2018 23:20

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


    1. VolCh
      29.01.2018 18:08

      Ну, в целом перевод на микросервисы делается не от хорошей жизни, а в том числе и чтобы облегчить жизнь эксплуатации, чтобы эксплуатация не упиралась в физические или финансовые пределы вертикального масштабирования. Микросервисы — это ответ на вопрос (один из возможных) «а можно сделать, чтобы вместо одного сервера с 256 ГБ оперативки было два, даже пускай три с 128 ГБ», это ответ на вопрос «а модно сделать так, чтобы деплой исправления опечатки в печатной форме для юриста не ложил на полчаса всю систему?». Собственно часто сами админы доходят до идей небольших, делающих одну вещь, сервисов. Если не впитали эту идею с молоком матери :)


      1. amarao
        30.01.2018 11:03

        Абсолютно валидная причина. Мы снижаем безумные расходы на железо увеличением расходов на обслуживание. На обслуживание расходы выросли чуть-чуть, а стоимость «просто серверов» по сравнению с «чудо-мейнфреймом» упала кратно. Это причина, достаточная для внедрения мультисервисной архитектуры.

        Я ж как раз про это и говорил — должна быть веская причина. Микросервисы без причины — признак дурачины.


  1. scruff
    29.01.2018 12:56

    Подскажите по терминологии, гуглил, но не особо усвоил — что такое оркестровка в микросервисах и как оректровка отличается от, например, управления или конфигурирования?


    1. amarao
      29.01.2018 12:59

      orchestration в хорошей реализации следит за всем lifecycle — то есть не только деплоит (запускает и конфигурирует), но подчищает после. «Управление» — слишком общий термин.


      1. andreycha
        29.01.2018 14:04

        Пардон, не туда ответил.


    1. andreycha
      29.01.2018 14:04

      Оркестровка применительно к микросервисам используется еще в одном смысле: как способ взаимодействия сервисов между собой. Вы какую оркестровку имеете в виду?


      1. amarao
        29.01.2018 16:09

        Первый раз такое слышу. Это откуда такое?


        1. andreycha
          29.01.2018 16:28

          По-моему еще из SOA идет, если не раньше. Оркестровка и хореография.

          Вкратце смысл такой:
          image


          1. amarao
            29.01.2018 16:44

            Вот это «An orchestration shows the complete behavior of each service» — очень точно. А насчёт того, что это «способ взаимодействия» — меня очень смущает, потому что это выглядит как описание сетевого протокола.


            1. Hronom
              01.02.2018 04:57

              А мне нормально, вот тут stackoverflow.com/a/30441546/285571 вначале ответа очень хорошо рассказали разницу между Orchestration и Choreography. Это именно описание поведения взаимодействия между сервисами. По какому принципу и понятиям они уживаются вместе образуя систему=)

              Orchestrating также применили тут на презентации www.slideshare.net/weaveworks/orchestrating-microservices-with-kubernetes по полному циклу управления микросервисами. Это из другой области.

              Ну это всё сухие термины…


              1. amarao
                01.02.2018 12:55

                Это, на самом деле, крайне интересный вопрос. Я осознал, что раньше под оркестрацией подразумевали регламент/протокол/соглашение, полностью описывающее всё взаимодействие сервисов. То есть это был термин уровня проектирования.

                А потом пришли инструменты оркестрации, и оркестрация из идеи в голове превратилась в конкретные yaml'ы, и сейчас оркестрация — это не только идея, но и её практическое воплощение. Средство оркестрации, описание этого взаимодействия в машиночитаемых (машиноисполнимых!) формах, etc.

                Примерно то же самое случилось с configuration management. Начиналось оно с идеи, а потом превратилось в конкретные проявляения конкретных софтин.


      1. scruff
        29.01.2018 17:18

        Если бы знал, что такое оркестровка сформировал бы точный её вид. Хотя amarao дал весьма понятное начальное определение оркестровки. Если можете дополнить, расширить или разделить на подвиды оркестровку, буду только только рад услышать. Спасибо.


  1. jakobz
    29.01.2018 13:48
    +1

    У меня вот бизнес часто хочет что-то типа «всем зайчикам, проживающим в одной хатке с бобриками, с 3 до 5 утра по их таймзоне, давать скидку на морковку зеленого цвета, в 10 долларов в рублях по текущему курсу, если морковку сажали беременные белочки, и грядки были не далее 10 км от речки».

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

    Короче, может все тут и пишут high-load видео-стриминг сервисы, а я один — про белочек и зайчиков. И всех дикий-предикий high-load, и прям надо половину сервисов писать на rust, и половину на python, и прям чтобы все скейлилось в разы за секунды, и умело жить когда половина системы легло. Тогда да. Тогда, наверное, хорошо все эти микросервисы работают.

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


    1. carebellum
      29.01.2018 13:59
      +1

      не совсем понятно откуда появилось предположение, что каждый сервис должен иметь свою БД


      1. andreycha
        29.01.2018 14:09

        Ну как бы из самой идеи микросервисов: возможность независимого развертывания и масштабирования. Но это скорее настоятельная рекомендация, нежели обязательное требование.

        По теме:
        «Microservices prefer letting each service manage its own database»
        Pattern: Database per service


        1. carebellum
          29.01.2018 14:12

          не стоит слепо следовать рекомендациям
          если бобробелочка хорошо вместе с зайчиками, и плохо по-отдельности, оставьте как есть


          1. Siroque
            29.01.2018 16:01

            Для этого надо чётко различать, что есть рекоммендация, а что есть неотъемлемая часть архитектурного паттерна. Иначе получается как со SCRUM — «Мы используем SCRUM! Но только у нас product owner и scrum master это один человек, мы выбросили ретроспективы за ненадобностью и используем канбан-доски»


          1. AlexanderG
            29.01.2018 17:06

            если бобробелочка хорошо вместе с зайчиками, и плохо по-отдельности, оставьте как есть

            … и тут мы получили снова монолит


            1. carebellum
              29.01.2018 17:14

              нет, мы получим вынесенный сервис БД


              1. AlexanderG
                30.01.2018 15:31

                С единой БД мы лишаемся независимости сервисов


          1. commanderxo
            29.01.2018 19:39

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

            Легко поменять систему которой никто не пользутеся, но вот бизнес почему-то ищет успешные (читай «старые») продукты и думает как бы их ещё проинтегрировать чтоб извлечь дополнительную пользу.


      1. Siroque
        29.01.2018 15:56

        Если в общем, то это следует из концепта аггрегаций описанного DDD.


    1. kkirsanov2
      29.01.2018 14:01
      +2

      А как так получилось что зайчики, бобрики и белочки в разных БД живут? Ведь классификаций можно придумать великое множество — начиная от «все живут в одной бд» до «разница в 1 атом — существенна».


      1. kozzztik
        29.01.2018 14:35

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


        1. nApoBo3
          29.01.2018 18:16

          Ну так не плачьте :)
          Корс сервисные агрегации данных это действительно проблема, но не в этом случае.

          «всем зайчикам, проживающим в одной хатке с бобриками»

          Выделяем хатки и их обитателей.

          ", с 3 до 5 утра по их таймзоне,
          давать скидку на морковку зеленого цвета,"

          В условиях скидки пописываем возможность указать цвет объекта и время операции.

          " в 10 долларов в рублях по текущему курсу,"

          Прикручиваем запрос курса у цб, возможно кэшируем его у себя.

          «если морковку сажали беременные белочки, и грядки были не далее 10 км от речки»

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

          Вообще вопрос в выделении зон ответственности сервисов и в способности предсказывать как они будут меняться в будущем.


          1. kozzztik
            29.01.2018 18:24

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

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


    1. habradante
      29.01.2018 14:04
      +1

      В такой ситуации можно сделать многосервисную архитектуру на одной БД. Микросервисы не панацея, у них масса минусов, и это не серебряная пуля, не надо плакать :)


    1. imanushin
      29.01.2018 14:21
      +2

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

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


      Потому что я в упор не понимаю, как можно сделать распределенный join 10-ка таблиц

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


      «всем зайчикам, проживающим в одной хатке с бобриками, с 3 до 5 утра по их таймзоне, давать скидку на морковку зеленого цвета, в 10 долларов в рублях по текущему курсу, если морковку сажали беременные белочки, и грядки были не далее 10 км от речки»

      Хотя даже в этой задаче сервис "поставщик курса валют" может быть отдельным.


      1. kkirsanov2
        29.01.2018 14:46

        Если в проекте возникла такая задача, то это сразу маркер абсолютной некомпетентности архитектора проекта.

        Бизнес меняется и требования меняются. Если белка — покупатель и бобёр покупатель то кажется логичным их объеденить в одну базу\таблицу Customer. Но вот о том, что они будут покупателями могли и не знать предыдущие 5 лет разработки системы.


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


        1. imanushin
          29.01.2018 15:03

          То есть вы считаете архитектора и разработчиков квалифицированными, если ошибка сохраняется


          5 лет разработки системы

          ?


          Нет, тут не кровати (т.е. микросервисы) двигать надо.


          1. VolCh
            29.01.2018 18:25

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


        1. mad_nazgul
          29.01.2018 15:05

          А в чем проблема?!
          Пишем еще один микросервис, который объединяет этот зоопарк в один домик.
          Наружу выставляются нужные методы (REST-API).
          Делов-то
          <:o)


          1. jakobz
            29.01.2018 18:24

            И рядом с этим микросервисом кладем БД, в которую выкачиваем по ночам все БД про валюты, реки, и половые связи зайчиков и белочек? Просто походами по нескольким REST-эндпоинтам такой запрос ведь не написать.


            1. VolCh
              29.01.2018 20:12

              Сильно зависит от задачи. Одно дело проверить вот этого конкретного клиента давать ли ему здесь и сейчас скидку, другое — разослать смс-рассылку "завтра с 3 до 5 ночи у вас скидка 0.01%", третье — дать бизнесу оценку сколько клиентов попадёт под скидку, если завтра мы её запустим. По разные задачи разные решения. Первую вполне можно решить походом по нескольким енд-поинтам.


            1. Paskin
              29.01.2018 23:58

              Для таких запросов есть специальные костыли вроде Apache Drill. Главное — их не показывать всяким data scientist-ам, а то умножение какой-нибудь виртуальной таблички в миллион записей на саму себя через REST принесет незабываемые ощущения.


            1. mad_nazgul
              30.01.2018 05:56

              Фига?!
              У зайчиков, белочек и прочих животных свои БД и микросервисы.
              К ним и ходим «в гости», а потом создаем «фрянкенпуха» и отдаем дальше.
              В общем считайте, что БД у вас нет, а есть сервисы, с которых тянутся животные.
              Понятно, что базист в шоке.
              Но кто сказал, что будет легко.
              <:o)


              1. jakobz
                30.01.2018 11:15

                Зайчик открывает «мокровка.маркет», и ищет зелёную морковку, выращенную на грядке возле речки.

                Сервис «маркет» идет в сервис «грядки», дергает «getAllGryadkiVozleRechki», достает 10000 ID-шек грядок. Потом идет в сервис «морковки», и передает ему 10000 ID-шек грядок в «getMorkovki?gryadkiId={...10k грядок}&{tcvet='green'}»

                Ну и дальше все начинают заниматься какой-нибудь хернёй типа кешей, репликацией куска БД через кафку, построением общего сервиса «поиск морковок», подключением graphQL, бинарной сериализацией 10к ID-шек в AVRO, индексированием морковок мна GPU и нейросетях…

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


                1. VolCh
                  30.01.2018 13:05

                  Сервис грядок вполне может (а скорее должен) хранить отношение морковок к грядкам и отдать id-шки морковок в ответ на getMorkovkiSGraydokVozleRechki, а сервис маркет может в запросе ограничить количество морковок в ответе по какому-то критерию грядок или просто первые деять идшников морковок в случайном порядке. В принципе даже сервис грядок может хранить мастер-данные о цвете морковок, если цвет используется только в контексте грядок. Либо хранить реплику мастер-данных о цвете, но тут надо будет позаботиться так или иначе об консистенции.


                  1. jakobz
                    30.01.2018 15:03

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

                    Или можно сделать горизонтальные сервисы типа «data warehouse», и «elastic index» — которые собирают и индексируют все имеющиеся данные, предоставляют к ним быстрый доступ, но принципиально не делают никакой бизнес-логики (для них зайчики и морковки — просто какие-то там таблицы)

                    Пойми правильно — я не против идеи микросервисов, и у меня у самого тут большая распределенная фигня с кафками и докерами. Просто ко мне регулярно приходят разные люди, с предложениями типа «а зачем тебе таблица employees со всеми сотрудниками в БД каждого приложения? Почему вы не сделали микросервис под это, и туда по REST API не ходите»? И вот этот пример с зайками и морковками — они воспринимают как что-то типа «опа, а реально такая проблема есть?».

                    И мне от этого как-то страшно становится — идея микросервисов очень активно продается, все ее к себе тащат, но мало кто понимает эту всю историю достаточно глубоко.


                    1. VolCh
                      30.01.2018 22:00

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


                      1. mad_nazgul
                        02.02.2018 10:13

                        Все украдено придумано до нас Лямбда-архитектура
                        <:o)


    1. ggo
      29.01.2018 14:40

      В реальности так и есть, хехе…
      Выделяется отдельный сервис — Бонусы. В него сливается тем или иным способов все, что нужно для принятия решения по бонусам. И затем либо сам сервис Бонусов строит кампании и отдает их потребителям, либо сами потребители идут в сервис Бонуса и спрашивают, есть ли что предложить для клиента Х.
      А все потому, что вы верно отметили, у нас куча разных (не всегда микро) сервисов.
      И не потому что кто-то очень любит сегментацию и пилит сервисы пачками. А потому, что бизнес большой и команд много, и многие команды слышали друг про друга, но реально не общались. Потому что когда команд за три десятка, общаться со всеми невозможно в принципе. И монолит даже теоретически невозможен.


    1. VolCh
      29.01.2018 18:20

      Для гигантского кеша есть название data warehouse и для него есть наработанные практики поддержания той или иной степени консистентности.


  1. r-moiseev
    29.01.2018 23:10

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


    1. raciasolvo
      30.01.2018 06:25

      и ответственно относиться к выбору инструментов.

      «Netflix хороши в DevOps. Netflix делают микросервисы. Таким образом, если я делаю микросервисы, я хорош в DevOps».

      Мысли из серии You Are Not Amazon, Again



  1. DexterHD
    30.01.2018 11:26

    Последние мысли: не путайте микросервисы с архитектурой

    Можно сказать так: «Если вы не знаете вашего бизнеса, и не в состоянии спроектировать монолит выделив правильно ограниченные контексты и разбив его на компоненты, микросервисы вам скорее всего не помогут».

    А если выделите правильно, то и монолит будет выглядеть норм ;)