Принципы проектирования систем: масштабируемость, надёжность и производительность
Проектирование систем — это процесс определения архитектуры, компонентов, модулей, интерфейсов и данных системы для удовлетворен ия заданных требований.
1. Сбор требований
Перед проектированием любой системы критически важно понять ограничения:
- Функциональные требования: Что система делает (например, «Пользователь может отправить сообщение»).
- Нефункциональные требования: Как система работает (например, «Обрабатывать 10k RPS», «99.9% доступность», «Низкая задержка»).
2. Стратегии масштабирования
Вертикальное масштабирование (Scaling Up)
Увеличение мощности одной машины (больше CPU, RAM, SSD).
- Плюсы: Просто, без архитектурных изменений.
- Минусы: Ограничено аппаратными возможностями, дорого, единая точка отказа.
Горизонтальное масштабирование (Scaling Out)
Добавление новых машин в пул и распределение нагрузки.
- Плюсы: Практически неограниченный рост, высокая отказоустойчивость.
- Минусы: Требует балансировщик нагрузки и усложняет архитектуру (распределённое состояние).
3. Масштабируемость баз данных
- Репликация: Копирование данных на несколько узлов (Master-Slave/Leader-Follower). Запись идёт в Master, чтение — из Slave.
- Шардирование: Разделение данных по нескольким независимым серверам баз данных на основе ключа шардирования (например, User ID).
- Партиционирование: Разделение больших таблиц на более мелкие логические части в пределах одного экземпляра базы данных.
4. Метрики производительности и закон Литтла
- Задержка (Latency): Время обработки одного запроса.
- Пропускная способность (Throughput): Количество запросов, обработанных за единицу времени.
- Конкурентность (Concurrency): Количество запросов, обрабатываемых одновременно.
Закон Литтла: Concurrency = Throughput × Latency.
Если увеличивать количество параллельных запросов (конкурентность) без увеличения пропускной способности, задержка бу дет расти.
5. Паттерны отказоустойчивости
Circuit Breaker
Предотвращает каскадные отказы, «разрывая» соединение с неисправной зависимостью и возвращая быстрый fallback-ответ.
Back Pressure
Система отклоняет новые запросы (например, HTTP 429), когда перегружена, вместо того чтобы позволять очередям расти бесконечно и приводить к аварии.
Идемпотентность
Гарантирует, что несколько одинаковых запросов дают тот же эффект, что и один. Критически важна для повторных попыток при сбоях сети (например, платежи).
6. Снижение хвостовой задержки (P99)
Хвостовая задержка — это высокая задержка, с которой сталкивается небольшой процент запросов.
- Hedged Requests: Отправка одного и того же запроса на несколько реплик и использование первого полученного ответа.
- Request Coalescing: Объединение одинаковых одновременных запросов в один вызов к бэкенду.
- Jittering: Добавление случайных задержек к запланированным задачам для предотвращения проблемы «thundering herd».
- Deadline Propagation: Передача максимального ограничения по времени всем подсервисам.
7. Распределённые транзакции
- 2PC (Two-Phase Commit): Синхронный, блокирующий, обеспечивает строгую согласованность, но плохо масштабируется.
- Паттерн Saga: Последовательность локальных транзакций с компенсирующими действиями при сбоях. Обеспечивает конечную согласованность и высокую масштабируемость.
- TCC (Try-Confirm-Cancel): Паттерн на основе резервирования, распространённый в финтехе.
8. Модели согласованности
- Строгая согласованность (Strong Consistency): Каждое чтение видит последнюю запись (например, банковские системы).
- Конечная согласованность (Eventual Consistency): Реплики в конечном счёте придут к единому состоянию, но временно могут показывать устаревшие данные (например, лайки в социальных сетях).
- Линеаризуемость (Linearizability): Операции выглядят мгновенными и упорядоченными.