Всем привет!
Вчера провели встречу посвященая системному дизайну — зачем он нужен, как проводить интервью по нему, какие подходы считаются хорошими, а какие — не очень.
- Системный дизайн — не про создание YouTube с нуля, а про умение подходить к архитектуре решений адекватно: понимать, зачем ты проектируешь, какие есть ограничения, сколько пользователей и как это будет масштабироваться.
- Неправильный подход — сразу делать «миллиард пользователей и микросервисы».
- Правильный подход — начать с MVP, понимать, что будет меняться, где узкие места, и проектировать с возможностью постепенного роста.
🧪 Пример с телеграм-ботом:
- Сделан за 2 часа, с SQLite под капотом, без вебхуков (используется long polling).
- Простая реализация, которая работает, справляется со своей задачей. Когда нагрузка вырастет — заменят SQLite на PostgreSQL.
- Главный месседж: если знаешь, где слабые места, это окей — мониторь и улучшай по мере необходимости.
📈 Скейлинг и автоскейлинг:
- Что такое горизонтальное масштабирование (новые инстансы).
- Как определить, когда надо скейлиться — метрики (CPU, кол-во соединений).
- Примеры настройки автоскейлинга на AWS.
💬 Обсуждение API и архитектуры:
- Клиент-серверная модель: браузер — клиент, сервер — отвечает.
- API — это контракт взаимодействия, желательно публичный и документированный.
- SQLite хорош для простых приложений, но не для больших нагрузок.
🧵 Асинхронность, очереди, шины:
- Асинхронная обработка запроса: клиент отправил — сервер положил задачу в очередь.
- Уведомление о завершении задачи — через почту, пуш, или API polling.
- Шины сообщений (RabbitMQ, Kafka) — удобны для микросервисов и снижения связанности.
- Kafka используется для логирования и анализа, Rabbit — для событий и коммуникаций между сервисами.
🔄 Eventual Consistency и проблемы шины:
- Данные не синхронны — это нормально.
- Нужны механизмы переигрывания (реплей), контроля доставки, обработки неудачных сообщений.
- Сага — шаблон управления распределёнными транзакциями: как откатить, если шаг провалился.
🧱 Монолит vs микросервисы:
- Не надо уходить в микросервисы просто потому что модно.
- Сначала вырастите монолит, поймите, где границы, потом уже выносите в сервисы.
- Закон Конвея: архитектура повторяет оргструктуру.
- Проблема распределённого монолита — усложнение без выигрыша в независимости.
🧭 Domain-Driven Design (DDD):
- DDD — это про мышление бизнес-доменами, а не про базы данных.
- Разделение логики по бизнес-смыслу: в одной системе может быть понятие «пользователь» в разных контекстах (например, в биллинге и в доступах).
- Bounded Context — ключевое понятие: внутри него — свои модели, вне — взаимодействие через контракты (например, API).
“Нельзя взять модель одного сервиса и напрямую использовать в другом — лучше через API.”
🧩 Модульность и выделение сервисов:
- Пример: систему делят на сервис заказов, пользователей, биллинга и т.д.
- Между сервисами — минимальные связи, общение через API/шину событий.
- Вынос сервисов логичен, когда они эволюционно становятся самостоятельными.
- Не нужно «микросервисить» с самого начала — это усложнит всё.
🛑 Антипаттерны распределённых систем:
- Распределённый монолит: вроде бы микросервисы, но при этом жёсткие связи между сервисами, деплой одного влияет на другой.
- Отсутствие автономии — главный враг микросервисов.
- Ошибка начинающих: каждый микросервис имеет свою базу, но по сути — всё равно связан жёстко через логику.
💥 Разграничение ответственности:
- Надо разделять: кто отвечает за сохранение данных, кто за их обработку, кто за их показ.
- Важно, чтобы команды были привязаны к сервисам, а не к слоям (как фронтенд, бекенд, база).
🎨 Микрофронтенды:
• Очень больная тема. Теоретически позволяют разным командам независимо пилить фронт.
• На практике — огромная сложность:
- • Конфликты версий библиотек
- • Разные подходы к сборке, роутингу
- • Долгие загрузки и проблемы UX
“Проще использовать условно iframe, чем пытаться сшить всё красиво.”