Бэкенд-команда айти-агентства Фьюче собрала в вики полное руководство по микросервисной архитектуре с Laravel и современным практикам Highload. Публикуем материал в сокращённом виде с незначительными правками. Полная версия доступна по ссылке.
Если коротко, рассмотрим, как строить микросервисную архитектуру на Laravel: практические решения, схемы взаимодействия сервисов, продвинутые паттерны и DevOps-аспекты развёртывания. Сравним Kubernetes с альтернативами, оценим плюсы и минусы микросервисов и их альтернатив, а также разберём ключевые принципы отказоустойчивости и консистентности данных.
Систему стоит разделять на микросервисы по бизнес-доменам. В e‑commerce это могут быть: каталог товаров, корзина, заказы, платежи, уведомления и т.д. Каждая команда отвечает за свой сервис с чётким Bounded Context.
Подход Self-Contained Systems рекомендует делать каждый модуль автономным: со своей логикой, данными и UI. Это снижает зависимость между сервисами и упрощает масштабирование. Взаимодействие происходит через интерфейсы, а не прямой доступ к базам данных.
Сервисы общаются синхронно через REST API или gRPC, а события передают через брокеры сообщений — Kafka или RabbitMQ.
Важно заранее спроектировать схему: кто кому вызывает сервис напрямую, а кто получает события. Диаграмма потоков данных помогает визуализировать это. При создании заказа сервис платежей вызывается синхронно, а событие OrderCreated публикуется в Kafka, чтобы доставка и маркетинг обработали его асинхронно.
Пример: при создании заказа сервис платежей вызывается синхронно, чтобы доставка и маркетинг обработали его асинхронно.
Традиционные транзакции ACID на несколько сервисов невозможны. Межсервисные транзакции не реализуются напрямую, вместо них используют Saga. Бизнес-транзакция делится на цепочку локальных операций, связанных сообщениями.
Saga гарантирует либо полное выполнение, либо откат уже выполненного через компенсирующие действия.
Пример: если один из сервисов бронирования не сработал, остальные операции Saga отменяет автоматически.
Эффективная коммуникация — ключ к работе микросервисов. Разберём основные подходы, их преимущества и недостатки, а также примеры, где каждый будет наиболее эффективен.
Привычный синхронный способ связи через HTTP (GET, POST, PUT, DELETE), данные обычно передаются в JSON.
Плюсы: простота и универсальность (поддержка почти всех языков, легко отлаживать через curl или Postman), stateless (каждый запрос независим, масштабировать проще) и гибкие контракты (можно эволюционно добавлять поля и версии API).
Минусы: JSON создаёт оверхед и может стать узким местом на нагрузке, синхронность связывает сервисы (задержка одного влияет на всех), а контракты могут «окостенеть», если много сервисов зависит от API.
Использовать: для внешних API и простых внутренних запросов.
Пример: REST для получения информации о товаре по ID.
Высокопроизводительный бинарный протокол от Google с HTTP/2 и Protocol Buffers.
Плюсы: быстро и компактно, парсинг быстрее JSON, поддержка стриминга и двунаправленной связи (real-time), строго типизированные контракты в .proto с авто-генерацией кода клиента и сервера.
Минусы: сложнее отлаживать вручную и нужны инструменты, браузеры напрямую не поддерживают (gRPC-Web или прокси), требует обучения команды и настройки инструментов.
Использовать: для высоконагруженных внутренних сервисов, строгого контракта и обмена между разными языками.
Пример: Laravel-монолит вызывает сервис на Go через gRPC для ускорения вычислений.
Брокеры сообщений связывают микросервисы асинхронно по паттерну Pub/Sub. Отправитель публикует событие, не зная получателей; подписчики реагируют на него при поступлении.
Распределённый лог событий с высокой пропускной способностью.
Плюсы: высокая производительность и масштабируемость с хранением истории событий, отлично подходит для event sourcing и потоковой обработки, продюсер и консюмер слабо связаны во времени, обработка может быть отложена.
Минусы: сложнее отлаживать, нет прямого ответа, требуется идемпотентность и учёт порядка, нужно обрабатывать дубликаты, необходим кластер с поддержкой ZooKeeper или партиций.
Кейсы: журналирование событий, обмен бизнес-событиями, аналитические пайплайны.
Классический брокер с очередями, маршрутизацией и подтверждениями (ACK).
Плюсы: прост в освоении, гибкая маршрутизация (direct, topic, fanout), подходит для job-очередей и точечных задач
Минусы: ограниченная масштабируемость по сравнению с Kafka, асинхронность усложняет отладку и обработку повторной доставки
Применение: фоновые задачи, уведомления, генерация отчётов. В Laravel легко интегрируется через Horizon.
Лог событий в Redis (начиная с версии 5.0).
Плюсы: очень быстрый и прост в развёртывании, поддержка групп потребителей и авто-подтверждений, подходит для небольших систем или локальной координации.
Минусы: ограничения по объёму и долговечности данных (хранение в памяти), масштабирование зависит от Redis
Кейсы: небольшие highload-проекты, межсервисное общение внутри продукта.
Синхронные (REST/gRPC) подходы просты, понятны, требуют быстрого ответа и доступности сервисов. Но асинхронные (очереди, события) дают слабую связанность, устойчивость и масштабируемость. Это сложняет обработку ошибок и согласованность данных.
Комбинированный подход: быстрый отклик через REST/gRPC + рассылка событий через брокеры.
Пример: сервис Заказы синхронно вызывает Платежи, а затем асинхронно публикует OrderPaid другим сервисам.
В монолите транзакция атомарна, в микросервисах распределена между разными БД. Поддерживать целостность сложно: 2PC непрактичен, поэтому системы проектируют с учётом eventual consistency для согласованности «в итоге».
Цепочка локальных транзакций с компенсациями. Если шаг не удался, выполняются «обратные» операции, откатывающие уже сделанное. Саги можно координировать двумя способами.
В этом подходе есть центральный оркестратор в качестве отдельного сервиса или модуля, который управляет всей цепочкой шагов. Он знает сценарий: кому и в каком порядке отправлять команды, ждёт ответы и решает, продолжать выполнение или откатывать уже сделанные шаги.
Пример: в Laravel можно сделать оркестрацию через очереди Jobs одна задача-оркестратор поочерёдно ставит задания для разных сервисов (через HTTP или Kafka) и следит за результатом. Если один из шагов завершился с ошибкой, оркестратор запускает компенсации в обратном порядке. Он же может хранить текущее состояние всей саги: что уже прошло, а что ещё в процессе.
Здесь нет центрального управляющего, каждый сервис сам решает, что делать, реагируя на события от других. Процесс получается «танцем» из реакций, когда один сервис опубликовал событие, второй его поймал, сделал свою часть работы и отправил следующее событие.
Пример: при оформлении заказа сервис Orders создаёт запись «pending» и публикует событие OrderCreated, сервис Customers ловит его, резервирует кредит и отправляет CreditReserved или CreditLimitExceeded. Orders реагирует на это и либо подтверждает заказ, либо отменяет.
Такой подход лишён единой точки отказа, но его труднее отследить. Процесс «распределён» между участниками, и добавление нового шага требует менять код сразу в нескольких местах. Поэтому хореография подходит для простых последовательностей, а для сложных процессов чаще выбирают оркестратора.
Вернёмся к примеру, когда нужно забронировать перелёт, отель и машину. Мы создаём Job BookTripSaga, где в методе handle по очереди вызываются сервисы: FlightService.book(), HotelService.book(), CarService.book(). Все три прошли успешно, бронирование подтверждено.
Но если где-то ошибка (например, отель не подтвердился), в catch блоке публикуем компенсирующие события: в Kafka отправляются команды CancelFlight, CancelCar. Эти сервисы получают команды и откатывают свои действия, т. е. отменяют бронь, возвращают деньги.
Компенсации можно регистрировать сразу после успешного шага, через события или callback’и в Laravel. В итоге Saga либо завершает всё успешно, либо аккуратно откатывает систему в исходное состояние.
Чтобы не потерять контекст, Saga хранит статусы шагов (например, в таблице saga_states) и после сбоя может продолжить с нужного места. Laravel помогает — очереди, транзакции и Kafka-интеграция уже есть, а для сложных сценариев можно взять готовую библиотеку вроде laravel-workflow.
Классическая проблема, когда нужно сохранить заказ и отправить событие OrderCreated. Если сначала сохранить в БД, а потом отправить в Kafka, сервис может упасть между этими шагами. Если наоборот отправить до коммита, может улететь фантомное событие, хотя заказ не записался.
Вместо прямой отправки событие записывается в ту же базу, в таблицу outbox, в одной транзакции с заказом. А потом отдельный фоновый процесс читает непросланные события и публикует их в брокер. Так данные и события сохраняются атомарно. Даже если сервис упал, сообщение останется в базе и позже будет отправлено.
Плюсы: нет сложных 2PC и событие не теряется, если данные записаны.
Минусы: больше кода и инфраструктуры (таблица, воркер, дисциплина), возможны дубли (если упал после отправки), разработчики должны пользоваться этим паттерном всегда.
На уровне Eloquent-событий, после сохранения заказа создавать запись Outbox или при помощи пакетов-абстракций (существуют готовые реализации паттерна для различных фреймворков).
CDC (Change Data Capture) для отслеживания транзакционного лога БД (Debezium читает binlog MySQL) и публикаций событий об изменениях.
Плюсы: не нужно менять код приложения для отправки событий.
Минусы: нужно уметь правильно читать транзакционные логи.
В распределённых системах сообщения могут приходить повторно. Обычно из-за сетевых сбоев, повторных попыток или особенностей брокеров. Чтобы не получилось двойного выполнения, сервисы должны быть идемпотентными, когда одно и то же событие не должно менять результат дважды.
Как это делают: в каждом сообщении есть уникальный ID (GUID или бизнес-ключ), потребитель ведёт лог обработанных ID (Redis или локальная БД) и перед обработкой нового события проверяет, если ID уже встречался — пропускает
Такой подход нужен не только при повторной доставке от брокера, но и если система сама пересылает событие (например, при компенсации).
Часто идемпотентность достигается сочетанием уникальных ключей в базе (повторный заказ с тем же номером не вставится) и проверок на уровне приложения.
Действия, которые отменяют или корректируют уже выполненные операции.
Пример: при отмене заказа нужно вернуть деньги, освободить товар и уведомить клиента.
Не всё можно отменить идеально. Отправленное письмо не вернуть, но можно выслать корректирующее. В финансах компенсация — это транзакция обратного знака (сторно).
При проектировании Saga важно сразу продумывать компенсации и фиксировать результаты каждого шага. Часто они сложнее основной операции, поэтому их тестируют так же тщательно, как и «прямой» сценарий.
Кроме Saga и Outbox, в больших проектах используют проверенные приёмы:
Микросервисная архитектура предъявляет серьёзные требования к инфраструктуре и DevOps-практикам. Нужно не только написать код, но и запустить десятки копий сервисов, обеспечить их автоматическое развертывание, масштабирование, мониторинг и безопасность.
Одно из главных преимуществ микросервисов в Kubernetes – масштабировать только нужные сервисы. Horizontal Pod Autoscaler (HPA) автоматически регулирует число подов по CPU, памяти или кастомным метрикам, например, длине очереди Laravel Horizon через Prometheus. Больше задач – больше реплик, очередь пуста – уменьшаем.
Можно масштабировать вручную (kubectl scale) или использовать Vertical Pod Autoscaler (VPA) для подбора ресурсов.
Важно, чтобы база и кэш выдерживали нагрузку: кластеры БД с репликами, шардирование, кластерный Redis. Laravel умеет работать с несколькими подключениями и кластерами, что удобно при росте.
В микросервисах отладка усложняется — запрос проходит через много сервисов с разными логами. Observability критически важен и включает: логи, метрики и трассировки (traces). OpenTelemetry (OTel) собирает всё это единообразно и является современным стандартом.
Чтобы понять путь запроса через микросервисы, каждому входящему запросу присваивают уникальный Trace ID. Он передаётся во все исходящие вызовы.
Библиотеки OpenTelemetry для PHP/Laravel (например, LaraOTel) автоматически отслеживают HTTP-запросы, SQL, кэш и очереди, собирая Span’ы и трассы. Эти данные экспортируются в визуализаторы вроде Jaeger, Zipkin или Grafana Tempo.
В итоге можно увидеть, что запрос /api/order прошёл через OrderService (100 ms), затем PaymentService (200 ms), а задержка 150 ms на внешнем API – вот узкое место. Такая прозрачность сильно облегчает отладку.
Метрики показывают, как работает система: RPS, задержки, ошибки, загрузка CPU, активные пользователи и т.д. Их собирают для анализа и оповещений. Стек Prometheus + Grafana – стандарт для этого.
Prometheus опрашивает сервисы по HTTP /metrics через экспортеры. В Kubernetes часто используют Prometheus Operator, который сам находит поды с метриками по аннотациям.
Для Laravel есть готовые экспортеры: Horizon (очереди, время выполнения), PHP-FPM (число воркеров, загрузка), а OpenTelemetry может слать метрики о контроллерах и задачах.
В Grafana строят графики QPS, среднее время ответа, процентильные задержки, и настраивают алерты. Например: error rate > 1% 5 минут – сигнал дежурному; память пода > 90% – предупреждение. Так команда быстро видит сбои и реагирует.
Вместо подключения к каждому контейнеру логи лучше собирать в одном месте. Классический подход (EFK), когда Logstash или Fluentd собирают stdout контейнеров, складывают в Elasticsearch, а Kibana даёт фильтры и просмотр.
Grafana Loki — современный и лёгкий вариант. Логи хранятся как стримы, оптимизировано под временные ряды, и их удобно запрашивать через LogQL. Loki отлично интегрируется с Grafana, метрики и логи в одном интерфейсе.
В Kubernetes часто используют либо EFK, либо PLG (Promtail + Loki + Grafana). Тогда по TraceID в Grafana можно сразу найти все связанные логи. Удобно при разборе инцидентов.
Для Laravel стоит писать логи в JSON и добавлять correlation ID (TraceID), чтобы быстро собрать всю историю обработки конкретного запроса.
Наблюдение: без метрик и трассировок сложно понять, где узкое место и почему произошёл сбой. OpenTelemetry помогает стандартизировать сбор данных и сделать «единую точку правды» о работе системы.
Наша система сама подберет вам исполнителей на услуги, связанные с разработкой сайта или приложения, поисковой оптимизацией, контекстной рекламой, маркетингом, SMM и PR.
Заполнить заявку
13201 тендер
проведено за восемь лет работы нашего сайта.
Highload-системы обычно распределены по нескольким узлам и обмениваются данными по сети.
Используется для всех внешних соединений. Например, фронтенд или мобильное приложение обращается к API Gateway, связь идёт по HTTPS.
Внутренний трафик между сервисами тоже шифруют. Есть требования (PCI DSS, GDPR), когда даже внутри периметра данные должны быть защищены. В облачных Kubernetes-кластерах нода может быть скомпрометирована и перехват трафика — реальная угроза.
Настройка mTLS (mutual TLS) защищает взаимодействие между сервисами. При mTLS каждый сервис имеет свой сертификат и проверяет сертификат собеседника — то есть сервисы аутентифицируют друг друга через TLS.
Подходы:
Mesh-подход часто выбирают как более удобный и масштабируемый.
Помимо шифрования, не менее важно убедиться, что вызов идёт от доверенного сервиса.
Подходы:
В Kubernetes популярны Service Mesh (Istio). Citadel выдаёт сертификаты, Envoy шифрует трафик и проверяет identity. Через AuthorizationPolicy можно настроить, какой сервис к какому обращается.
Если mesh не используется, можно сделать Service Accounts, когда каждый сервис подтягивает JWT из безопасного хранилища (Vault) и подписывает им запросы. Самый простой вариант — 1 статический токен для всех вызовов в качестве минимальной безопасности.
Пароли к БД, API-ключи, приватные ключи JWT и прочие секреты нельзя хранить в .env в репозитории или в Docker-образе — это антипаттерн.
Правильный подход: использовать Kubernetes Secrets (можно шифровать через KMS) или внешние хранилища типа HashiCorp Vault. Vault даёт централизованное хранение и даже может выдавать динамические секреты. Например, на каждый под свой уникальный временный пароль к БД.
В Kubernetes Vault легко интегрировать через CSI Driver, чтобы секреты монтировались в под автоматически. Лучше хранить их в одном надёжном месте для минимизции распространения секретов. Так проще проводить ротацию, обновили в Vault, сервисы подтянули новые при следующем обращении.
Не забывайте про принцип наименьших привилегий, когда каждый сервис видит только свои секреты.
Безопасность CI/CD: pipeline-сборки и деплоя тоже должен быть защищён (артефакты подписываются, доступ в регистри контейнеров ограничен). Подписывайте контейнеры (Docker Content Trust, Cosign) и проверяйте подпись на кластере через Admission Controller, чтобы убедиться, что образ не подменён.
Для публичных API требуются стандартные меры: TLS, WAF на уровне ingress (фильтрация SQL-инъекций, XSS и других атак) и rate limiting. Это защищает сервис от DoS и перегрузок. В Laravel можно использовать встроенный Throttle middleware или использовать Istio для лимитов
Данные в базах и бэкапах нужно шифровать. Для особо чувствительных полей можно шифровать на уровне колонки. В микросервисах данные распределены, поэтому важно не допустить утечки через логи или события. Например, номера кредиток не должны попадать во внутренние топики Kafka.
Организуйте аудит и наблюдение за безопасностью: централизованные логи должны фиксировать аномалии, неудачные входы и нестандартные обращения сервисов. При необходимости интегрируйте с SIEM для корпоративного контроля.
Есть альтернативы для оркестрации контейнеров. Подсветим, когда лучше Kubernetes и когда проще использовать лёгкие решения.
Для разработки проще и быстрее поднять несколько контейнеров локально для проверки совместной работоспособности. Но в продакшене Compose не справится, нет автозапуска при сбоях и масштабирования на несколько узлов.
Docker Swarm добавляет кластер и базовую оркестрацию, но уступает Kubernetes по функциональности и сообществу.
Compose и Swarm подходят для маленьких проектов или внутренних сервисов, где немного контейнеров и их легко поддерживать вручную. Но с ростом нагрузки ручное управление быстро становится проблемой. Становится трудно следить за состоянием, масштабировать и балансировать.
Kubernetes делает всё автоматически: перезапускает упавшие процессы, перераспределяет нагрузку при добавлении узлов и управляет сервисами на большом числе микросервисов.
Сервис для управления контейнерами без собственного control-plane. Быстрй запуск через создание Task в консоли и настройки Service (deployment). AWS берёт часть задач на себя, но функциональность ограничена по сравнению с Kubernetes.
Нет большой экосистемы вроде Helm charts или операторов, низкая портируемость (ECS привязан к AWS). Если вся инфраструктура в AWS и не хочется заводить Kubernetes, смело используйте ECS.
В других облаках есть другие упрощённые решения: Azure Container Instances, Service Fabric, Google Cloud Run (serverless-контейнеры).
Ограничения ECS: сложнее делать cross-region deployments, меньше гибкости в сетевых настройках. Kubernetes же открытый, поддерживается всеми облаками и позволяет тонко настраивать всё, поэтому многие выбирают его даже в AWS ради унификации.
Лёгкий и простой оркестратор с одним бинарником и минимумом зависимостей, который умеет запускать не только контейнеры, но и обычные процессы. У него меньше сообщества и готовых решений: чарты, операторы и рецепты для сложных сценариев встречаются редко. Nomad хорошо подходит, когда Kubernetes слишком громоздкий или нежелателен.
Для Laravel-микросервисов используют там, где уже применяют stack (Consul, Vault) и хотят единый подход. Масштабируется Nomad хорошо, но из-за ограничения готовых компонентов, мониторинг придётся настраивать вручную или через Consul. В Kubernetes можно сразу поставить Helm-чарт Prometheus Operator и получать метрики.
Laravel-проекты часто начинают с монолита, который со временем растёт. Kubernetes позволяет плавно переходить к микросервисам: сначала можно деплоить монолит, потом выделять новые сервисы. Процесс остаётся одинаковым, что упрощает управление.
Kubernetes независим от окружения, разработчики запускают сервисы локально в minikube, а продакшен может быть в облаке или on-premise. Манифесты и Helm-чарты остаются теми же. Это снижает привязку к конкретному вендору.
Экосистема Kubernetes позволяет стандартизировать работу больших команд: service discovery через встроенный DNS, управление конфигами через ConfigMap и Secrets, масштабирование через HPA, стратегии обновлений и готовые решения для наблюдаемости через Operators.
Kubernetes сложнее и требует опыта, поэтому для небольших проектов можно выбрать что проще. Но когда речь идёт о десятках микросервисов и highload, он себя оправдывает: автоматический перезапуск при падении, отложенный старт зависимых сервисов, обновления без downtime. Всё решается декларативно, без скриптов и ночных правок.
Пример: кластер из 50 PHP-подов сам следит за здоровьем сервисов. Если под перестал отвечать, Kubernetes перезапускает его на другом экземпляре. Если сервер-нода выходит из строя, pods автоматически перемещаются на другие ноды. Так система остаётся устойчивой, а команда меньше тратит времени на ручное управление.
Сначала создаём структурированный монолит с ясной доменной моделью, а потом выделяем «проблемные» части в отдельные сервисы. Например, Shopify сначала использовал Rails-монолит, а потом вынес checkout в отдельный сервис. Модульный монолит дисциплинированный, почти как микросервисы в одном приложении.
Автономные приложения, каждое полностью обслуживает свою функцию и может включать фронтенд, бэкенд и базу данных.
Особенности:
Пример: интернет-банк можно разбить на SCS (счета и выписки, переводы, платежи, кредиты). Каждая SCS со своей логикой и частью веб-интерфейса. На уровне пользователя они объединяются в единый портал. Часть страниц может быть отдельным виджетом от конкретной SCS, часть просто ссылкой на её функционал.
В Laravel это можно сделать через разные поддомены и отдельные приложения с обменом событиями.
Идея проста – приложение разбивается на независимые части (компоненты), которые можно развивать отдельно, но не обязательно превращать в отдельные сервисы.
Варианты:
Итог: сначала внутри одного приложения стоит поддерживать модульный монолит для дисциплины и порядка, затем можно выделять крупные автономные подсистемы (SCS) для вертикального разделения продукта, а внутри всего этого использовать компонентную архитектуру для гибкости и возможности расширения.
Когда использовать: если система не требует гигантского масштабирования и нужна гибкость, если команда пока не готова к сложности микросервисов и хочет разделять функционал, если важно быстро выпускать новые возможности без постоянной синхронизации множества сервисов.
Пример: стартап начинает с модульного монолита на Laravel с единым деплоем и модулями внутри. Позже тяжёлые части (например, модуль с высокой нагрузкой) можно вынести в отдельные сервисы, а остальные оставить внутри. Такой гибридный подход очень распространён.
Важно: быстро доставлять ценность пользователям с нужным качеством и приемлемыми затратами. Микросервисы лишь один из вариантов, выбирайте подход, исходя из команды, продукта и планов роста.
В highload-системах нужно предусмотреть механизмы, позволяющие системе работать даже при частичных отказах компонентов.
Работает как электрический предохранитель, но для сервисов. Если внешний сервис часто падает, перестаём к нему обращаться на некоторое время и сразу возвращаем ошибку, пока он не восстановится.
Пример: сервис А вызывает сервис B, а тот постоянно отвечает с таймаутом или ошибкой 500. После нескольких неудач Circuit Breaker «размыкается» и все новые запросы к B сразу получают отказ (ошибка 503) без ожидания. Это защищает сервис А от зависаний и предотвращает лавину нагрузки на B.
Через заданный интервал Circuit Breaker переходит в состояние Half-Open и пропускает пробный запрос к B. Если он успешный, цепь «замыкается» обратно. Если опять ошибка, снова размыкается, пока сервис B не восстановится.
В Laravel нет встроенного CB, но можно использовать библиотеки вроде php-circuit-breaker или реализовать через кеш (отслеживать процент ошибок и флаг «отключено»). В облаке его часто выносят на уровень Service Mesh (Istio с настройками на уровне destination rules), и тогда прокси Envoy управляет подключениями вместо самих сервисов.
Многие сбои носят временный характер из-за глюка в сети или перегрузки. Поэтому полезно повторить запрос, но делать это грамотно.
Варианты:
В Laravel клиент Guzzle позволяет настроить политику ретраев для HTTP-запросов, у Job можно указать $tries и $retryAfter для очередей.
Важно, чтобы ретраи были идемпотентными. Повторный запрос не должен создавать дубль операции. Например, деньги не списываются дважды. GET-запросы обычно безопасны, а для изменений используем уникальные ID или специальные проверки. Circuit Breaker отлично дополняет ретраи, защищая систему от лавины повторов при настоящих проблемах.
Каждый внешний вызов должен иметь настроенный таймаут. Без него зависший запрос будет вечно держать соединение и съедать ресурсы.
Таймаут должен быть достаточно длинным, чтобы дождаться ответа при нормальной работе, но коротким, чтобы быстро отрубить зависание. Например, для внутреннего REST-запроса 95-й перцентиль 50мс, можно таймаут 200мс.
Timeout Budget с помощью одного входящего запроса вызывает каскад из нескольких сервисов, и нужно распределять общий допустимый бюджет времени.
Если API Gateway должен ответить за 1 с и вызывает три сервиса последовательно, нельзя каждому дать по 1 с. Лучше распределить, например, по 300 мс на каждый, оставив запас.
Laravel сам по себе не следит за Timeout Budget, но при проектировании можно задать свои SLA и мониторить задержки. Иногда входящий запрос передают в заголовках запроса с дедлайном. В Google Dapper подобное делали. На практике достаточно настраивать таймауты с запасом и мониторить перцентиль задержек.
Метафора из кораблестроения, когда корабль разделяют на секции, чтобы пробоина не затопила всё судно. В софте это означает изоляцию ресурсов для разных подсистем. Сбой одной подсистемы не должен забирать все потоки, память или CPU.
Пример: веб-сервер выделяет отдельный пул из 5 потоков для запросов к медленному API. Если API не подвис, только 5 поток зависнут, остальные 50 обработают другие запросы. Без bulkhead всё бы встало.
В Laravel это реализовать сложнее, т. к. PHP-воркеры одинаковые. Можно разделять очереди, выделять отдельные воркеры на отправку email и очередь на финансовые операции. Тогда всплеск писем не заблокирует критичные транзакции.
В Kubernetes bulkhead достигается лимитом ресурсов и разнесением сервисов. Например, ограничить сервис рекомендаций 1 CPU, даже если он станет безумно популярен, чтобы не отъел CPU у сервиса checkout.
Способность системы переключаться на резервный экземпляр, если основной недоступен. В микросервисах это обычно обеспечивает оркестратор: Kubernetes перезапускает pod на другой ноде, а Service отправит трафик туда.
Но бывают более крупные failover. Если целый датасентр упал, тогда помогают multi-region развёртывания с балансировкой DNS или любым глобальным traffic manager. Т.е. активный-пассивный или активный-активный режимы.
В Laravel можно предусмотреть резервный API endpoint или набор конфигов для ручного переключения.
Для баз данных failover достигается репликацией и автопереключением (Postgres — Patroni, Mongo — replSet, MySQL — Group Replication). Важно, чтобы приложение умело работать с несколькими хостами, Laravel Database это поддерживает.
Stateful-компоненты (Redis, кэш, очереди) тоже стоит запускать в кластерном режиме. Redis в Sentinel или Cluster обеспечат фейловер мастера без потери данных.
Система должна быть спроектирована так, чтобы при сбоях второстепенных сервисов основные функции продолжали работать, пусть и в урезанном режиме.
Примеры:
Для таких случаев в коде ставят проверки. Вызов внешнего сервиса оборачивают в try/catch с таймаутом. Если запрос не удался, логируем ошибку и продолжаем выполнение с дефолтным поведением.
В Laravel можно использовать вспомогательные методы
$response=Http::timeout(2)->get(...)->onError(fn()=>null);
Другой приём — кэшировать последний успешный ответ. Если сервис профилей не отвечает, можно показать сохранённый вариант «устаревшего» профиля. Многие сайты так делают, ведь лучше какой-то контент, чем ничего.
Graceful degradation тесно связана с UX. Лучше честно сообщить, что некоторые разделы недоступны, чем крутить вечный прелоадер или выбрасывать ошибку 500. На уровне API стоит возвращать корректные коды, с чётким описанием и какая подсистема недоступна.
Отказоустойчивость — это не только про скорость ответов, но и про то, чтобы сервис умел подниматься сам. Kubernetes выполняет роль watchdog, когда упал процесс и тут же перезапустил.
Внутри приложения также можно предусмотреть защиту. Например, если задача падает 5 раз подряд, её можно временно выключить и отправить уведомление.
Подходы:
Resilience patterns работают совместно:
Построить микросервисную архитектуру на Laravel реально, но важно делать всё продуманно. Для senior backend-разработчика главное видеть общую картину. Как разбиение на сервисы влияет на разработку, тестирование, деплой и поддержку. Микросервисы не упрощают работу, они перераспределяют сложность. Часть решается кодом сервиса, часть инфраструктурой.
Laravel предоставляет богатый инструментарий для реализации многих из описанных паттернов, опираясь на мировой опыт. Главное — соблюдать принципы: разделение ответственности, устойчивость к ошибкам, автоматизация и наблюдаемость. Тогда даже под высокой нагрузкой ваша система останется управляемой, а пользователи довольны быстротой и надёжностью сервиса.