Микросервисная архитектура требует надежной коммуникации между сервисами, защиты внешних API-запросов и балансировки нагрузки. Прокси-серверы решают эти задачи, выступая посредниками между сервисами, внешними API и клиентами. В этом руководстве разберем, как правильно интегрировать прокси в микросервисную инфраструктуру, какие типы прокси использовать для разных сценариев и как настроить безопасную коммуникацию.
Роль прокси в микросервисной архитектуре
В микросервисной архитектуре прокси-серверы выполняют несколько критически важных функций, которые отличаются от традиционного использования прокси для анонимизации или обхода блокировок. Здесь прокси становятся неотъемлемой частью инфраструктуры, обеспечивая надежную и безопасную коммуникацию между компонентами системы.
Основные роли прокси в микросервисах:
- API Gateway — единая точка входа для всех клиентских запросов, которая маршрутизирует их к соответствующим микросервисам, скрывая внутреннюю архитектуру системы
- Sidecar Proxy — прокси-контейнер, который работает рядом с каждым сервисом (паттерн Service Mesh), перехватывая весь входящий и исходящий трафик
- Reverse Proxy — распределение нагрузки между несколькими экземплярами одного сервиса, обеспечение отказоустойчивости
- Forward Proxy — контроль и защита исходящих запросов к внешним API, скрытие внутренних IP-адресов инфраструктуры
- Прокси безопасности — терминация SSL/TLS, аутентификация, авторизация, защита от DDoS и других атак
Прокси позволяют реализовать важные архитектурные паттерны: circuit breaker (автоматическое отключение неработающих сервисов), retry logic (повторные попытки при сбоях), rate limiting (ограничение частоты запросов), request/response transformation (преобразование форматов данных). Все это делает систему более устойчивой к сбоям и упрощает управление сложной распределенной инфраструктурой.
Важно: В микросервисной архитектуре прокси работают на двух уровнях — как внешний шлюз для клиентов (API Gateway) и как внутренние прокси между сервисами (Service Mesh). Оба уровня критически важны для безопасности и надежности системы.
Типы прокси для разных сценариев использования
Выбор типа прокси зависит от конкретной задачи в микросервисной архитектуре. Разные сценарии требуют разных характеристик: скорости, надежности, анонимности или географического распределения.
| Сценарий | Тип прокси | Почему |
|---|---|---|
| Внутренняя коммуникация сервисов | HTTP/HTTPS прокси (Envoy, NGINX) | Максимальная скорость, низкая задержка, поддержка HTTP/2 |
| Запросы к внешним API с лимитами | Резидентные прокси | Обход rate limits, реальные IP пользователей, низкий риск блокировок |
| Парсинг данных для аналитики | Прокси дата-центров | Высокая скорость, низкая стоимость, подходит для массовых запросов |
| Работа с мобильными API | Мобильные прокси | Имитация реальных мобильных пользователей, доступ к mobile-only API |
| Балансировка нагрузки | Reverse Proxy (HAProxy, NGINX) | Распределение трафика, health checks, автоматическое переключение при сбоях |
| Географически распределенная система | Резидентные прокси с geo-таргетингом | Доступ к региональным API, соответствие требованиям локализации данных |
Для внутренней коммуникации между микросервисами обычно используются специализированные прокси-решения вроде Envoy Proxy или NGINX, которые оптимизированы для низкой задержки и высокой пропускной способности. Они поддерживают современные протоколы (HTTP/2, gRPC) и интегрируются с системами Service Mesh.
Для работы с внешними API выбор зависит от требований конкретного сервиса. Если API имеет жесткие rate limits или блокирует запросы с IP дата-центров, нужны резидентные прокси. Для массового сбора данных, где скорость важнее анонимности, подойдут прокси дата-центров. Мобильные прокси необходимы при работе с API, которые проверяют тип устройства или требуют мобильных IP-адресов.
Прокси как API Gateway: защита и маршрутизация
API Gateway — это специализированный прокси-сервер, который выступает единой точкой входа для всех клиентских запросов к микросервисной системе. Вместо того чтобы клиенты напрямую обращались к десяткам разных сервисов, они отправляют все запросы на один адрес API Gateway, который маршрутизирует их к нужным сервисам.
Основные функции API Gateway:
- Маршрутизация запросов — определение, какой микросервис должен обработать запрос, на основе URL, заголовков или других параметров
- Аутентификация и авторизация — проверка токенов (JWT, OAuth), управление доступом к разным сервисам
- Rate Limiting — ограничение количества запросов от одного клиента для защиты от перегрузки и DDoS
- Агрегация ответов — объединение данных от нескольких сервисов в один ответ клиенту
- Преобразование протоколов — конвертация REST в gRPC, HTTP/1.1 в HTTP/2
- Кэширование — сохранение часто запрашиваемых данных для снижения нагрузки на сервисы
- Логирование и мониторинг — централизованный сбор метрик и логов всех запросов
Популярные решения для API Gateway: Kong, Tyk, AWS API Gateway, Azure API Management, NGINX Plus, Traefik. Выбор зависит от масштаба системы, требований к производительности и используемой облачной платформы.
// Пример конфигурации NGINX как API Gateway
upstream auth_service {
server auth:8001;
}
upstream user_service {
server user:8002;
}
upstream order_service {
server order:8003;
}
server {
listen 80;
server_name api.example.com;
# Ограничение частоты запросов
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
location /api/auth/ {
limit_req zone=api_limit burst=20;
proxy_pass http://auth_service/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /api/users/ {
# Проверка токена перед проксированием
auth_request /auth/verify;
proxy_pass http://user_service/;
}
location /api/orders/ {
auth_request /auth/verify;
proxy_pass http://order_service/;
}
# Внутренний endpoint для проверки токенов
location = /auth/verify {
internal;
proxy_pass http://auth_service/verify;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
}
}
API Gateway скрывает внутреннюю архитектуру системы от внешних клиентов. Клиенты не знают, сколько микросервисов существует и как они взаимодействуют — они видят только единый API. Это упрощает версионирование, позволяет изменять внутреннюю структуру без влияния на клиентов и улучшает безопасность, так как внутренние сервисы не доступны напрямую из интернета.
Интеграция с Service Mesh (Istio, Linkerd)
Service Mesh — это инфраструктурный слой, который управляет коммуникацией между микросервисами с помощью прокси-серверов, развернутых рядом с каждым сервисом (паттерн Sidecar). В отличие от API Gateway, который обрабатывает только внешний трафик, Service Mesh контролирует весь внутренний трафик между сервисами.
Самые популярные решения Service Mesh — Istio (использует Envoy Proxy как sidecar) и Linkerd (использует собственный легковесный прокси). Они автоматически внедряют прокси-контейнер рядом с каждым pod в Kubernetes, перехватывая весь входящий и исходящий трафик.
Возможности Service Mesh через прокси:
- Mutual TLS (mTLS) — автоматическое шифрование всего трафика между сервисами с взаимной аутентификацией
- Traffic Management — управление маршрутизацией, канареечные развертывания, A/B тестирование
- Observability — автоматический сбор метрик, трейсов и логов без изменения кода сервисов
- Resilience — circuit breaking, retry logic, timeout management, fault injection для тестирования
- Service Discovery — автоматическое обнаружение сервисов и балансировка нагрузки
# Пример конфигурации Istio VirtualService для маршрутизации
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: user-service
spec:
hosts:
- user-service
http:
- match:
- headers:
version:
exact: "v2"
route:
- destination:
host: user-service
subset: v2
- route:
- destination:
host: user-service
subset: v1
weight: 90
- destination:
host: user-service
subset: v2
weight: 10 # Канареечное развертывание: 10% трафика на v2
---
# Circuit Breaker для защиты от каскадных сбоев
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: user-service
spec:
host: user-service
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
http1MaxPendingRequests: 50
maxRequestsPerConnection: 2
outlierDetection:
consecutiveErrors: 5
interval: 30s
baseEjectionTime: 30s
maxEjectionPercent: 50
Service Mesh решает проблему "распределенного монолита" — когда логика взаимодействия между сервисами (retry, timeout, circuit breaking) дублируется в коде каждого сервиса. Вместо этого вся эта логика выносится в прокси-слой, что упрощает код сервисов и обеспечивает единообразное поведение всей системы.
Важное преимущество — полная прозрачность трафика. Каждый запрос между сервисами проходит через прокси, который логирует метрики: время отклика, коды ошибок, размер payload. Эти данные автоматически отправляются в системы мониторинга (Prometheus, Grafana) и трейсинга (Jaeger, Zipkin), создавая полную картину работы распределенной системы без необходимости добавлять инструментацию в код каждого сервиса.
Защита запросов к внешним API через прокси
Микросервисы часто взаимодействуют с внешними API: платежные системы, сервисы геолокации, API социальных сетей, поставщики данных. Прямые запросы к внешним API создают несколько проблем: раскрытие внутренних IP-адресов инфраструктуры, риск блокировки при превышении rate limits, отсутствие контроля над исходящим трафиком.
Использование прокси для исходящих запросов решает эти проблемы и добавляет дополнительные возможности:
- Скрытие инфраструктуры — внешние API видят IP-адреса прокси, а не ваших серверов
- Обход rate limits — ротация IP-адресов для распределения запросов
- Географическое распределение — доступ к региональным API через прокси в нужных странах
- Централизованное управление — единая точка контроля всех исходящих запросов
- Кэширование ответов — снижение количества запросов к дорогим API
- Мониторинг и логирование — отслеживание всех обращений к внешним сервисам
// Python: настройка прокси для requests к внешним API
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
class ExternalAPIClient:
def __init__(self, proxy_url, proxy_rotation=False):
self.session = requests.Session()
# Настройка прокси
self.proxies = {
'http': proxy_url,
'https': proxy_url
}
# Retry логика для устойчивости
retry_strategy = Retry(
total=3,
backoff_factor=1,
status_forcelist=[429, 500, 502, 503, 504],
allowed_methods=["GET", "POST"]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
self.session.mount("http://", adapter)
self.session.mount("https://", adapter)
def call_payment_api(self, data):
"""Запрос к платежному API через прокси"""
try:
response = self.session.post(
'https://api.payment-provider.com/charge',
json=data,
proxies=self.proxies,
timeout=10,
headers={'User-Agent': 'MyService/1.0'}
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
# Логирование ошибки
print(f"Payment API error: {e}")
raise
# Использование с пулом прокси для ротации
class ProxyPool:
def __init__(self, proxy_list):
self.proxies = proxy_list
self.current = 0
def get_next(self):
proxy = self.proxies[self.current]
self.current = (self.current + 1) % len(self.proxies)
return proxy
# Инициализация
proxy_pool = ProxyPool([
'http://user:pass@proxy1.example.com:8080',
'http://user:pass@proxy2.example.com:8080',
'http://user:pass@proxy3.example.com:8080'
])
# Для каждого запроса используем следующий прокси
client = ExternalAPIClient(proxy_pool.get_next())
Для работы с внешними API, которые имеют строгие ограничения или блокируют запросы с IP дата-центров, резидентные прокси становятся необходимостью. Они предоставляют реальные IP-адреса домашних пользователей, что снижает риск блокировки и позволяет обходить географические ограничения.
// Node.js: прокси для внешних API с автоматической ротацией
const axios = require('axios');
const HttpsProxyAgent = require('https-proxy-agent');
class ExternalAPIService {
constructor(proxyList) {
this.proxyList = proxyList;
this.currentProxyIndex = 0;
this.requestCounts = new Map(); // Счетчик запросов для rate limiting
}
getNextProxy() {
const proxy = this.proxyList[this.currentProxyIndex];
this.currentProxyIndex = (this.currentProxyIndex + 1) % this.proxyList.length;
return proxy;
}
async callAPI(endpoint, data, options = {}) {
const proxyUrl = this.getNextProxy();
const agent = new HttpsProxyAgent(proxyUrl);
// Rate limiting: не более 100 запросов в минуту на прокси
const proxyKey = proxyUrl;
const now = Date.now();
const count = this.requestCounts.get(proxyKey) || { count: 0, resetTime: now + 60000 };
if (count.count >= 100 && now < count.resetTime) {
// Переключаемся на следующий прокси
return this.callAPI(endpoint, data, options);
}
try {
const response = await axios({
method: options.method || 'POST',
url: endpoint,
data: data,
httpsAgent: agent,
timeout: options.timeout || 10000,
headers: {
'User-Agent': 'Mozilla/5.0 (compatible; MyService/1.0)',
...options.headers
}
});
// Обновляем счетчик
if (now >= count.resetTime) {
this.requestCounts.set(proxyKey, { count: 1, resetTime: now + 60000 });
} else {
count.count++;
}
return response.data;
} catch (error) {
if (error.response?.status === 429) {
// Rate limit exceeded - переключаемся на другой прокси
console.log(`Rate limit on ${proxyUrl}, switching proxy`);
return this.callAPI(endpoint, data, options);
}
throw error;
}
}
}
// Использование
const apiService = new ExternalAPIService([
'http://user:pass@proxy1.example.com:8080',
'http://user:pass@proxy2.example.com:8080'
]);
module.exports = apiService;
Балансировка нагрузки и отказоустойчивость
Прокси-серверы играют ключевую роль в обеспечении высокой доступности микросервисной системы через балансировку нагрузки и автоматическое переключение при сбоях. Когда у вас запущено несколько экземпляров одного сервиса (для горизонтального масштабирования), прокси распределяет запросы между ними, обеспечивая равномерную нагрузку.
Основные алгоритмы балансировки нагрузки:
- Round Robin — поочередная отправка запросов на каждый сервер в списке, простой и эффективный для однородных серверов
- Least Connections — отправка запроса на сервер с наименьшим количеством активных соединений, подходит для долгих запросов
- IP Hash — привязка клиента к конкретному серверу на основе его IP, обеспечивает sticky sessions
- Weighted Round Robin — распределение с учетом мощности серверов (более мощные получают больше запросов)
- Random — случайный выбор сервера, подходит для stateless сервисов
# HAProxy конфигурация для балансировки с health checks
global
maxconn 4096
log stdout format raw local0
defaults
mode http
timeout connect 5s
timeout client 50s
timeout server 50s
option httplog
frontend api_frontend
bind *:80
default_backend api_servers
backend api_servers
balance roundrobin
# Health check: проверка /health каждые 2 секунды
option httpchk GET /health
http-check expect status 200
# Retry логика
retries 3
option redispatch
# Серверы с весами (server3 в 2 раза мощнее)
server server1 10.0.1.10:8080 check weight 1 maxconn 500
server server2 10.0.1.11:8080 check weight 1 maxconn 500
server server3 10.0.1.12:8080 check weight 2 maxconn 1000
# Резервный сервер (используется только если основные недоступны)
server backup1 10.0.2.10:8080 check backup
Health checks — критически важная функция для отказоустойчивости. Прокси регулярно проверяет доступность каждого сервера (обычно через HTTP endpoint /health или /ready) и автоматически исключает неработающие серверы из пула балансировки. Когда сервер восстанавливается и начинает отвечать на health checks, он автоматически возвращается в пул.
Стратегии отказоустойчивости через прокси:
- Active Health Checks — прокси активно опрашивает серверы для проверки их доступности
- Passive Health Checks — прокси отслеживает реальные запросы и исключает серверы при накоплении ошибок
- Circuit Breaker — временное отключение проблемного сервиса для предотвращения каскадных сбоев
- Graceful Degradation — переключение на упрощенный режим работы или кэшированные данные при сбоях
- Failover to Backup — автоматическое переключение на резервные серверы или регионы
// Python: реализация Circuit Breaker для прокси к внешним сервисам
from datetime import datetime, timedelta
from enum import Enum
class CircuitState(Enum):
CLOSED = "closed" # Нормальная работа
OPEN = "open" # Сервис недоступен, запросы блокируются
HALF_OPEN = "half_open" # Тестовый режим после восстановления
class CircuitBreaker:
def __init__(self, failure_threshold=5, timeout=60, success_threshold=2):
self.failure_threshold = failure_threshold # Ошибок до открытия
self.timeout = timeout # Секунд до попытки восстановления
self.success_threshold = success_threshold # Успехов для закрытия
self.state = CircuitState.CLOSED
self.failures = 0
self.successes = 0
self.last_failure_time = None
def call(self, func, *args, **kwargs):
if self.state == CircuitState.OPEN:
if datetime.now() - self.last_failure_time > timedelta(seconds=self.timeout):
self.state = CircuitState.HALF_OPEN
print("Circuit breaker: переход в HALF_OPEN")
else:
raise Exception("Circuit breaker OPEN: сервис недоступен")
try:
result = func(*args, **kwargs)
self._on_success()
return result
except Exception as e:
self._on_failure()
raise e
def _on_success(self):
self.failures = 0
if self.state == CircuitState.HALF_OPEN:
self.successes += 1
if self.successes >= self.success_threshold:
self.state = CircuitState.CLOSED
self.successes = 0
print("Circuit breaker: восстановление, переход в CLOSED")
def _on_failure(self):
self.failures += 1
self.last_failure_time = datetime.now()
if self.failures >= self.failure_threshold:
self.state = CircuitState.OPEN
print(f"Circuit breaker OPEN: {self.failures} ошибок подряд")
# Использование
breaker = CircuitBreaker(failure_threshold=3, timeout=30)
def call_external_service():
# Ваш код запроса к внешнему API через прокси
pass
try:
result = breaker.call(call_external_service)
except Exception as e:
# Fallback логика: кэш, дефолтные значения и т.д.
print(f"Сервис недоступен: {e}")
Безопасность коммуникации между сервисами
В микросервисной архитектуре прокси-серверы обеспечивают несколько уровней безопасности: шифрование трафика, аутентификацию сервисов, защиту от атак и изоляцию сетевых сегментов. Без правильной настройки безопасности внутренний трафик между сервисами может быть перехвачен или подделан.
Ключевые аспекты безопасности через прокси:
- Mutual TLS (mTLS) — двусторонняя аутентификация, когда и клиент, и сервер проверяют сертификаты друг друга. Service Mesh автоматически настраивает mTLS между всеми сервисами
- TLS Termination — прокси расшифровывает HTTPS-трафик на границе, проверяет его и передает сервисам по защищенному каналу
- JWT Validation — проверка токенов доступа на уровне прокси, до того как запрос дойдет до сервиса
- IP Whitelisting — ограничение доступа к сервисам только с разрешенных IP-адресов
- DDoS Protection — rate limiting, connection limits, защита от SYN flood на уровне прокси
- WAF (Web Application Firewall) — фильтрация вредоносных запросов, защита от SQL injection, XSS
# NGINX конфигурация с SSL/TLS и безопасностью
server {
listen 443 ssl http2;
server_name api.internal.example.com;
# SSL сертификаты
ssl_certificate /etc/nginx/certs/api.crt;
ssl_certificate_key /etc/nginx/certs/api.key;
# Современные протоколы и шифры
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# Client certificate для mTLS
ssl_client_certificate /etc/nginx/certs/ca.crt;
ssl_verify_client on;
# Безопасные заголовки
add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
# Rate limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=100r/s;
limit_req zone=api burst=200 nodelay;
# Connection limiting
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn addr 10;
# IP whitelisting
allow 10.0.0.0/8; # Внутренняя сеть
allow 172.16.0.0/12; # VPC
deny all;
location / {
# Проверка JWT токена
auth_jwt "Restricted API";
auth_jwt_key_file /etc/nginx/jwt_key.json;
proxy_pass http://backend_service;
# Передача информации о клиентском сертификате
proxy_set_header X-Client-DN $ssl_client_s_dn;
proxy_set_header X-Client-Verify $ssl_client_verify;
}
}
Service Mesh значительно упрощает настройку безопасности, автоматически генерируя и ротируя сертификаты для mTLS, применяя политики доступа и шифруя весь трафик между сервисами. Например, в Istio можно задать политику, что сервис "payment" может принимать запросы только от сервиса "order", и это будет автоматически применено на уровне прокси без изменения кода сервисов.
Важно для production: Всегда используйте mTLS для внутренней коммуникации сервисов, даже если они находятся в одной приватной сети. Это защищает от атак типа man-in-the-middle и обеспечивает аутентификацию на уровне сервисов, а не только на уровне сети.
Мониторинг и логирование прокси-трафика
Прокси-серверы предоставляют уникальную возможность для централизованного мониторинга всего трафика в микросервисной системе. Поскольку весь трафик проходит через прокси (как внешний через API Gateway, так и внутренний через Service Mesh), вы получаете полную видимость работы системы без необходимости инструментировать каждый сервис.
Ключевые метрики для мониторинга на уровне прокси:
- Latency (задержка) — время обработки запроса на каждом этапе: прокси, сервис, внешние API
- Throughput (пропускная способность) — количество запросов в секунду, объем переданных данных
- Error Rate — процент ошибок (4xx, 5xx), типы ошибок, проблемные endpoints
- Connection Metrics — количество активных соединений, connection pool usage
- Circuit Breaker State — состояние circuit breakers для каждого сервиса
- SSL/TLS Metrics — статус сертификатов, версии протоколов, ошибки handshake
# NGINX конфигурация для экспорта метрик в Prometheus
server {
listen 9113;
location /metrics {
stub_status;
access_log off;
allow 10.0.0.0/8; # Только для Prometheus сервера
deny all;
}
}
# Логирование в JSON формате для structured logging
log_format json_combined escape=json
'{'
'"time_local":"$time_local",'
'"remote_addr":"$remote_addr",'
'"request":"$request",'
'"status": "$status",'
'"body_bytes_sent":"$body_bytes_sent",'
'"request_time":"$request_time",'
'"upstream_response_time":"$upstream_response_time",'
'"upstream_addr":"$upstream_addr",'
'"http_referrer":"$http_referer",'
'"http_user_agent":"$http_user_agent",'
'"http_x_forwarded_for":"$http_x_forwarded_for"'
'}';
access_log /var/log/nginx/access.log json_combined;
Distributed Tracing — одна из самых мощных возможностей мониторинга через прокси. Каждый запрос получает уникальный trace ID, который прокси добавляет в заголовки и передает дальше по цепочке сервисов. Системы трейсинга (Jaeger, Zipkin) собирают информацию от всех прокси и строят полный путь запроса через систему, показывая, сколько времени он провел в каждом сервисе.
// Node.js: добавление трейсинга в прокси middleware
const express = require('express');
const { v4: uuidv4 } = require('uuid');
const axios = require('axios');
const app = express();
// Middleware для добавления trace ID
app.use((req, res, next) => {
// Получаем trace ID из заголовка или создаем новый
const traceId = req.headers['x-trace-id'] || uuidv4();
const spanId = uuidv4();
// Добавляем в заголовки для передачи дальше
req.traceId = traceId;
req.spanId = spanId;
res.setHeader('x-trace-id', traceId);
// Логируем начало обработки
const startTime = Date.now();
res.on('finish', () => {
const duration = Date.now() - startTime;
// Structured log для анализа
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
traceId: traceId,
spanId: spanId,
method: req.method,
path: req.path,
status: res.statusCode,
duration: duration,
userAgent: req.headers['user-agent'],
ip: req.ip
}));
});
next();
});
// Прокси endpoint с передачей трacing заголовков
app.all('/api/*', async (req, res) => {
const targetService = determineTargetService(req.path);
try {
const response = await axios({
method: req.method,
url: `http://${targetService}${req.path}`,
data: req.body,
headers: {
...req.headers,
'x-trace-id': req.traceId,
'x-parent-span-id': req.spanId,
'x-span-id': uuidv4() // Новый span для downstream запроса
}
});
res.status(response.status).json(response.data);
} catch (error) {
console.error(JSON.stringify({
traceId: req.traceId,
error: error.message,
service: targetService
}));
res.status(500).json({ error: 'Service unavailable' });
}
});
function determineTargetService(path) {
if (path.startsWith('/api/users')) return 'user-service:8080';
if (path.startsWith('/api/orders')) return 'order-service:8080';
return 'default-service:8080';
}
app.listen(3000);
Алертинг на основе метрик прокси позволяет быстро обнаруживать проблемы. Например, можно настроить алерты на: внезапный рост latency (возможно, один из сервисов деградирует), увеличение error rate выше порога (проблемы с кодом или зависимостями), изменение паттернов трафика (возможная DDoS атака или вирусная нагрузка).
Примеры реализации на Python и Node.js
Рассмотрим практические примеры интеграции прокси в микросервисы на Python и Node.js для разных сценариев: внутренняя коммуникация, работа с внешними API, балансировка нагрузки.
Python: сервис с прокси для внешних API
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import httpx
import asyncio
from typing import List, Optional
import logging
app = FastAPI()
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class ProxyConfig(BaseModel):
url: str
max_requests_per_minute: int = 60
class ProxyPool:
def __init__(self, proxies: List[ProxyConfig]):
self.proxies = proxies
self.current_index = 0
self.request_counts = {p.url: 0 for p in proxies}
self.reset_time = asyncio.get_event_loop().time() + 60
async def get_next_proxy(self) -> str:
# Сброс счетчиков каждую минуту
current_time = asyncio.get_event_loop().time()
if current_time >= self.reset_time:
self.request_counts = {p.url: 0 for p in self.proxies}
self.reset_time = current_time + 60
# Найти прокси с доступными запросами
for _ in range(len(self.proxies)):
proxy = self.proxies[self.current_index]
self.current_index = (self.current_index + 1) % len(self.proxies)
if self.request_counts[proxy.url] < proxy.max_requests_per_minute:
self.request_counts[proxy.url] += 1
return proxy.url
# Все прокси исчерпали лимит
raise HTTPException(status_code=429, detail="All proxies rate limited")
# Инициализация пула прокси
proxy_pool = ProxyPool([
ProxyConfig(url="http://user:pass@proxy1.example.com:8080", max_requests_per_minute=100),
ProxyConfig(url="http://user:pass@proxy2.example.com:8080", max_requests_per_minute=100),
ProxyConfig(url="http://user:pass@proxy3.example.com:8080", max_requests_per_minute=100)
])
class ExternalAPIClient:
def __init__(self, proxy_pool: ProxyPool):
self.proxy_pool = proxy_pool
async def fetch_data(self, endpoint: str, params: dict = None) -> dict:
proxy_url = await self.proxy_pool.get_next_proxy()
async with httpx.AsyncClient(proxies={"http://": proxy_url, "https://": proxy_url}) as client:
try:
response = await client.get(
endpoint,
params=params,
timeout=10.0,
headers={"User-Agent": "MyMicroservice/1.0"}
)
response.raise_for_status()
logger.info(f"Successfully fetched from {endpoint} via {proxy_url}")
return response.json()
except httpx.HTTPStatusError as e:
logger.error(f"HTTP error {e.response.status_code} from {endpoint}")
raise HTTPException(status_code=e.response.status_code, detail=str(e))
except httpx.RequestError as e:
logger.error(f"Request error to {endpoint}: {e}")
raise HTTPException(status_code=503, detail="External API unavailable")
api_client = ExternalAPIClient(proxy_pool)
@app.get("/data/{resource_id}")
async def get_external_data(resource_id: str):
"""Endpoint, который получает данные из внешнего API через прокси"""
external_endpoint = f"https://api.external-service.com/v1/resources/{resource_id}"
try:
data = await api_client.fetch_data(external_endpoint)
return {"status": "success", "data": data}
except HTTPException:
raise
except Exception as e:
logger.error(f"Unexpected error: {e}")
raise HTTPException(status_code=500, detail="Internal server error")
@app.get("/health")
async def health_check():
return {"status": "healthy", "service": "external-api-proxy"}
# Запуск: uvicorn main:app --host 0.0.0.0 --port 8000
Node.js: API Gateway с балансировкой нагрузки
const express = require('express');
const axios = require('axios');
const rateLimit = require('express-rate-limit');
const app = express();
app.use(express.json());
// Конфигурация микросервисов
const services = {
users: [
{ url: 'http://user-service-1:8001', healthy: true, activeConnections: 0 },
{ url: 'http://user-service-2:8001', healthy: true, activeConnections: 0 },