API gateway: PHP, Node, Go, Rust — gRPC и RabbitMQ
В микросервизната архитектура „API gateway“ обикновено означава публичен периметър: TLS, маршрутизация, удостоверяване, ограничения на честотата и понякога BFF, който сглобява отговор за уеб или мобилен клиент. Зад този слой услугите говорят по друг начин — често чрез gRPC (синхронен RPC) или брокери на съобщения като RabbitMQ (асинхронна доставка). Нито един избор не е „единствено верният стек“: се различават операционната цена, уменията на екипа и сценариите на отказ.
Свързани материали: PHP на сървъра — FPM, Swoole, workers · Sail: RabbitMQ и опашки
Съдържание
- Какво всъщност прави шлюзът
- PHP като слой на шлюза
- Node.js на периметъра
- Go за шлюзове и сайдкари
- Rust, когато микросекундите имат значение
- Вътрешни извиквания: gRPC
- Вътрешна работа: RabbitMQ
- Кога да комбинирате gRPC и опашки
- Сравнителна таблица
- Рецепти
Какво всъщност прави шлюзът
Типични отговорности:
- Вход — HTTP/HTTPS от интернет; HTTP/3 често завършва при балансьора.
- Политики — проверка на JWT, API ключове, IP списъци, връзка с WAF.
- Форма на трафика — rate limiting, лимити на размера на тялото, таймаути.
- Маршрутизация — префикси на пътища към кластери (
/billing/*→ billing). - Агрегация (по избор) — BFF вика няколко бекенда и връща един JSON.
Точки (1)–(5) могат да се реализират в приложен код (PHP, Node, Go, Rust) или да се делегират на Envoy, Traefik, Kong, NGINX или облачен API gateway, като в езика остане само BFF. В продъкшън често е смесица: nginx прекратява TLS, Kong слага плъгини, малък сервис на Go или PHP добавя домейн-специфична авторизация.
PHP като слой на шлюза
Кога пасва
- Екипът вече поддържа Laravel или Symfony; искате един контур за публичен HTTP и част от оркестрацията.
- Шлюзът не е „глупав прокси на милиони RPS“, а място за сесии, OAuth, HTML грешки или сървърни UI фрагменти.
- Приемате модела FPM на заявка (или Octane) и хоризонтално мащабиране зад балансьор.
Плюсове
- Бързи функции: удостоверяване, валидация, преводи, бизнес правила.
- Екосистема: HTTP клиенти, OpenAPI, опашки за странични ефекти.
- По-лесно наемане и ревю от при изцяло полиглотен периметър.
Минуси
- При FPM по-скъп старт на заявка от мини Go бинарник (намалява се с Opcache, preload, внимателен автолоад).
- Лесно е да се натовари пулът от workers с тежки синхронни извиквания в middleware.
- Масов WebSocket от една машина може да насочи към Swoole/Octane или отделен прокси.
Мини-рецепт (в духа на Laravel)
Групи маршрути с throttle и auth; навън — HTTP клиент:
<?php
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Route;
Route::middleware(['throttle:api', 'auth:sanctum'])->prefix('v1')->group(function () {
Route::get('/orders/{id}', function (string $id) {
$response = Http::timeout(3)
->withHeaders(['X-Internal-Token' => config('services.billing.token')])
->get(config('services.billing.url')."/orders/{$id}");
abort_unless($response->successful(), $response->status());
return $response->json();
});
});
Памет и стабилност: третирайте шлюза като високонатоварен PHP — без неограничени кешове на потребителски данни в static, навсякъде таймаути към външни услуги, pm.max_requests (FPM) или рециклиране на workers (Octane), ако RSS расте под натоварване.
Node.js на периметъра
Кога пасва
- Нужен е тънък BFF с много паралелни HTTP към апстрийми.
- В шлюза участват фронтенд разработчици; JSON и SSR инструментите са познати.
- Нужна е голяма npm екосистема (OpenTelemetry, GraphQL, WebSocket).
Плюсове
- Естествен модел за много паралелни изходящи HTTP с
async/await. - Много бърз цикъл за сглобяване на API и прототипи.
Минуси
- Нужна е дисциплина: блокиране на event loop с тежък CPU или синхронен I/O вреди на всички заявки.
- Дърво от зависимости и supply-chain рискове без заковки и одит.
- Нативни добавки и ъпгрейди на рунтайма увеличават операционната повърхност.
Мини-рецепт (набросък Fastify)
npm init -y
npm install fastify @fastify/http-proxy
import Fastify from 'fastify';
import proxy from '@fastify/http-proxy';
const app = Fastify({ logger: true });
app.register(proxy, {
upstream: 'http://billing.internal',
prefix: '/billing',
rewritePrefix: '/v1',
});
await app.listen({ port: 3000, host: '0.0.0.0' });
Go за шлюзове и сайдкари
Кога пасва
- Искате един статичен бинарник, предсказуем GC, прост контейнер за Linux.
- Периметърът или вътрешният слой говори gRPC или реализира собствено балансиране.
- Платформеният екип стандартизира библиотеки.
Плюсове
- Силни примитиви за конкурентност при I/O-bound шлюзове.
- Култура към наблюдаемост (pprof, OpenTelemetry).
- Зрели grpc-go и grpc-gateway (HTTP JSON → gRPC).
Минуси
- Не на всеки му харесват шаблоните за грешки и многословността спрямо PHP/Python.
- Codegen от protobuf добавя стъпки в CI.
Мини-рецепт (grpcurl)
go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
grpcurl -plaintext localhost:50051 list
Rust, когато микросекундите имат значение
Кога пасва
- Строги бюджети за закъснение, важни алокации или парсинг на критично за сигурността място.
- Готови сте да платите време за компилация и строг borrow checker.
Плюсове
- Предсказуема производителност и безопасност на паметта без история с GC паузи.
- Tonic (gRPC) и Axum (HTTP) са чест избор в нови проекти.
Минуси
- Включване на нови хора е по-скъпо от PHP или Node за типичен уеб екип.
- По-бавни итерации, ако всеки деплой чака пълна прекомпилация в CI.
Чест компромис: Rust или Go за един услуга за политики/удостоверяване, PHP — за основния CRUD.
Вътрешни извиквания: gRPC
gRPC обикновено означава HTTP/2, договори Protobuf и генерирани заглушки на всеки език.
Плюсове
- Силен договор — полетата и типовете са явни; счупени промени личат при codegen.
- По-компактно от JSON по жицата; стрийминг за големи данни.
- Метаданни за трасиране и удостоверяване на всяко извикване.
Минуси
- Браузърът не говори „чист“ gRPC — нужен е gRPC-Web и прокси.
- По-трудно дебъгване от
curlкъм JSON без grpcurl и добри логове/метрики. - Балансьорите трябва коректно да маршрутизират HTTP/2 към gRPC.
PHP: официално или community gRPC разширение + генерирани класове; винаги задавайте таймаути и лимити на повторения. За нови вътрешни API уговорете deadline (grpc-timeout) между услугите.
Вътрешна работа: RabbitMQ
RabbitMQ е AMQP брокер: издатели изпращат към exchange, опашките се връзват с ключове, консуматорите правят ack / nack.
Плюсове
- Разкачване във времето — пиковете се буферират при брокера.
- Шаблони: работна опашка, pub/sub, topic, отложена доставка (внимателно с плъгини).
- Зряла експлоатация: клъстер, огледални опашки (classic), quorum queues в съвременни схеми.
Минуси
- Това не е база данни — ако консуматорите са спрели, опашките растат; нужни са мониторинг и DLQ.
- Точно веднъж край до край не се гарантира; проектирайте идемпотентни обработчици.
- Разследване на „изчезнало съобщение“ без correlation id и структурни логове е мъка.
PHP (Laravel): QUEUE_CONNECTION=rabbitmq с пакет като vladimir-yuldashev/laravel-queue-rabbitmq; локално вижте гайда за Sail и опашки. Не излагайте RabbitMQ в интернет без TLS и акаунти.
Кога да комбинирате gRPC и опашки
- Команда: HTTP → шлюз → публикуване на „OrderPlaced“ в RabbitMQ → workers изпълняват. На клиента — 202 + id или outbox + анкетиране на статус.
- Заявка: HTTP → шлюз → gRPC към read услуга с кеш — ниска латентност, синхронен отговор.
- Саги / компенсации: съобщения с идемпотентни обработчици и ясни таймаути.
Не превръщайте опашката в скрит RPC без дедлайни: „изпратихме и се надяваме“ не понася частични откази.
Сравнителна таблица
| Слой / инструмент | Добре, когато… | Помислете пак, когато… |
|---|---|---|
| PHP шлюз | Умения на екипа, богата логика на периметъра, стек Laravel/Symfony | Трябва почти голи прокси на екстремен RPS |
| Node шлюз | BFF с много паралелен HTTP, JS организация | Тежък CPU на горещия път |
| Go шлюз | Малък бинарник, gRPC мрежа, платформен стандарт | Няма ресурс за поддръжка на Go |
| Rust шлюз | Строги SLA за закъснение/памет | Екипът е само на PHP и трябва бърз MVP |
| gRPC вътрешно | Типизирани договори, стрийминг, полиглот | Публичен браузърен клиент без междинни слоеве |
| RabbitMQ | Поглъщане на пикове, асинхронни процеси, мащаб на консуматори | Всъщност ви трябва синхронен заявка-отговор |
Рецепти
RabbitMQ локално (Docker)
docker run -d --hostname rabbit --name rabbit \
-p 5672:5672 -p 15672:15672 \
-e RABBITMQ_DEFAULT_USER=guest -e RABBITMQ_DEFAULT_PASS=guest \
rabbitmq:4-management
Уеб интерфейс: http://localhost:15672 (в битие сменете паролите).
Деклариране на опашка през CLI
docker exec rabbit rabbitmqadmin declare queue name=orders durable=true
Минимален Protobuf (илюстрация)
order.proto:
syntax = "proto3";
package billing.v1;
message GetOrderRequest { string id = 1; }
message GetOrderResponse { string id = 1; string status = 2; }
service Orders {
rpc Get(GetOrderRequest) returns (GetOrderResponse);
}
Пускайте protoc с grpc_php_plugin (и плъгини за други езици) в CI; или комитирайте генерирания код, или генерирайте в Docker — изберете едно правило за хранилището.
Фрагмент .env на Laravel за RabbitMQ
QUEUE_CONNECTION=rabbitmq
RABBITMQ_HOST=rabbit
RABBITMQ_PORT=5672
RABBITMQ_USER=guest
RABBITMQ_PASSWORD=guest
RABBITMQ_QUEUE=default
Срещу „тихи“ откази
- Пренасяйте
X-Request-Idот шлюза в gRPC метаданни и заглавки на съобщения. - Слагайте deadline на gRPC и TTL / DLX на критични опашки.
- На един държете дълбочина на опашките, натоварване на консуматорите и p95 латентност на шлюза.
Още материали
- Документация на RabbitMQ
- Документация на gRPC
- Envoy — когато периметърът е предимно политика и маршрутизация
- Sail: RabbitMQ и опашки — рецепти на този сайт
- Опашки в Laravel (официална документация)