Микросервисы на PHP: архитектура и практика от А до Я
В современной веб-разработке монолитная архитектура всё чаще уступает место микросервисам. PHP, несмотря на стереотипы, является отличной платформой для построения распределённых систем. В этой статье мы разберём, как спроектировать и реализовать микросервисную архитектуру на PHP, от теории до практических примеров кода.
1. Что такое микросервисы и почему PHP?
Микросервисная архитектура — это подход, при котором приложение разбивается на небольшие, независимо развёртываемые сервисы. Каждый сервис отвечает за свою бизнес-функцию и взаимодействует с другими через лёгкие протоколы (обычно HTTP/REST или очереди сообщений).
Почему PHP подходит для микросервисов?
- Быстрая разработка и низкий порог входа
- Богатая экосистема фреймворков (Laravel, Symfony, Slim)
- Отличная поддержка Docker и контейнеризации
- Множество библиотек для работы с очередями (RabbitMQ, Redis)
- Хорошая совместимость с API-шлюзами
2. Архитектура микросервисного приложения на PHP
Давайте рассмотрим типовую архитектуру для интернет-магазина, разбитого на микросервисы:
// Структура проекта
/user-service - управление пользователями
/product-service - каталог товаров
/order-service - обработка заказов
/payment-service - оплата
/api-gateway - единая точка входа
Ключевые принципы:
- Независимые базы данных — каждый сервис имеет свою БД
- Слабая связанность — сервисы общаются только через API
- Отказоустойчивость — падение одного сервиса не ломает всё приложение
- Масштабирование — можно увеличивать мощность только проблемных сервисов
3. Практическая реализация: создаём микросервис на PHP
Напишем простой микросервис для управления пользователями с использованием фреймворка Slim 4.
3.1. Базовая структура сервиса
<?php
// public/index.php - точка входа микросервиса
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
// Middleware для CORS и JSON
$app->addBodyParsingMiddleware();
$app->addErrorMiddleware(true, true, true);
// Маршруты
$app->get('/users', function (Request $request, Response $response) {
$users = [
['id' => 1, 'name' => 'Иван', 'email' => 'ivan@example.com'],
['id' => 2, 'name' => 'Мария', 'email' => 'maria@example.com']
];
$payload = json_encode($users);
$response->getBody()->write($payload);
return $response->withHeader('Content-Type', 'application/json');
});
$app->post('/users', function (Request $request, Response $response) {
$data = $request->getParsedBody();
// Логика сохранения пользователя в БД
$newUser = [
'id' => rand(100, 999),
'name' => $data['name'],
'email' => $data['email']
];
$payload = json_encode($newUser);
$response->getBody()->write($payload);
return $response->withHeader('Content-Type', 'application/json')->withStatus(201);
});
$app->run();
3.2. Взаимодействие между сервисами
Для связи между микросервисами используем GuzzleHttp — мощный HTTP-клиент для PHP:
<?php
// Пример вызова user-service из order-service
require 'vendor/autoload.php';
use GuzzleHttp\Client;
class UserServiceClient
{
private $client;
public function __construct()
{
$this->client = new Client([
'base_uri' => 'http://user-service:8080',
'timeout' => 2.0,
]);
}
public function getUser(int $id): array
{
try {
$response = $this->client->get("/users/{$id}");
return json_decode($response->getBody(), true);
} catch (\Exception $e) {
// Обработка ошибок и fallback
return ['error' => 'User service unavailable'];
}
}
}
// Использование
$userClient = new UserServiceClient();
$user = $userClient->getUser(1);
3.3. Асинхронное взаимодействие через очереди
Для событий, не требующих немедленного ответа (отправка email, обновление статистики), используем RabbitMQ:
<?php
// Отправка события в очередь (publisher.php)
require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;
$connection = new AMQPStreamConnection('rabbitmq', 5672, 'guest', 'guest');
$channel = $connection->channel();
$channel->queue_declare('order_created', false, true, false, false);
$data = json_encode([
'order_id' => 12345,
'user_id' => 1,
'total' => 1500.00,
'timestamp' => time()
]);
$msg = new AMQPMessage($data, ['delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT]);
$channel->basic_publish($msg, '', 'order_created');
echo " [x] Sent order event\n";
$channel->close();
$connection->close();
4. Docker-контейнеризация микросервисов
Для удобного развёртывания и изоляции сервисов используем Docker Compose:
# docker-compose.yml
version: '3.8'
services:
api-gateway:
build: ./api-gateway
ports:
- "80:80"
depends_on:
- user-service
- product-service
user-service:
build: ./user-service
ports:
- "8081:80"
environment: