Перейти к основному содержимому

Архитектура и Highload: масштабируемость, микросервисы и производительность

С ростом приложений возникают проблемы, связанные с производительностью, масштабируемостью и поддерживаемостью.

1. Монолит vs Микросервисы​

  • Монолит: единое приложение, в котором вся бизнес-логика тесно связана.
    • Плюсы: легко разрабатывать, тестировать и деплоить (на начальном этапе); простое горизонтальное масштабирование (дублируется всё приложение); низкая сетевая задержка (все компоненты в одном адресном пространстве).
    • Минусы: сложно масштабировать отдельные части; долгие сборка/деплой; сложность кода; единая точка отказа может вывести из строя всё приложение.
  • Микросервисы: подход, при котором одно приложение состоит из множества небольших, слабо связанных и независимо разворачиваемых сервисов.
    • Плюсы:
      • Независимое масштабирование: компоненты можно масштабировать независимо, оптимизируя использование ресурсов и затраты.
      • Скорость и гибкость: проще обновлять и добавлять новую функциональность, не затрагивая всё приложение.
      • Технологическая независимость: команды могут выбирать стек, наиболее подходящий для конкретной задачи каждого сервиса.
      • Изоляция сбоев: проблемы в одном сервисе реже приводят к падению всей системы, обеспечивая лучшую отказоустойчивость.
    • Минусы: высокая сложность эксплуатации; проблемы согласованности данных (распределённые транзакции); сетевые задержки и риски потери связности; более объёмное и сложное логирование/мониторинг.

Микросервисы vs SOA (Service-Oriented Architecture)​

Оба подхода декомпозируют приложения на сервисы, но различаются масштабом и способом взаимодействия:

  • SOA: корпоративная инициатива по стандартизации интеграции всех веб-сервисов в организации, часто с использованием Enterprise Service Bus (ESB).
  • Микросервисы: архитектура на уровне приложения, ориентированная на маленькие, независимые сервисы, взаимодействующие через легковесные механизмы (REST, gRPC, Message Queues).

2. Стратегии масштабирования​

  • Вертикальное масштабирование: добавление ресурсов (CPU, RAM) на один сервер.
  • Горизонтальное масштабирование: добавление серверов и распределение нагрузки (Load Balancing).

3. Масштабирование баз данных​

  • Разделение чтения/записи (Read/Write Splitting): одна Master-база данных (запись) и несколько Replica (чтение).
  • Partitioning: разделение большой таблицы на более мелкие части в рамках одного экземпляра БД.
  • Sharding: распределение данных между несколькими физическими серверами баз данных.
    • Vertical Sharding: размещение разных таблиц в разных базах данных.
    • Horizontal Sharding: разделение строк одной таблицы между несколькими БД на основе ключа шардирования (shard key).

4. Архитектурные паттерны​

  • CQRS (Command Query Responsibility Segregation): разделение моделей для записи данных (Commands) и чтения данных (Queries).
  • Event Sourcing: вместо хранения текущего состояния сохраняются все изменения в виде последовательности событий.
  • API Gateway: единая точка входа для всех микросервисов, отвечающая за маршрутизацию, аутентификацию и балансировку нагрузки.
  • Circuit Breaker: предотвращает каскадные сбои в системе, вызванные неработающим сервисом.

5. CAP-теорема​

В распределённой системе можно обеспечить только два из трёх следующих свойств:

  • Consistency (согласованность): все узлы видят одни и те же данные в одно и то же время.
  • Availability (доступность): каждый запрос получает ответ (успех или ошибка).
  • Partition Tolerance (устойчивость к разделению): система продолжает работать несмотря на сетевые сбои.

6. Highload и производительность баз данных​

  • PHP-FPM и Nginx: Nginx выступает в роли обратного прокси, передавая PHP-запросы пулу PHP-FPM через Unix-сокет или TCP.
  • Оптимизация вставок в большие таблицы:
    • Используйте Bulk Inserts (INSERT INTO ... VALUES (), (), ...).
    • Отключайте индексы во время вставки (если возможно) и перестраивайте их после.
    • Используйте LOAD DATA INFILE для массивных наборов данных.
    • Отключайте autocommit или используйте транзакции.
  • Инструменты профилирования БД: EXPLAIN, SHOW PROFILE, Slow Query Log, Performance Schema, Percona Toolkit.
  • Поиск узких мест производительности PHP: Xhprof, Blackfire.io, New Relic, Tideways.
  • Обработка Deadlock'ов: делайте транзакции короткими, обращайтесь к таблицам в одном и том же порядке, используйте логику повторных попыток, применяйте более низкие уровни изоляции, если это допустимо.

7. Каверзный вопрос о производительности​

Сценарий: GET-эндпоинт превышает тайм-аут при чтении из большой таблицы. Как оптимизировать, НЕ меняя тело ответа?​

  • Ответ:
    1. Добавить/оптимизировать индексы: убедитесь, что запрос использует покрывающий индекс (covering index — индекс, содержащий все столбцы из SELECT).
    2. Пагинация: реализуйте курсорную пагинацию (даже если «тело» не меняется, выборка должна быть ограничена).
    3. Материализованное представление/кэш: предварительно вычислите результат и сохраните его в отдельной таблице или Redis.
    4. Денормализация: добавьте необходимые столбцы в основную таблицу, чтобы избежать дорогостоящих JOIN'ов.
    5. Vertical/Horizontal Sharding: переместите данные на более быстрые диски или распределите их между серверами.
    6. Read Replicas: разгрузите master-базу данных, направив запросы на чтение на реплику.

8. Highload-производительность (специфика PHP)​

  • PHP-FPM: использует пул рабочих процессов для обработки входящих запросов от веб-сервера (Nginx/Apache).
  • OPCache: хранит предварительно скомпилированный байт-код, чтобы не парсить скрипты при каждом запросе.
  • JIT (Just-In-Time): доступен в PHP 8+, транслирует байт-код в машинный код для определённых задач.
  • Swoole / RoadRunner: альтернативы PHP-FPM, которые держат приложение в памяти между запросами (аналогично Node.js или Go).
  • Очереди (Queueing): используйте такие инструменты, как RabbitMQ, Kafka или Redis, чтобы выносить ресурсоёмкие задачи (отправка писем, обработка изображений) в фоновые воркеры.

9. Ключевые технологии для микросервисов​

  • Контейнеры (Docker): обеспечивают легковесную и единообразную среду для запуска сервисов, гарантируя одинаковое поведение в разных окружениях.
  • Оркестрация (Kubernetes): управляет развёртыванием, масштабированием и эксплуатацией контейнеров приложений в кластерах.
  • API Gateways: выступают единой точкой входа для всех клиентских запросов, обеспечивая маршрутизацию, аутентификацию и балансировку нагрузки.

10. Service Discovery и паттерны​

  • Service Discovery: позволяет сервисам находить друг друга и взаимодействовать динамически при масштабировании вверх/вниз или при сбоях. Обычно использует health checks и запускает перебалансировку трафика через балансировщик нагрузки.
  • Backend-for-frontend (BFF): паттерн, при котором для каждого конкретного фронтенда (например, мобильное приложение, веб) создаётся отдельный бэкенд-сервис, оптимизированный по данным и производительности для этого клиента.
  • Adapter Patterns: используются для связи между различными сервисами или устаревшими системами.