API gateway: PHP, Node, Go, Rust — gRPC и RabbitMQ

В микросервизната архитектура „API gateway“ обикновено означава публичен периметър: TLS, маршрутизация, удостоверяване, ограничения на честотата и понякога BFF, който сглобява отговор за уеб или мобилен клиент. Зад този слой услугите говорят по друг начин — често чрез gRPC (синхронен RPC) или брокери на съобщения като RabbitMQ (асинхронна доставка). Нито един избор не е „единствено верният стек“: се различават операционната цена, уменията на екипа и сценариите на отказ.

Свързани материали: PHP на сървъра — FPM, Swoole, workers · Sail: RabbitMQ и опашки

Съдържание


Какво всъщност прави шлюзът

Типични отговорности:

  1. Вход — HTTP/HTTPS от интернет; HTTP/3 често завършва при балансьора.
  2. Политики — проверка на JWT, API ключове, IP списъци, връзка с WAF.
  3. Форма на трафика — rate limiting, лимити на размера на тялото, таймаути.
  4. Маршрутизация — префикси на пътища към кластери (/billing/* → billing).
  5. Агрегация (по избор) — 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 латентност на шлюза.

Още материали