Глава 1 Надежные, масштабируемые и удобные в сопровождении приложения

Подходы к работе над информационными системами

Книга
Высоконагруженные приложения. Программирование, масштабирование, поддержка

Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems

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

Программа вечера

Об авторе

Мартин Клеппман

Мартин Клеппман

Martin Kleppmann — исследователь распределённых систем, ИТ-предприниматель, доцент Кембриджского университета

  • Rapportive (2010) — плагин для Gmail: показывал профили людей из соцсетей прямо в почте. Куплен LinkedIn в 2012 ↗
  • Go Test It — платформа для проверки веб-приложений в разных браузерах и на разных платформах. Куплена Red Gate Software в 2009 ↗
  • После сделки несколько лет работал в LinkedIn над инфраструктурой обработки больших объёмов данных на Apache Kafka и Samza.
  • Кембридж — преподаёт криптографию, распределённые системы и компьютерную безопасность; с 2024 года — Associate Professor.
  • CRDT ↗Придумал не он. Конфликт-свободные реплицируемые типы данных ввели Марк Шапиро, Нуну Прегиса, Карлуш Бакеру и Марек Завирски в 2011 году. Клеппман их исследует и формально верифицирует, а справочник crdt.tech ведёт вместе с Шапиро и Аннетт Бениусой. — алгоритмы, позволяющие обновлять данные на разных устройствах одновременно без конфликтов (как в Google Документах, где текст правят несколько человек сразу).
  • Automerge ↗Один из создателей. Открытый движок синхронизации для многопользовательских приложений: работает офлайн, сливает правки без конфликтов и помнит каждое изменение. — библиотека с открытым исходным кодом, на которой такие приложения и строят.
  • Local-first ↗Соавтор манифеста. Эссе «Local-First Software: You Own Your Data, in spite of the Cloud» (Ink & Switch, 2019) — вместе с Адамом Уиггинсом, Питером ван Харденбергом и Марком Макгранаханом. — подход, ради которого нужны CRDT: данные лежат на устройстве и работают без интернета, но синхронизируются при сети.
  • Bluesky ↗Советник и исследователь. Соавтор рецензируемой статьи об AT Protocol — открытом протоколе, на котором работает сеть (2024). — децентрализованная социальная сеть, которой он помогает как советник.
Высоконагруженные приложения. Программирование, масштабирование, поддержка

Культовый статус в мире ИТ ему принесла книга «Высоконагруженные приложения» (Designing Data-Intensive Applications): она разошлась сотнями тысяч экземпляров и стала главным учебником по архитектуре баз данных для разработчиков по всему миру.

  • Объединяет сложную академическую теорию и реальную практику крупных ИТ-компаний.
  • Написана понятным языком, со схемами, и не продвигает одну технологию — ни только SQL, ни только NoSQL.
  • Учит мыслить компромиссами: понимать, чем мы жертвуем — скоростью, надёжностью или консистентностью данных, — выбирая тот или иной архитектурный подход.

Виды приложений

Высоконагруженные даннымиdata-intensive

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

Узкое место

Чистая производительность CPU — просто ограничивающий фактор. Основная проблема — объём данных, их сложность и скорость изменения.

Высоконагруженные вычислениямиcompute-intensive

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

Узкое место

Процессор: задача упирается в количество вычислений.

Алан Кей
«Интернет настолько хорош, что большинство людей считает его природным ресурсом, таким как Тихий океан, а не чем-то сотворённым руками человека. Когда в последний раз в технологии подобного масштаба не было ни одной ошибки?» Алан Кей, из интервью Dr. Dobb’s Journal (2012) · эпиграф к главе 1
фото: Marcin Wichary, CC BY 2.0

Спойлер

Две главные мысли, которые будут раскрыты дальше.

01

Важна задача,
а не инструмент

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

Один и тот же инструмент может решать разные задачи, а разные инструменты — похожие задачи.

02

Разработчик —
архитектор

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

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

Нет «одного правильного инструмента»

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

Базы данных PostgreSQL PostgreSQL — реляционная СУБД с открытым исходным кодом. Транзакции, надёжное хранение на диске, JSON, полнотекстовый поиск. Классический «источник правды» приложения. MySQL MySQL — самая распространённая реляционная СУБД веба. Та же задача: хранить данные так, чтобы их потом можно было найти. MongoDB MongoDB — документная база: вместо строк и таблиц — JSON-документы. Схемы гибче, а задача та же — хранение и поиск. ClickHouse ClickHouse — колоночная аналитическая СУБД: миллиарды строк сканируются за секунды. Хранилище, заточенное под отчёты, а не под транзакции. SQLite SQLite — вся база в одном файле рядом с приложением. Сервера нет, но задача та же: хранить и отдавать данные по запросу.
Кэш Redis Redis — хранилище структур данных в памяти: строки, списки, множества, потоки. Отвечает за микросекунды, поэтому чаще всего стоит перед базой как кэш. Memcached Memcached — кэш в чистом виде: ключ, значение, время жизни. Ничего не хранит на диске и не умеет ничего, кроме быстрых чтений. Couchbase Couchbase — вырос из memcached: тот же протокол кэша в памяти, но с диском и документной моделью. Hazelcast Hazelcast — распределённый кэш в памяти: данные размазаны по узлам кластера, приложение работает с ними как с обычной коллекцией.
Очереди сообщений Apache Kafka Apache Kafka — распределённый журнал событий: сообщения пишутся на диск в порядке поступления и раздаются множеству независимых потребителей. RabbitMQ RabbitMQ — брокер сообщений с маршрутизацией: очереди, обменники, подтверждения доставки. Классика асинхронного обмена между сервисами. NATS NATS — лёгкая шина сообщений: минимум гарантий по умолчанию, зато миллионы сообщений в секунду и простая эксплуатация. Apache Pulsar Apache Pulsar — брокер сообщений, у которого хранение вынесено в отдельный слой: подписки, очереди и потоки в одном сервисе. Amazon SQS Amazon SQS — очередь как облачный сервис: своего сервера нет, платишь за сообщения. Та же задача — передать работу другому обработчику.
MySQL MySQL — только хранение: строки, таблицы, транзакции. Очередью и кэшем быть не пытается. MongoDB MongoDB — документное хранилище. Данные отдаёт быстро, но роль кэша или брокера на себя не берёт. ClickHouse ClickHouse — аналитическое хранилище: миллиарды строк для отчётов. Чистая база и ничего кроме. SQLite SQLite — база в одном файле рядом с приложением. Ни кэша, ни очередей — только хранение.
Memcached — единственный здесь, кто остался чистым кэшем: ключ, значение, TTL, ничего на диске.
RabbitMQ RabbitMQ — брокер с маршрутизацией: доставил сообщение и забыл. Хранилищем данных не притворяется. Amazon SQS Amazon SQS — облачная очередь: сообщения приходят и уходят, читать историю заново нельзя.
Couchbase Couchbase вырос из memcached: тот же протокол кэша в памяти — плюс диск, индексы и документная модель. Кэш и база одновременно.
Apache Kafka Apache Kafka хранит сообщения столько, сколько нужно, и умеет транзакции: очередь, из которой можно перечитать всю историю, — по надёжности уровень базы данных. PostgreSQL PostgreSQL с SKIP LOCKED и LISTEN/NOTIFY раздаёт задачи обработчикам: обычная база работает как очередь. Apache Pulsar Apache Pulsar держит сообщения в отдельном слое хранения и уводит старые в объектное хранилище — очередь с архивом на годы.
Hazelcast — кэш в памяти, у которого есть очереди, топики и надёжные задания: кэш и брокер в одном процессе.
Redis Redis — кэш в памяти, персистентность на диск (AOF/RDB) и потоки с группами потребителей. Все три роли сразу. NATS NATS с JetStream: шина сообщений, хранение потоков и KV-хранилище с кэшем — тоже все три роли сразу.

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

Требования стали такими жёсткими и широкими, что отдельная утилита уже не способна обеспечить все потребности приложения. Работа разбивается на задачи — каждую эффективно решает свой инструмент.

API Клиентские запросы Код приложения Кэш в оперативной памяти Redis Запросы на чтение сначала проверяют, не кэшированы ли данные Неудачные обращения к кэшу и записи в кэш Основная база данных PostgreSQL Полнотекстовый индекс Elasticsearch Запросы на поиск Очередь сообщений Apache Kafka Асинхронные задачи Код приложения Например, отправка сообщений электронной почты «Внешний мир» Код приложения Перехват изменений в данных Применение изменений к поисковому индексу Сделать кэш недействительным или обновить Redis — хранилище структур данных в памяти. Здесь стоит перед базой как кэш: отвечает за микросекунды и снимает с базы повторяющиеся чтения. PostgreSQL — реляционная СУБД с транзакциями и надёжным хранением на диске. Здесь это источник правды: всё остальное — производные от неё представления. Elasticsearch — поисковый движок на инвертированном индексе: полнотекстовый поиск, фильтры и агрегации, которых обычная база так быстро не даёт. Apache Kafka — распределённый журнал событий. Сюда складываются асинхронные задачи, а разбирают их отдельные обработчики в своём темпе.

Эти компоненты нужно грамотно связать

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

Пользователь меняет имя в профиле
Приложение код, который всё связывает
основное хранилище PostgreSQL Аня
кэш Redis Аня
Клиент видит Аня

Пока данные согласованы: в хранилище и в кэше одно и то же имя, клиент видит его же.

Разработчик думает как архитектор

К этому приводит простая цепочка — и вместе с ней появляются три свойства системы, о которых теперь приходится думать в первую очередь.

01 Разные задачи
02 Разные инструменты
03 Несколько компонентов в одной системе
04 Компоненты не знают бизнес-логику друг друга
05 Код приложения должен их связать
06 Разработчик = архитектор

За что теперь отвечает разработчик

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

Надёжность

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

Масштабируемость

Должны быть предусмотрены разумные способы решения возникающих при росте системы проблем — росте в смысле объёмов данных, трафика или сложности.

Удобство сопровождения

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

Итог

Главная цепочка доклада — от инструмента к системе.

01 Нет «одного правильного инструмента»

Границы между категориями размылись: Redis — хранилище в роли очереди, Kafka — очередь с надёжностью базы данных. Смотрим не на ярлык, а на задачу, которую инструмент решает в конкретной архитектуре.

02 Система из нескольких компонентов

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

03 Их нужно грамотно связать

Инструменты не знают друг о друге: изменили имя в PostgreSQL — Redis остался со старым. Синхронизация — обязанность кода приложения, и цель не в том, чтобы сбоев не было, а в том, чтобы система из них корректно выходила.

04 Разработчик думает как архитектор

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

Мартин Клеппман

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

вывод по главе 1 книги «Высоконагруженные приложения» Мартина Клеппмана

Что далее

Артём Никифоров
Антон Помазков
Артём Никифоров