[Перевод] Букварь по дизайну систем (Часть 1 с дополнениями по микросервисам)

hth7pusdcnys9m96fymdr7mo1q4.png

Несколько лет назад, для закрытия одного их предметов мне довелось перевести данный букварь. Де-факто этот вариант стал официальным переводом. Но развитию этого перевода мешает, тот факт, что он был написан в Google Drive и закрыт на редактирования. Сегодня я уделил время на переформатирования всего этого текста в MD формат с помощью редактора Хабра, с радостью публикую здесь и вскоре отдам текущим контрибьюторам.


Словарь

Node — нода — узел с каким либо ресурсом
Content — контент — данныe
Traffic — трафик — запрос/ответ, данные которые передаются от сервера клиенту и наоборот
Hardware — железо — аппаратная часть
Instance — инстанс — созданный объект какой либо сущности. Например инстанс сервера API
Headers — хедеры — заголовки (как правило TCP пакета, но может быть и HTTP запроса)



Производительность (Performance) vs масштабируемости (Scalability)

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


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


Дополнительный материал



Задержка (Latency) vs Пропускная способность (Throughput)

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

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

В общем случае, следует стремиться достигнуть максимальной пропускной способности при допустимой латентности.


Дополнительный материал



Доступность (Availability) vs (Консистентность) Consistency


CAP теорема

e49uqtbt1fk--gfohniay4ef_3i.png

В распределенных системах, вы сможете гарантировать только две вещи из трёх:


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

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

CP — (consistency and partition tolerance) — Консистентность + устойчивость к разделению
В такой системе, в результате ожидания ответа от ноды, можно получить timeout (истечение времени ожидания). Такой подход отлично подходит для систем в которых требуется соблюдение атомарности операций. Например транзакций в банке. Нельзя купить, что-то, не успев пополнив счет.

AP — (availability and partition tolerance) — Доступность + устойчивость к разделению
Ответы возвращают наиболее свежие данные доступные ноде, но они могут быть не самыми свежими в целом. Запись данных в распределенных системах занимает некоторое время (необходимо сделать множество копий между несколькими базами данных), поэтому данные могут появится не сразу.

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


Дополнительный материал



Паттерны консистенции

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


Слабая консистенция

После записи, читатель может увидеть записанное, а может и не увидеть. Здесь применяется метод best effort (A best effort approach is taken)

Данный подход можно наблюдать в таких системах как memcached. Слабая консистенция отлично подходит для использования в real-time, например VoIP, видео чатах и мультиплеерных играх. Например, если вы разговариваете по телефону и потеряли связь на некоторое время, то вы не услышите то, что было сказано в этот момент времени.


Частичная консистенция

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

Этот подход часто используется в системах DNS и Email. Частичная консистенция отлично подходит для системы с высокой доступностью.


Сильная консистенция

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

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


Дополнительный материал



Паттерны доступности

Существует два главных паттерна для поддержки высокой доступности: отказоустойчивость и реплицирование.


Отказоустойчивость (Fail-over)

Активный-пассивный (Active-passive)
С таким подходом происходит отправка пульса (heartbeats) между активным и пассивным серверами. Если пульс прекращается, то пассивный сервер берет на себя обязанности активного сервера переключая IP адреса на себя.
Время простоя (downtime) зависит от того, как быстро пассивный сервер готов начать работу в качестве активного. Пассивный сервер может ожидать в горячем (hot) или холодном (cold) состоянии.

Пассивный сервер может убить активный сервер путем использования команды — shoot the other node in the head (STONITH), это метафорическая команда и может быть реализовано как угодно. Делается это для того, чтобы в системе не функционировало одновременно два активных сервера, так как это может привести к ошибкам.

Активный-пассивный отказоустойчивый подход может так же называться как master-slave — мастер-раб.

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

Если доступ к серверу выставлен наружу, то DNS должен знать IP адреса обоих серверов. Если сервера выставлены для внутреннего использования, то логика на уровне приложения должна знать об обоих серверах.

Активный-активный, может так же называться как — master-master — мастер-мастер.


Недостатки


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


Репликация

Master-slave и master-master
Мы рассмотрим эти два подхода в разделе про базы данных.



Система доменных имен (Domain name system)

zonaatqhzf1jmt7_dyjis6nequi.jpeg

DNS — преобразует доменное имя в IP адрес. Например www.example.com в 127.0.0.1.

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


  • NS-запись (name server) — определяет DNS сервер для вашего домена/субдомена.
  • MX-запись (mail exchange) — определяет почтовый сервис для принятия почты.
  • A-запись (address) — определяет IP адрес в виде доменного имени.
  • CNAME-запись (canonical) — определяет другое имя (example.com как www.example.com) или A-запись.

Такие сервисы как CloudFlare и Route 53 предоставляют управляемые DNS сервисы. Некоторые DNS сервисы могут направлять трафик, используя разные методы:


  • Взвешенное распределение трафика
    — Предотвращает попадание трафика на сервера, которые не способны принять запрос
    — Балансирует трафик между серверами
    — Позволяет проводить A/B тестирование
  • Распределение по задержке
  • Геораспределение


Недостатки DNS


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


Дополнительный материал



Сеть доставки контента (Content delivery network)

lcc5rsgvzw6tolpi_d9oov-lm9a.jpeg

Content delivery network (CDN) — это глобальная и распределенная сеть прокси серверов, предоставляющая контент пользователям в различных локациях по всему миру. Как правило, CDN хранит статичные файлы такие как HTML, CSS, JS, но есть сервисы которые хранят и динамичный контент.

Использование CDN улучшает производительность двумя способами:


  • Пользователи получают контент с ближайшего к ним CDN сервера
  • Сервер с приложением не тратит усилия на обработку таких запросов


Push CDN

Push CDNs получают новый контент каждый раз когда оно обновляется на сервере. В данном случае, пользователь CDN (разработчик) отвечает за обновление CDN серверов актуальным контентом. Можно настроить время по которому истекает актуальность контента или обновлять его только тогда когда появится новый.

Push CDN отлично подходит для сайтов с маленьким трафиком или для сайтов контент которых меняется не часто. Лучше один раз загрузить контент на CDN, чем выкачивать его с сервера на постоянной основе.


Pull CDN

Pull CDN выкачивает новые данные при первом обращении пользователя. Такой первый запрос как правило медленней последующих, так как требует получения данных с сервера. Следующие запросы уже будут закешированы CDN-ном и буду происходить быстрей.

TTL — time-to-live, определяет как долго контент будет храниться в кеше. Pull CDN позволяет уменьшить объем данных, который хранится на CDN, но тем самым может вызвать увеличение ненужного трафика на сервер, если данные на CDN устаревают раньше, чем они действительно становятся не актуальными на сервере.

Pull CDN отлично подходит сайтам с большим трафиком, так как количество обращений к закешированным данным гораздо больше.


Недостатки: CDN.


  • Контент на CDN может устаревать, если он обновляется раньше удаления кеша.
  • Необходимость изменение ссылок на новый контент.


Дополнительный материал:



Балансировщик нагрузки (Load balancer)

b7btnoay30hjnvlarpn86bb8vvw.png

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

Балансиры эффективны:


  • Когда нужно предотвратить обработку запроса не работающим сервером;
  • Когда нужно защитить ресурсы от чрезмерной нагрузки;
  • Когда нужно избежать единой точки отказа;

Балансиры могут быть реализованы с помощью железа (дорого) или программно например с HAProxy.

Дополнительные плюсы использования:


  • SSL терминация — расшифровка входящих запросов и шифровка ответов.
    — Сервера не будут тратить свои ресурсы.
    — Нет необходимости ставить сертификаты X.509 на каждый сервер
  • Хранение сессий — выдает куки пользователями и пытается направлять одного и тоже юзера на тот же сервер. Убирает необходимость хранить сессию на серверах, что в принципе и не должно происходить учитывая горизонтальное масштабирование, где инстансы одного и того же приложения запущены на множестве серверов.

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

Балансиры могут направлять трафик опираясь на следующие метрики:


Layer 4 балансировка

Данная балансировка работает на транспортном уровне, определяя как распределить запрос. Обычно используется IP адрес и порт источника и получателя в заголовке пакетов, но не в их содержимом. Балансиры направляют трафик с помощью Network Address Translation (NAT).


Layer 7 балансировка

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

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

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


Горизонтальное масштабирование (Horizontal scaling)

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

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


  • Представляет из себя непростую задачу
  • Сервера не должны хранить какое либо состояние, например сессии или изображения пользователей
  • Сессии и прочее должно храниться отдельно в базах данных (SQL, NoSQL) или в кеше (Redis, Memcached)
  • Кэширующие сервера должны обрабатывать большинство запросов


Недостатки:


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


Дополнительный материал



Реверс прокси (веб-сервер) — Reverse proxy (web server)

upyo5fqk9yulmbdafagwugbjdow.png

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

Дополнительные плюсы:


  • Повышенная безопасность — Прячет информацию о бекенд серверах, блокирует IP адреса, ограничивает количество соединений на клиента.
  • Масштабируемость и гибкость — Клиенты видят только прокси сервер, а внутренняя конфигурация может быть любой.
  • SSL терминация — Расшифровка входящих и шифровка исходящих пакетов в одном месте. Нет необходимости делать это на каждом сервере
  • Сжатие — Сжатие ответов
  • Кеширование — Возврат ответов на кэшированные запросы
  • Статический контент — Отдает статический контент напрямую
    — HTML/CSS/JS
    — Фото
    — Видео
    — Прочее


Балансировщик vs реверс прокси


  • Использование балансировщика полезно когда у вас несколько серверов. Чаще всего балансировщики используется для распределения нагрузки между серверами, которые выполняют одну и ту же задачу.
  • Реверс прокси может быть полезным даже с одним сервером и предоставлять описанные выше полезные возможности.
  • Такие решения как NGINX и HAProxy могут поддерживать layer 7 реверс прокси и балансировку нагрузки.


Недостатки:


  • Использование реверс прокси увеличивает сложность системы.
  • Использование одного реверс прокси сервера создает единую точку отказа. Решение этой проблемы увеличивает сложность системы.


Дополнительный материал



Слой / уровень приложения (Application layer)

b6mi6gr0fbevdjzqvqoq4dnp_du.png

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

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


Микросервисы — Microservices

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

Термин «Microservice Architecture» получил распространение в последние несколько лет как описание способа дизайна приложений в виде набора независимо развертываемых сервисов. В то время как нет точного описания этого архитектурного стиля, существует некий общий набор характеристик: организация сервисов вокруг бизнес-потребностей, автоматическое развертывание, перенос логики от шины сообщений к приемникам (endpoints) и децентрализованный контроль над языками и данными.

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

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

Для того, чтобы начать рассказ о стиле микросервисов, лучше всего сравнить его с монолитом (monolithic style): приложением, построенном как единое целое. Enterprise приложения часто включают три основные части: пользовательский интерфейс (состоящий как правило из HTML страниц и javascript-а), базу данных (как правило реляционной, со множеством таблиц) и сервер. Серверная часть обрабатывает HTTP запросы, выполняет доменную логику, запрашивает и обновляет данные в БД, заполняет HTML страницы, которые затем отправляются браузеру клиента. Любое изменение в системе приводит к пересборке и развертыванию новой версии серверной части приложения.

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

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

x-qintdkx1fzuxev_vgssn-ikpy.png

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

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


Свойства архитектуры микросервисов

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


Разбиение через сервисы

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

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

Архитектура микросервисов использует библиотеки, но их основной способ разбиения приложения — путем деления его на сервисы. Мы определяем библиотеки как компоненты, которые подключаются к программе и вызываются ею в том же процессе, в то время как сервисы — это компоненты, выполняемые в отдельном процессе и коммуницирующие между собой через веб-запросы или remote procedure call (RPS).

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

Другое следствие использования сервисов как компонент — более явный интерфейс между ними. Большинство языков программирования не имеют хорошего механизма для объявления Published Interface. Часто только документация и дисциплина предотвращают нарушение инкапсуляции компонентов. Сервисы позволяют избежать этого через использование явного механизма удаленных вызовов.

Тем не менее, использование сервисов подобным образом имеет свои недостатки. Удаленные вызовы работают медленнее, чем вызовы в рамках процесса, и поэтому API должен быть менее детализированным (coarser-grained), что часто приводит к неудобству в использовании. Если вам нужно изменить набор ответственностей между компонентами, сделать это сложнее из-за того, что вам нужно пересекать границы процессов.

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


Организация вокруг потребностей бизнеса

Когда большое приложение разбивается на части, часто менеджмент фокусируется на технологиях, что приводит к образованию UI команды, серверной команды и БД команды. Когда команды разбиты подобным образом, даже небольшые изменения отнимают много времени из-за необходимости кросс-командного взаимодействия. Это приводит к тому, что команды размещают любую логику на тех слоях, к которым имеют доступ. Закон Конвея (Conway’s Law) в действии.
«Любая организация, которая проектирует какую-то систему (в широком смысле) получит дизайн, чья структура копирует структуру команд в этой организации»
— Melvyn Conway, 1967

zwc12b8aesraduytpvswehs-row.png
Закон Конвея (Conway’s Law) в действии

Микросервисный подход к разбиению подразумевает раазбиение на сервисы в соответствии с потребностями бизнеса. Такие сервисы включают в себя полный набор технологий, необходимых для этой бизнес-потребности, в том числе пользовательский интерфейс, хранилице данных и любые внешние взаимодействия. Это приводит к формированию кросс-функциональных команд, имеющих полный набор необходимых навыков: user-experience, базы данных и project management.

hh2ue9lyzovbhobp0a387vddh6c.png
Сервисные границы, подкрепленные границами команд

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

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


Насколько большими должны быть микросервисы?

Хотя термин «Микросервис» стал популярным названием для этого архитектурного стиля, само имя приводит к чрезмерному фокусу на размере сервисов и спорам о том, что означает приставка «микро». В наших разговорах с теми, кто занимался разбиением ПО на микросервисы, мы видели разные размеры. Наибольший размер был у компаний, следовавших правилу «Команда двух пицц» (команда, которую можно накормить двумя пиццами), т.е. не более 12 человек (прим. перев.: следуя этому правилу, я в команде должен быть один). В других компаниях мы видели команды, в которых шестеро человек поддерживали шесть сервисов.
Это приводит к вопросу о том, есть ли существенная разница в том, сколько человек должно работать на одном сервисе. На данный момент мы считаем, что оба этих подхода к построению команд (1 сервис на 12 человек и 1 сервис на 1 человека) подходят под описание микросервисной архитектуры, но возможно мы изменим свое мнение в будущем. (прим. перев.: со времен статьи появилось множество других статей, развивающих эту тему; наиболее популярным сейчас считается мнение о том, что сервис должен быть настолько большим, чтобы он мог полностью «уместиться в голове разработчика», независимо от количества строк кода).


Продукты, а не проекты

Большиство компаний по разработке ПО, которые мы видим, используют проектную модель, в которой целью является разработка некой части функциональности, которая после этого считается завершенной. После завершения эта часть передается команде поддержки и проектная команда распускается.
Сторонники микросервисов сторонятся этой модели, утверждая, что команда должна владеть продуктом на протяжении всего срока его жизни. Корни этого подхода уходят к Амазону, у компании есть правило «вы разработали, вам и поддерживать», при котором команда разработки берет полную ответственность за ПО в продакшне. Это приводит к тому, что разработчики регулярно наблюдают за тем, как их продукт ведет себя в продакшне, и больше контактируют с пользователями, т.к. им приходится брать на себя как минимум часть обязанностей по поддержке.
Мышление в терминах продукта устанавливает связь с потребностями бизнеса. Продукт — это не просто набор фич, которые необходимо реализовать. Это постоянные отношения, цель которых — помочь пользователям увеличить их бизнес-возможности.
Конечно, этого можно также достичь и в случае с монолитным приложением, но высокая гранулярность сервисов упрощает установку персональных отношений между разработчиками сервиса и его пользователями.


Умные приемники и глупые каналы передачи данных (Smart endpoints and dumb pipes)

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

Комьюнити микросервисов предпочитает альтернативный подход: умные приемники сообщений и глупые каналы передачи. Приложения, построенные с использованием микросервисной архитектуры, стремятся быть настолько незавимыми (decoupled) и сфокусировнными (cohesive), насколько возможно: они содержат собственную доменную логику и выступают больше в качестве фильтров в классическом Unix-овом смысле — получают запросы, применяют логику и отправляют ответ. Вместо сложных протоколов, таких как WS-* или BPEL, они используют простые REST-овые протоколы.

Два наиболее часто используемых протокола — это HTTP запросы через API ресурса и легковесный месседжинг. Лучшее выражение первому дал Ian Robinson: «Be of the web, not behind the web».
Команды, практикующие микросервисную архитектуру, используют те же принципы и протоколы, на которых построена всемирная паутина (и, по сути, Unix). Часто используемые ресурсы могут быть закешированы с очень небольшими усилиями со стороны разработчиков или IT-администраторов.

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

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


Децентрализованное управление

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

Разбивая монолит на сервисы, мы имеем выбор, как построить каждый из них. Хотите использовать Node.js для простых страничек с отчетами? Пожалуйста. C++ для real-time приложений? Отлично. Хотите заменить БД на ту, которая лучше подходит для операций чтения вашего компонента? Ради бога.

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

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

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

Комьюнити микросервисов ценит сервисные контракты, но не любит оверхеды и поэтому использует различные пути управления этими контрактами. Такие шаблоны как Tolerant Readerи Consumer-Driven Contracts часто используются в микросервисах, что позволяет им эволюционировать независимо. Проверка Consumer-Driven контрактов как часть билда увеличивает уверенность в правильности функционирование сервисов. Мы знаем ком

© Habrahabr.ru