Слои, модель OSI и типы коммуникаций
Антон представляется первым: больше десяти лет опыта, языки менялись — были C++, Java, C#, JavaScript, последние несколько лет основной Scala, — а сейчас он выступает в роли архитектора в привлечении Тинькофф Бизнеса. Артём делает сервисы, которые отвечают, можем ли мы вообще предложить человеку продукт и на каких условиях, а учился по специальности про системы связи, так что глава про коммуникации ему близка по профилю. Перед разбором участники вспоминают второй кирпич Таненбаума — про компьютерные сети: по словам одного из них, книга дошла до шестого издания в двадцать первом году, туда дописали про Wi-Fi и телеком, а соавторов у неё становится всё больше — иначе такой объём не удержать актуальным. Сама глава начинается со слоёв, и сразу всплывает модель OSI: аббревиатуру никто с ходу не расшифровал, и это честно — книга тут же пишет, что протоколов под неё так и не появилось.
Практичнее выглядит четырёхуровневая модель: физический уровень, покрывающий первые два уровня OSI, network с роутингом и IP, транспорт с TCP и приложение, вобравшее верхние уровни. Смысл слоя в том, что он добавляет к сообщению свой заголовок, чтобы следующий понял, куда отправлять дальше; полезная нагрузка при этом может быть маленькой, а сборка и разбор заголовков не бесплатны и в некоторых случаях бьют по перформансу. У автора тоже четыре уровня, но в middleware он выносит DNS, авторизацию и распределённый коммит — всё, поверх чего мы пишем приложение, — а ниже кладёт уровень операционной системы. Вывод участников: важно не помнить, семь уровней или четыре, а понимать, зачем слои и какие сервисы они дают соседу сверху. Дальше коммуникации делятся на transient, где клиент дождался подтверждения и забыл про сообщение, и persistent, где запрос лежит в промежуточном хранилище, пока получатель за ним не придёт, — понятный пример второго варианта авторы берут из почты.
RPC: заглушки, повторы и прозрачность
На диаграммах жирными линиями показано, где клиент заблокирован, где ему приходит промежуточное подтверждение доставки, а где он отправил запрос и пошёл дальше, чтобы получить ответ колбэком или вовсе не получить. Вторую часть главы открывают историей: сначала в распределённых системах явно передавали сообщения, а в восьмидесятых предложили смотреть на это как на вызов удалённой процедуры — и RPC, отмечают участники, используется повсеместно по сей день. Антон разбирает локальный вызов: параметры кладутся на стек, управление уходит в процедуру, результат возвращается тем же путём, и именно эту картинку надо держать в голове, потому что ломаться будет она. Большой список локально удобно передать по ссылке, чтобы не копировать его целиком; есть и стратегия с копированием и возвратом значения обратно. Удалённо указатель не передашь: появляются маршалинг, единый формат и заглушки клиента и сервера, которые генерируются по описанию интерфейса.
Второй подход — RMI с передачей ссылок на удалённые объекты; примера другого языка со встроенным RPC никто не вспомнил, а к RMI у участников претензии по безопасности: на умолчаниях легко получить серьёзную уязвимость. Приходит вопрос от слушателя про обрыв соединения: обрабатывать его придётся на клиенте — таймауты, отсутствие ответа, при необходимости повторы, причём механизма ретраев, зашитого прямо в заглушку, один из участников не встречал и считает идею так себе. Повторы тянут идемпотентность: ключ, который не меняется при ретрае, чтобы сервер узнал дубль, — но попасть надо на тот же сервер, а он должен ключ ещё и помнить. Fault tolerance, по их прикидкам, ждёт в восьмой главе. Антон формулирует обратную сторону прозрачности: разработчик забывает, что сеть ненадёжна по определению, открывает транзакцию и уходит по сети — транзакция висит, коммиты стоят, система работает плохо. Один из ведущих поддерживает книгой про философию дизайна: модель «удалённый вызов неотличим от локального» обманчива, потому что обещание не выполняется.
Брокеры, Kafka и рассылка слухов
Из вариаций RPC разбирают асинхронный вызов с колбэком и мультикаст, когда зовут несколько серверов и берут либо все ответы, либо самый быстрый; участники узнают в этом чтение из реплик с кворумом «половина плюс один» и правкой разошедшихся значений прямо при чтении, что душит производительность. Третья часть — про явный обмен сообщениями, который нужен, когда вызываемый процесс недоступен. От сокетов, где транспорт даёт только «слушать» и «послать», поднимаются к ZeroMQ с его request-reply, publish-subscribe и pipeline: request-reply — тот же RPC, только через очередь, а сообщения можно слать ещё до установки соединения. Дальше MPI: ведущий вспоминает, как году в 2005 считал так матрицы на кластере и код выходил не по-человечески. Главное в MPI — модель отказа: при сбое программа просто умирает, потому что сеть кластера считается быстрой и надёжной, и если это семь девяток, а результат нужен к завтрашнему дню, расчёт проще перезапустить.
Антон вспоминает университетский курс параллельных вычислений, где параллельность в пределах машины и обмен по сети были разными фреймворками. Дальше появляются менеджеры очередей с адресацией, роутингом и справочником «кто где живёт», а за ними брокер: N участников со своими диалектами дают квадратичное число переводчиков, а с брокером каждому нужен один маппинг в его формат плюс плагины, в том числе для трансляции протоколов. Отступлением, которого в книге нет, разбирают Kafka: это не брокер, а журнал, порядок есть внутри партиции, но не внутри топика, а консьюмеров в группе не больше, чем партиций. Последнюю часть про мультикаст участники называют эзотерической: своих таких систем почти никто не писал. Артём разбирает дерево рассылки, ломающееся вместе с узлом, флудинг по ближайшим соседям и вероятностный gossip, экономящий сеть ценой недостигнутых узлов. Удаление ломает схему: вернувшийся узел разносит данные заново, поэтому рассылают маркер — «свидетельство смерти». Через неделю — пятая глава.
Что стоит унести с собой
- 01Слои нужны не ради семи букв OSI, а ради интерфейса для соседа сверху: каждый уровень добавляет свой заголовок, и сборка с разбором этих заголовков стоит перформанса.
- 02RPC прячет сеть, но не отменяет её: обрывы, таймауты и повторы остаются на клиенте, а безопасный повтор требует ключа идемпотентности и сервера, который этот ключ помнит.
- 03Брокер выигрывает арифметикой: вместо квадратичного числа переводчиков между N участниками каждому хватает одного маппинга в формат брокера, а сверху добавляются плагины.
- 04Модель отказа — часть дизайна протокола: MPI позволяет себе умереть на сбое, потому что рассчитан на быструю надёжную сеть кластера, а gossip мирится с недостигнутыми узлами ради разгрузки сети.