Слои, звенья и цена уровней
Алексей рассказывает о себе: полтора года в инвестиционном направлении, где внедряет архитектурные практики и строит высоконагруженные системы для доступа клиентов к мировым рынкам, а до этого были инфраструктура, разработка ПО и видеостриминг в духе Twitch с возможностью заработка, который не взлетел. Сергей Иванов проектирует больше двадцати лет: онлайн-казино, «когда это ещё не было незаконным», банковские системы со сложным доменом, собственную инфраструктуру, которую собирали сами, во времена, когда про облака не знали; с 2019 года проводит конференцию по архитектуре и больше года назад участвовал в создании архитектурной ассоциации, где спор о том, как назвать практикующего консультанта, который в ней состоит, упёрся в одну из главных проблем разработки — именование. Книгу участники хвалят за то, что термин появляется посреди повествования и авторы ссылаются на работы, где он вводился. Минус тот же: вырвать определение из контекста трудно, и один из участников признаётся, что при конспектировании просто переписывает текст — настолько всё концентрированно.
Архитектура у авторов — это то, из каких компонентов состоит система, как они связаны и взаимодействуют; рядом стоят промежуточный слой, отделяющий приложения от нижележащих платформ, и системная архитектура, то есть развёртывание на реальных машинах, до которого, замечает один из ведущих, на систем-дизайн-интервью редко успевают дойти. Слои — разделение логическое, звенья — физическое, и определение строится на противопоставлении; те же компоненты могут ужиться в одном процессе, если приложение собрано из слабо связанных кусков с внутрипроцессным или сетевым транспортом. Слой описывается тройкой «интерфейс — сервис — протокол», пример — сетевые стеки. Плюсы: реализации взаимозаменяемы, а тестировать слои проще, чем одну огромную конструкцию. Минус — цена пересечения границ: заголовки и преобразования данных на десятке слоёв могут стоить дороже полезной работы, отсюда сжатие заголовков, буферизация и попытки вроде HTTP/2 и QUIC, плюс административная плата за поддержку каждого протокола.
Удалённые вызовы, микросервисы и события
Классическую трёхуровневую схему участники пролистывают — с неё все когда-то начинали — и идут в сервис-ориентированные стили, где авторы смешали объектные архитектуры, микросервисы и REST. Удалённый вызов методов вспоминают без нежности: дёргаешь локальный метод, а исполняется он на другой машине; тестовую среду под такое построить почти невозможно, задержки постоянные, и от этого великолепия быстро ушли к обмену сообщениями. Один из участников оговаривается: виноват мог быть не подход, а исполнение — middleware тогда, вероятно, писали плохо, и при хорошей реализации идея имела бы право на жизнь. Проблема, по мнению участников, в ложных гарантиях: middleware прячет и сложность, и идемпотентность вызовов, разработчик пишет код так, будто процесс падает целиком, а ждёт на порядок дольше и ловит ошибки там, где их не ждал. Ментальная модель не меняется между локальным и удалённым вызовом, поэтому даже настроить приложение нормально не выходит: непонятно, где оно стоит.
Один из ведущих связывает это с когнитивной сложностью из книги о философии дизайна ПО, которую читает параллельно: сложность, спрятанную под гарантии, прорывает в самом неудобном месте — идёшь по красивому тонкому льду, проваливаешься, тебя сносит течением, а зная про глубину, ты бы построил мост. Микросервисы участники выводят из объектно-ориентированного дизайна: композиция большого сервиса из мелких, где ключ — модульность и логические границы; сначала делили как придётся, а когда стало тяжело, на помощь пришёл DDD. В книге про них всего один блок, зато по делу: соглашения о размере нет, важны отдельные процессы, возможно на разных машинах, и независимость сервисов. Претензия к главе тоже есть — REST вынесен отдельным стилем, хотя микросервис спокойно отдаёт и RPC, и REST; сам REST хвалят за понятный человеку набор ресурсов и операций и за то, что состояние хранит клиент. Оттуда же и клиентские композиции: главным потребителем стал человек, а не компьютер.
Middleware, звенья, облака и блокчейн
Таблица связанности раскладывает взаимодействие по ссылочной и временной осям: прямой вызов связан по обеим, почтовый ящик конкретного получателя развязывает время, событийная шина — ссылку, а самый развязанный угол — разделяемое пространство данных, для которого приводят бытовой пример с файловой шарой, куда коллеги складывают файлы и раз в день заглядывают. Подписка бывает по топику, по ключу и по содержимому: в книге подписываются на события с координатами внутри географической области, а рабочий пример звучит из инвестиций — событие «портфель обновлён», и сервис сам решает, интересны ли ему облигации или акции. Тут же вспоминают техническое ограничение популярных брокеров: топик на каждого из трёх миллионов клиентов физически не заведёшь, поэтому приложения читают весь поток и проверяют каждое событие. Middleware авторы описывают как операционную систему распределённой системы: управление ресурсами, общение приложений, безопасность и учёт потреблённых ресурсов. Расширяют middleware обёртками и перехватчиками: обёртки между всеми парами приложений дают полносвязный граф, который замучаешься писать, брокер сводит схему к звезде, а современный пример перехвата — service mesh, который берёт на себя безопасное взаимодействие и обнаружение сервисов и умеет, например, взаимную аутентификацию по доверенным ключам.
В системных архитектурах авторы разделяют вертикальное деление по функциям и горизонтальное, где ноды одинаковы, но держат разные части данных — как разнесение столбцов против шардирования в базах. Классических звеньев три, но в жизни доходит до восьми-девяти: клиентский запрос в инвестициях проходит миллион приложений и транспортов по пути к бирже. Симметричные сети, где узел одновременно клиент и сервер, разделяют на структурированные, чья топология требует администратора, и неструктурированные, которые живут на нестабильном составе и распространении через gossip. Последнюю треть проходят бегом: облако даёт пул ресурсов и эластичность, но остаются вопросы цены, гарантий и мощностей в нужном регионе, а сервисы лучше брать с ванильной установкой; edge придвигает вычисления к клиенту, где сотня миллисекунд задержки для беспилотника уже критична, а Amazon готов привезти стойки прямо к заказчику; в блокчейне участники подчёркивают неизменяемость цепочки — и вспоминают, как в Google File System изменяемые чанки на границе разных мастеров заставляли делать распределённые транзакции, а в Colossus их сделали неизменяемыми.
Что стоит унести с собой
- 01Слои — разделение логическое, звенья — физическое; взаимозаменяемость и простота тестирования оплачиваются заголовками, а на десятке слоёв пересечение границ дороже полезной работы.
- 02Удалённый вызов, притворяющийся локальным, даёт ложные гарантии: ментальная модель не меняется, идемпотентность спрятана в middleware, а ошибки и задержки приходят там, где их не ждут.
- 03Про микросервисы в книге одна страница, но по делу: соглашения о размере нет, важны отдельные процессы и независимость, а логические границы помогает найти DDD.
- 04Неизменяемость упрощает распределённый дизайн: в Google File System изменяемые чанки на границе разных мастеров требовали распределённых транзакций, в Colossus чанки сделали неизменяемыми.