Микросервисы — это не просто модный тренд. Это способ разбить большую систему на маленькие, независимые кусочки, которые легче разрабатывать, тестировать и масштабировать. Если вы PHP-разработчик и хотите попробовать себя в этой архитектуре, но не знаете, с чего начать, — эта статья для вас. Мы пройдём путь от пустой папки до работающего микросервиса, обсудим подводные камни и дадим практические советы.

Digital-студия WNDER

Что такое микросервис и зачем он нужен

Представьте, что у вас есть интернет-магазин. В монолите всё свалено в одну кучу: корзина, оплата, уведомления, каталог. Поменяли что-то в корзине — пересобираем и перезапускаем всё приложение. Микросервисный подход предлагает разделить эту кучу на отдельные сервисы: сервис корзины, сервис оплаты, сервис уведомлений. Каждый живёт своей жизнью, общается с другими по сети (обычно через HTTP или очереди).

Главные плюсы: независимое развёртывание, масштабирование только нужного сервиса, возможность использовать разные технологии для разных задач. Минусы тоже есть: сложнее отлаживать, нужно следить за сетью и согласованностью данных. Но если система растёт, микросервисы могут спасти.

Правило: Не начинайте с микросервисов, если у вас маленький проект. Монолит проще и быстрее на старте. Переходите к микросервисам, когда монолит станет трудно поддерживать.

Выбор инструментов и подготовка окружения

Для PHP-микросервисов нам понадобится несколько вещей:

  • Веб-сервер или встроенный сервер PHP (для разработки).
  • Фреймворк для обработки HTTP-запросов. Можно взять Slim, Lumen или даже чистый PHP. Я рекомендую Slim — он лёгкий и не навязывает архитектуру.
  • Менеджер зависимостей Composer.
  • Docker для изоляции сервисов (по желанию, но очень удобно).

Установим Slim через Composer. Создадим папку проекта и выполним:

composer require slim/slim slim/psr7

Теперь создадим точку входа — файл public/index.php. Это будет наш первый микросервис, который просто отвечает на запросы.

<?php
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Slim\Factory\ResponseFactory;
use Slim\Factory\ServerRequestFactory;

require __DIR__ . '/../vendor/autoload.php';

$app = Slim\Factory\AppFactory::create();

$app->get('/hello/{name}', function (Request $request, Response $response, array $args) {
    $name = $args['name'];
    $response->getBody()->write("Hello, $name");
    return $response;
});

$app->run();

Запустим встроенный сервер PHP:

php -S localhost:8080 -t public

Откройте в браузере http://localhost:8080/hello/World — увидите приветствие. Поздравляю, вы только что создали простейший микросервис!

Организация кода и взаимодействие между сервисами

Хороший микросервис должен быть маленьким и делать одну вещь. Например, сервис пользователей, сервис заказов, сервис платежей. Каждый сервис — отдельный проект со своим репозиторием и зависимостями.

Как они общаются? Чаще всего через HTTP/REST. Один сервис делает HTTP-запрос к другому. Для этого можно использовать библиотеку Guzzle.

Установим Guzzle:

composer require guzzlehttp/guzzle

Пример вызова другого сервиса из нашего кода:

<?php
use GuzzleHttp\Client;

$client = new Client([
    'base_uri' => 'http://users-service:8081',
    'timeout'  => 2.0,
]);

$response = $client->request('GET', '/users/123');
$data = json_decode($response->getBody(), true);

Важно продумать, что делать, если сервис недоступен. Нужны таймауты, повторные попытки, запасные варианты. Об этом ниже.

Лайфхак: Используйте переменные окружения для адресов других сервисов. Так вы сможете легко переключаться между локальной разработкой, тестовым и продакшен-окружением.

Обработка ошибок и отказоустойчивость

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

Основные из них:

  • Таймауты — не ждите ответа вечно.
  • Повторные попытки (retry) — если запрос не удался, попробуйте ещё раз (но с ограничением).
  • Предохранитель (circuit breaker) — если сервис часто падает, временно перестаньте к нему обращаться.
  • Запасной вариант (fallback) — верните закешированные данные или значение по умолчанию.

В PHP есть библиотеки, например, php-circuit-breaker. Но можно реализовать простой предохранитель самостоятельно. Пример:

<?php
class CircuitBreaker {
    private $failures = 0;
    private $lastFailureTime = 0;
    private $threshold = 3;
    private $timeout = 60;

    public function call(callable $service) {
        if ($this->isOpen()) {
            throw new Exception('Circuit is open');
        }
        try {
            $result = $service();
            $this->reset();
            return $result;
        } catch (Exception $e) {
            $this->recordFailure();
            throw $e;
        }
    }

    private function isOpen() {
        if ($this->failures < $this->threshold) {
            return false;
        }
        if (time() - $this->lastFailureTime > $this->timeout) {
            $this->reset();
            return false;
        }
        return true;
    }

    private function recordFailure() {
        $this->failures++;
        $this->lastFailureTime = time();
    }

    private function reset() {
        $this->failures = 0;
        $this->lastFailureTime = 0;
    }
}

Этот класс позволяет временно блокировать вызовы к проблемному сервису.

Логирование, мониторинг и развёртывание

Без логов и мониторинга микросервисы превращаются в чёрный ящик. Нужно понимать, что происходит в каждом сервисе. Используйте PSR-3 логгер, например, Monolog.

composer require monolog/monolog

Пример настройки логирования в Slim:

<?php
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$logger = new Logger('my_service');
$logger->pushHandler(new StreamHandler(__DIR__ . '/../logs/app.log', Logger::DEBUG));

$app->add(function ($request, $handler) use ($logger) {
    $logger->info('Request', ['method' => $request->getMethod(), 'uri' => $request->getUri()]);
    $response = $handler->handle($request);
    $logger->info('Response', ['status' => $response->getStatusCode()]);
    return $response;
});

Для мониторинга можно использовать Prometheus + Grafana. Но на первых порах достаточно смотреть логи и настроить простые health-check эндпоинты.

Развёртывание: каждый сервис упаковывается в Docker-образ и запускается отдельно. Можно использовать docker-compose для локальной разработки и Kubernetes для продакшена.

Пример Dockerfile для PHP-сервиса:

FROM php:8.1-apache
COPY . /var/www/html/
RUN docker-php-ext-install pdo pdo_mysql
EXPOSE 80

Не забудьте про CI/CD — автоматическую сборку и деплой. GitHub Actions или GitLab CI помогут.

Практические советы и типичные ошибки

Вот несколько советов, которые сэкономят вам время и нервы:

  • Не делайте микросервисы слишком мелкими. Если сервис состоит из одной функции, это overhead. Балансируйте.
  • Используйте API Gateway. Он будет единой точкой входа для клиентов и маршрутизировать запросы к сервисам.
  • Продумайте версионирование API. Добавляйте префикс /v1/ в URL, чтобы не ломать клиентов при изменениях.
  • Автоматизируйте тестирование. Юнит-тесты и интеграционные тесты обязательны.
  • Следите за состоянием сервисов. Health-check эндпоинт должен возвращать 200 OK, если сервис жив.

Типичные ошибки новичков:

  • Синхронные вызовы между сервисами без таймаутов.
  • Общая база данных для нескольких сервисов (это антипаттерн).
  • Игнорирование идемпотентности операций (повторный запрос может создать дубликат).

Вот таблица, которая поможет выбрать способ взаимодействия между сервисами:

Способ Когда использовать Плюсы Минусы
HTTP/REST Простые синхронные запросы Простота, понятность Зависимость от доступности
gRPC Высокая производительность, строгие контракты Быстро, эффективно Сложнее в настройке
Очереди (RabbitMQ, Kafka) Асинхронная обработка, развязка сервисов Устойчивость к нагрузкам Сложность отладки

Заключение

Разработка PHP микросервисов с нуля — задача не на один день, но вполне решаемая. Начните с малого: сделайте один простой сервис, научитесь его деплоить и мониторить. Постепенно добавляйте новые. Главное — не усложняйте без необходимости и всегда думайте о том, как ваша система будет вести себя при сбоях.

Помните, что микросервисы — это инструмент, а не цель. Если монолит справляется, возможно, не стоит его ломать. Но если вы готовы — вперёд, экспериментируйте!

Студия WNDER