Deep Engineering

System Design

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

Разделы
6
Статьи
8
ИСТОЧНИКОВ
67
Сложность
8 статей · подходит

Разделы

Статьи

ПродвинутыйОпубликованоBackend for Frontend: слой, который знает, кто спрашиваетПаттерн описали в 2015 году ради скорости и автономии команд. Через одиннадцать лет черновик IETF стал настойчиво рекомендовать его ради того, о чём его авторы не писали, — чтобы токен вообще не попадал в браузер.bffapi-designweb-securityfrontend-backendcsrf30 МИН12 ИСТОЧНИКОВЧитать →ПродвинутыйОпубликованоРастянутый кэш на два датацентра: почему аналогия с базой ложная«База же у нас растянута репликами, и ничего» — про базу это правда, но «растянуть» у базы и у кэша означает разное. Кэш держится сравнительным свойством: поход в него должен обходиться дешевле операции источника, которую он заменяет. На дешёвом чтении по ключу за каналом между ДЦ этого не остаётся — 41,09 мс против 0,09 мс до базы под рукой. А кластер, разложенный по датацентрам поровну, при разрыве отказал в обеих половинах сразу, включая ту, у которой большинство голосов. Заодно здесь проверен сам измерительный стенд — и оказалось, что одно из опубликованных чисел мерило не расстояние, а дефект прибора.redisvalkeycachingreplicationredis-cluster80 МИН10 ИСТОЧНИКОВЧитать →ПродвинутыйОпубликованоДва способа собрать Valkey из нескольких узлов: кластер и SentinelРазница между ними не в отказоустойчивости — она есть у обоих. Различают их четыре вещи разом: как разложены данные, кто принимает решение о переключении, кто отвечает клиенту на вопрос «куда слать команду» и что для этого должен уметь сам клиент. Плюс пятое измерение, о котором забывают чаще всего: версия. Правило «в кластере база ровно одна» верно для Redis и Valkey до 9.0 и неверно для Valkey 9 — и здесь это перемерено на двух кластерах, отличающихся одной строкой конфига.valkeyrediscachingclusteringsentinel60 МИН8 ИСТОЧНИКОВЧитать →ПродвинутыйОпубликованоУровни изоляции: цена SERIALIZABLE — это повторы, а не медленный запросТаблица из стандарта описывает, что уровню запрещено пропускать, а не что он пропускает у вас. PostgreSQL расходится с ней в обе стороны сразу: фантом на REPEATABLE READ не проходит, хотя стандарт его там разрешает, — а write skew проходит целиком, и этой аномалии в таблице нет вовсе. Замер добавляет второе: в этой нагрузке REPEATABLE READ и SERIALIZABLE неразличимы между собой — разница между ними меньше разброса между кругами, — а цена платится повторами.postgresqltransactionsisolation-levelsserializablewrite-skew30 МИН2 ИСТОЧНИКОВЧитать →ПродвинутыйОпубликованоTransaction outbox: что он гарантирует, чего не гарантирует и во что обходитсяСобытие становится строкой той же базы, и тогда у него та же судьба, что у заказа. Дальше начинается интересное: релей, который помнит номер последней отправленной строки, теряет события молча, а обещанный порядок доставки паттерн не даёт — ни через опрос таблицы, ни через чтение WAL.outboxpostgresqlcdckafkaidempotency30 МИН9 ИСТОЧНИКОВЧитать →ПродвинутыйОпубликованоШардирование: ключ решает, куда идёт каждый запросРазложить данные по узлам — половина дела; вторая половина — то, что после этого перестаёт работать. Здесь посчитано и измерено на живом PostgreSQL: при переходе с восьми шардов на девять деление по модулю перевозит 88,9 % ключей, а минимум — 11,1 %; на стенде с postgres_fdw запрос без ключа шардирования платит пять обменов с каждым шардом, и две настройки совмещают из них только два; транзакция через postgres_fdw, задевшая два шарда, оставила строку после ошибки у клиента в трёх случаях из четырёх.shardingpartitioningpostgresqlpostgres-fdwconsistent-hashing50 МИН7 ИСТОЧНИКОВЧитать →ПродвинутыйОпубликовано3.13DI-контейнер: что он делает вместо вас — и чем dishka отличается от dependency-injectorКонтейнер решает не «уменьшить связанность», а две конкретные задачи: собрать граф объектов и провести границу времени их жизни. Главное расхождение двух библиотек — на второй. Из этого следует и то, что два репозитория одного запроса окажутся в разных транзакциях, и то, кто быстрее — ответ на второй вопрос зависит от первого.dependency-injectiondi-containerdishkadependency-injectorscopes25 МИН6 ИСТОЧНИКОВЧитать →ПродвинутыйОпубликованоБалансировка нагрузки: кто выбирает сервер и что он в этот момент знаетЧем раньше принято решение, тем меньше о нём известно. DNS выбирает сервер за минуты до запроса и не знает про него ничего; L7-балансировщик выбирает в момент запроса и знает всё. Из этого следует и разделение слоёв, и главный результат модели очередей: least connections и least response time — лучший выбор ровно до тех пор, пока сигнал о загрузке свежий.load-balancingdnsl4l7power-of-two-choices45 МИН13 ИСТОЧНИКОВЧитать →

Рекомендуемый порядок

Граф знаний

НЕЛИНЕЙНО · С УЧЁТОМ ПРЕДПОСЫЛОК

Темы связаны между собой, и связи здесь не нарисованы, а посчитаны: каждая статья сама называет, на что опирается и с чем соседствует, а картинка собирается из этих названий. Пунктирный кружок — тема, которую статьи уже называют связанной, но которая ещё не написана.

9 · 7 вершин и связей

Связи списком

Без связей: di-containers