Mikroservis mimarisi, hizmetler arasında güvenilir iletişim, dış API isteklerinin korunması ve yük dengelemesi gerektirir. Proxy sunucuları, hizmetler, dış API'ler ve istemciler arasında aracılık yaparak bu sorunları çözer. Bu kılavuzda, proxy'yi mikroservis altyapısına nasıl doğru bir şekilde entegre edeceğimizi, farklı senaryolar için hangi proxy türlerini kullanacağımızı ve güvenli iletişimi nasıl ayarlayacağımızı inceleyeceğiz.
Mikroservis mimarisinde proxy'nin rolü
Mikroservis mimarisinde proxy sunucuları, anonimlik veya engelleri aşmak için geleneksel proxy kullanımından farklı olarak birkaç kritik işlevi yerine getirir. Burada proxy, sistem bileşenleri arasında güvenilir ve güvenli iletişim sağlayarak altyapının ayrılmaz bir parçası haline gelir.
Mikroservislerde proxy'nin ana rolleri:
- API Gateway — tüm istemci istekleri için tek giriş noktası, istekleri ilgili mikroservislere yönlendirir ve sistemin iç mimarisini gizler
- Sidecar Proxy — her hizmetin yanında çalışan proxy konteyneri (Service Mesh modeli), tüm gelen ve giden trafiği yakalar
- Reverse Proxy — bir hizmetin birden fazla örneği arasında yük dağılımı, hata toleransı sağlar
- Forward Proxy — dış API'lere yapılan giden isteklerin kontrolü ve korunması, iç altyapının IP adreslerini gizler
- Güvenlik Proxy'si — SSL/TLS sonlandırması, kimlik doğrulama, yetkilendirme, DDoS ve diğer saldırılara karşı koruma
Proxy'ler, önemli mimari kalıpların uygulanmasına olanak tanır: circuit breaker (çalışmayan hizmetlerin otomatik olarak devre dışı bırakılması), retry logic (hatalarda tekrar deneme), rate limiting (istek sıklığının sınırlanması), request/response transformation (veri formatlarının dönüştürülmesi). Tüm bunlar, sistemi hatalara karşı daha dayanıklı hale getirir ve karmaşık dağıtık altyapının yönetimini kolaylaştırır.
Önemli: Mikroservis mimarisinde proxy'ler iki düzeyde çalışır — istemciler için dış bir geçit (API Gateway) ve hizmetler arasında iç proxy'ler (Service Mesh). Her iki düzey de sistemin güvenliği ve güvenilirliği için kritik öneme sahiptir.
Farklı kullanım senaryoları için proxy türleri
Proxy türünün seçimi, mikroservis mimarisindeki belirli bir göreve bağlıdır. Farklı senaryolar, hız, güvenilirlik, anonimlik veya coğrafi dağılım gibi farklı özellikler gerektirir.
| Senaryo | Proxy Türü | Neden |
|---|---|---|
| Hizmetler arası iç iletişim | HTTP/HTTPS proxy (Envoy, NGINX) | Maksimum hız, düşük gecikme, HTTP/2 desteği |
| Rate limitleri olan dış API'lere istekler | Konut proxy'leri | Rate limitlerin aşılması, gerçek kullanıcı IP'leri, düşük blokaj riski |
| Analiz için veri kazıma | Veri merkezi proxy'leri | Yüksek hız, düşük maliyet, toplu istekler için uygun |
| Mobil API'lerle çalışma | Mobil proxy'ler | Gerçek mobil kullanıcıları taklit etme, yalnızca mobil API'lere erişim |
| Yük dengeleme | Reverse Proxy (HAProxy, NGINX) | Trafiğin dağıtımı, sağlık kontrolleri, arızalarda otomatik geçiş |
| Coğrafi olarak dağıtılmış sistem | Coğrafi hedefleme ile konut proxy'leri | Bölgesel API'lere erişim, veri yerelleştirme gereksinimlerine uyum |
Mikroservisler arasındaki iç iletişim için genellikle, düşük gecikme ve yüksek bant genişliği için optimize edilmiş Envoy Proxy veya NGINX gibi özel proxy çözümleri kullanılır. Bu çözümler, modern protokolleri (HTTP/2, gRPC) destekler ve Service Mesh sistemleriyle entegre olur.
Dış API'lerle çalışırken, seçim belirli hizmetin gereksinimlerine bağlıdır. Eğer API, katı rate limitlere sahipse veya veri merkezi IP'lerinden gelen istekleri engelliyorsa, konut proxy'leri gereklidir. Hızın anonimlikten daha önemli olduğu toplu veri toplama durumlarında, veri merkezi proxy'leri uygundur. Mobil proxy'ler, cihaz türünü kontrol eden veya mobil IP adresleri gerektiren API'lerle çalışırken gereklidir.
Proxy olarak API Gateway: koruma ve yönlendirme
API Gateway, mikroservis sistemine yapılan tüm istemci istekleri için tek giriş noktası olan özel bir proxy sunucusudur. İstemciler, doğrudan birçok farklı hizmete erişmek yerine, tüm isteklerini tek bir API Gateway adresine gönderir ve bu sunucu, istekleri gerekli hizmetlere yönlendirir.
API Gateway'in ana işlevleri:
- İstek yönlendirme — hangi mikroservisin isteği işlemesi gerektiğini URL, başlıklar veya diğer parametreler temelinde belirleme
- Kimlik doğrulama ve yetkilendirme — token'ların (JWT, OAuth) kontrolü, farklı hizmetlere erişim yönetimi
- Rate Limiting — aşırı yüklenme ve DDoS koruması için bir istemciden gelen isteklerin sayısını sınırlama
- Cevap toplama — birkaç hizmetten gelen verileri tek bir yanıt halinde birleştirme
- Protokol dönüştürme — REST'i gRPC'ye, HTTP/1.1'i HTTP/2'ye dönüştürme
- Önbellekleme — sıkça talep edilen verileri saklayarak hizmetlerin yükünü azaltma
- Günlükleme ve izleme — tüm isteklerin merkezi metrik ve günlük toplama
Popüler API Gateway çözümleri: Kong, Tyk, AWS API Gateway, Azure API Management, NGINX Plus, Traefik. Seçim, sistemin ölçeğine, performans gereksinimlerine ve kullanılan bulut platformuna bağlıdır.
// NGINX'in API Gateway olarak yapılandırma örneği
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;
# İstek sıklığı sınırlaması
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/ {
# Proxy öncesi token kontrolü
auth_request /auth/verify;
proxy_pass http://user_service/;
}
location /api/orders/ {
auth_request /auth/verify;
proxy_pass http://order_service/;
}
# Token'ların kontrolü için iç endpoint
location = /auth/verify {
internal;
proxy_pass http://auth_service/verify;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
}
}
API Gateway, sistemin iç mimarisini dış istemcilerden gizler. İstemciler, kaç tane mikroservisin olduğunu ve bunların nasıl etkileştiğini bilmez — sadece tek bir API görürler. Bu, sürümlemeyi kolaylaştırır, iç yapıyı değiştirmeye olanak tanır ve güvenliği artırır, çünkü iç hizmetler doğrudan internete erişilemez.
Service Mesh ile entegrasyon (Istio, Linkerd)
Service Mesh, mikroservisler arasındaki iletişimi yönetmek için proxy sunucularını kullanan bir altyapı katmanıdır; her hizmetin yanında (Sidecar modeli) dağıtılır. API Gateway'den farklı olarak, yalnızca dış trafiği değil, hizmetler arasındaki tüm iç trafiği kontrol eder.
En popüler Service Mesh çözümleri — Istio (Envoy Proxy'yi sidecar olarak kullanır) ve Linkerd (kendi hafif proxy'sini kullanır). Kubernetes'teki her pod'un yanına otomatik olarak bir proxy konteyneri yerleştirir, tüm gelen ve giden trafiği yakalar.
Proxy üzerinden Service Mesh'in sağladığı olanaklar:
- Mutual TLS (mTLS) — hizmetler arasındaki tüm trafiğin otomatik şifrelenmesi ve karşılıklı kimlik doğrulama
- Trafik Yönetimi — yönlendirme yönetimi, kanarya dağıtımları, A/B testleri
- Gözlemlenebilirlik — kodda değişiklik yapmadan otomatik metrik, iz ve günlük toplama
- Dayanıklılık — devre kesici, tekrar deneme mantığı, zaman aşımı yönetimi, hata enjekte etme ile test etme
- Hizmet Keşfi — hizmetlerin otomatik keşfi ve yük dengelemesi
# Yönlendirme için Istio VirtualService yapılandırma örneği
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 # Kanarya dağıtımı: v2 için %10 trafik
---
# Circuit Breaker ile kaskad hatalardan korunma
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, "dağıtık monolit" sorununu çözer — hizmetler arasındaki etkileşim mantığının (tekrar deneme, zaman aşımı, devre kesici) her hizmetin kodunda tekrarlanması. Bunun yerine, tüm bu mantık proxy katmanına taşınır, bu da hizmetlerin kodunu basitleştirir ve sistemin tutarlı davranışını sağlar.
Önemli bir avantaj — trafiğin tam şeffaflığı. Hizmetler arasındaki her istek, metrikleri günlüğe kaydeden proxy üzerinden geçer: yanıt süresi, hata kodları, yük boyutu. Bu veriler otomatik olarak izleme sistemlerine (Prometheus, Grafana) ve izleme sistemlerine (Jaeger, Zipkin) gönderilir ve dağıtık sistemin çalışması hakkında tam bir resim oluşturur.
Dış API'lere yapılan isteklerin proxy üzerinden korunması
Mikroservisler genellikle dış API'lerle etkileşimde bulunur: ödeme sistemleri, coğrafi konum servisleri, sosyal medya API'leri, veri sağlayıcıları. Dış API'lere doğrudan yapılan istekler, birkaç sorunu beraberinde getirir: iç altyapının IP adreslerinin açığa çıkması, rate limitlerin aşılması durumunda engellenme riski, giden trafiğin kontrolünün olmaması.
Giden istekler için proxy kullanmak, bu sorunları çözer ve ek olanaklar sunar:
- Altyapının gizlenmesi — dış API'ler proxy'nin IP adreslerini görür, sunucularınızın IP adreslerini değil
- Rate limitlerin aşılması — istekleri dağıtmak için IP adreslerinin döndürülmesi
- Coğrafi dağılım — gerekli ülkelerdeki proxy üzerinden bölgesel API'lere erişim
- Merkezi yönetim — tüm giden isteklerin tek bir kontrol noktası
- Cevapların önbelleğe alınması — pahalı API'lere yapılan isteklerin sayısını azaltma
- İzleme ve günlüğe kaydetme — dış hizmetlere yapılan tüm çağrıların izlenmesi
// Python: dış API'lere yapılan istekler için proxy ayarı
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()
# Proxy ayarı
self.proxies = {
'http': proxy_url,
'https': proxy_url
}
# Dayanıklılık için tekrar deneme mantığı
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):
"""Ödeme API'sine proxy üzerinden istek"""
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:
# Hata günlüğü
print(f"Ödeme API hatası: {e}")
raise
# Proxy havuzuyla döndürme için kullanım
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
# Başlatma
proxy_pool = ProxyPool([
'http://user:pass@proxy1.example.com:8080',
'http://user:pass@proxy2.example.com:8080',
'http://user:pass@proxy3.example.com:8080'
])
# Her istek için bir sonraki proxy kullanılır
client = ExternalAPIClient(proxy_pool.get_next())
Sıkı kısıtlamalara sahip veya veri merkezi IP'lerinden gelen istekleri engelleyen dış API'lerle çalışırken, konut proxy'leri gereklidir. Bunlar, gerçek ev kullanıcılarının IP adreslerini sağlar, bu da blokaj riskini azaltır ve coğrafi kısıtlamaları aşmayı mümkün kılar.
// Node.js: dış API'ler için otomatik döndürme ile proxy
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 için istek sayacı
}
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: proxy başına dakikada en fazla 100 istek
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) {
// Bir sonraki proxy'ye geçiyoruz
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
}
});
// Sayacı güncelle
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 aşıldı - başka bir proxy'ye geçiyoruz
console.log(`Rate limit ${proxyUrl} üzerinde, proxy değiştiriliyor`);
return this.callAPI(endpoint, data, options);
}
throw error;
}
}
}
// Kullanım
const apiService = new ExternalAPIService([
'http://user:pass@proxy1.example.com:8080',
'http://user:pass@proxy2.example.com:8080'
]);
module.exports = apiService;
Yük dengeleme ve hata toleransı
Proxy sunucuları, yük dengelemesi ve arızalarda otomatik geçiş yoluyla mikroservis sisteminin yüksek erişilebilirliğini sağlamakta önemli bir rol oynar. Bir hizmetin birden fazla örneği çalıştığında (yatay ölçeklendirme için), proxy istekleri bunlar arasında dağıtır ve dengeli bir yük sağlar.
Yük dengeleme için temel algoritmalar:
- Round Robin — listedeki her sunucuya sırayla istek gönderme, homojen sunucular için basit ve etkili
- Least Connections — en az aktif bağlantıya sahip sunucuya istek gönderme, uzun süreli istekler için uygundur
- IP Hash — istemcileri IP'lerine göre belirli bir sunucuya bağlama, sticky session'ları sağlar
- Weighted Round Robin — sunucuların gücüne göre dağıtım (daha güçlü olanlar daha fazla istek alır)
- Random — rastgele sunucu seçimi, durumdan bağımsız hizmetler için uygundur
# HAProxy yapılandırması sağlık kontrolleri ile yük dengelemesi için
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
# Sağlık kontrolü: her 2 saniyede bir /health kontrolü
option httpchk GET /health
http-check expect status 200
# Tekrar deneme mantığı
retries 3
option redispatch
# Ağırlıklı sunucular (server3 iki kat daha güçlü)
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
# Yedek sunucu (sadece ana sunucular kullanılamıyorsa)
server backup1 10.0.2.10:8080 check backup
Sağlık kontrolleri, hata toleransı için kritik bir işlevdir. Proxy, her sunucunun erişilebilirliğini düzenli olarak kontrol eder (genellikle /health veya /ready HTTP endpoint'i üzerinden) ve çalışmayan sunucuları otomatik olarak dengeleme havuzundan çıkarır. Sunucu geri döndüğünde ve sağlık kontrollerine yanıt vermeye başladığında, otomatik olarak havuza geri döner.
Proxy üzerinden hata toleransı stratejileri:
- Aktif Sağlık Kontrolleri — proxy, sunucuların erişilebilirliğini kontrol etmek için aktif olarak sorgular
- Pasif Sağlık Kontrolleri — proxy, gerçek istekleri izler ve hata birikimi durumunda sunucuları çıkarır
- Circuit Breaker — kaskad hataları önlemek için sorunlu hizmetin geçici olarak devre dışı bırakılması
- Graceful Degradation — hatalar durumunda basitleştirilmiş çalışma modu veya önbelleğe alınmış verilere geçiş
- Yedek Sunucuya Geçiş — otomatik olarak yedek sunuculara veya bölgelere geçiş
// Python: dış hizmetlere proxy için Circuit Breaker uygulaması
from datetime import datetime, timedelta
from enum import Enum
class CircuitState(Enum):
CLOSED = "closed" # Normal çalışma
OPEN = "open" # Hizmet erişilemez, istekler engelleniyor
HALF_OPEN = "half_open" # Kurtarma sonrası test modu
class CircuitBreaker:
def __init__(self, failure_threshold=5, timeout=60, success_threshold=2):
self.failure_threshold = failure_threshold # Açılmadan önceki hata sayısı
self.timeout = timeout # Kurtarma denemeleri için saniye
self.success_threshold = success_threshold # Kapatma için başarı sayısı
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("Devre kesici: HALF_OPEN'a geçiş")
else:
raise Exception("Devre kesici AÇIK: hizmet erişilemez")
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("Devre kesici: kurtarma, CLOSED'a geçiş")
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"Devre kesici AÇIK: {self.failures} ardışık hata")
# Kullanım
breaker = CircuitBreaker(failure_threshold=3, timeout=30)
def call_external_service():
# Proxy üzerinden dış API'ye istek kodunuz
pass
try:
result = breaker.call(call_external_service)
except Exception as e:
# Yedekleme mantığı: önbellek, varsayılan değerler vb.
print(f"Hizmet erişilemez: {e}")
Hizmetler arası iletişim güvenliği
Mikroservis mimarisinde proxy sunucuları, birkaç güvenlik katmanı sağlar: trafik şifreleme, hizmet kimlik doğrulama, saldırılara karşı koruma ve ağ segmentlerinin izolasyonu. Güvenlik ayarları doğru yapılmadığında, hizmetler arası iç trafik ele geçirilebilir veya sahte olabilir.
Proxy üzerinden güvenlik için ana noktalar:
- Mutual TLS (mTLS) — hem istemci hem de sunucu, birbirlerinin sertifikalarını kontrol eder. Service Mesh, tüm hizmetler arasında mTLS'yi otomatik olarak ayarlar
- TLS Sonlandırması — proxy, HTTPS trafiğini sınırda şifreler, kontrol eder ve hizmetlere güvenli bir kanaldan iletir
- JWT Doğrulaması — istek hizmete ulaşmadan önce proxy düzeyinde erişim token'larının kontrolü
- IP Beyaz Listeleme — hizmetlere yalnızca izin verilen IP adreslerinden erişim kısıtlaması
- DDoS Koruması — rate limiting, bağlantı limitleri, SYN flood koruması proxy düzeyinde
- WAF (Web Uygulama Güvenlik Duvarı) — kötü niyetli isteklerin filtrelenmesi, SQL injection, XSS koruması
# SSL/TLS ve güvenlik ile NGINX yapılandırması
server {
listen 443 ssl http2;
server_name api.internal.example.com;
# SSL sertifikaları
ssl_certificate /etc/nginx/certs/api.crt;
ssl_certificate_key /etc/nginx/certs/api.key;
# Modern protokoller ve şifreler
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# mTLS için istemci sertifikası
ssl_client_certificate /etc/nginx/certs/ca.crt;
ssl_verify_client on;
# Güvenli başlıklar
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;
# Bağlantı sınırlaması
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn addr 10;
# IP beyaz listeleme
allow 10.0.0.0/8; # İç ağ
allow 172.16.0.0/12; # VPC
deny all;
location / {
# JWT token kontrolü
auth_jwt "Kısıtlı API";
auth_jwt_key_file /etc/nginx/jwt_key.json;
proxy_pass http://backend_service;
# İstemci sertifikası bilgilerini iletme
proxy_set_header X-Client-DN $ssl_client_s_dn;
proxy_set_header X-Client-Verify $ssl_client_verify;
}
}
Service Mesh, mTLS için otomatik olarak sertifikaları oluşturup döndürerek, erişim politikalarını uygulayarak ve hizmetler arasındaki tüm trafiği şifreleyerek güvenlik ayarlarını önemli ölçüde basitleştirir. Örneğin, Istio'da "payment" hizmetinin yalnızca "order" hizmetinden gelen istekleri kabul edebileceği bir politika belirlenebilir ve bu, hizmetlerin kodunda değişiklik yapmadan proxy düzeyinde otomatik olarak uygulanır.
Üretim için önemli: Hizmetler arası iletişim için her zaman mTLS kullanın, hatta aynı özel ağda bulunsalar bile. Bu, man-in-the-middle türü saldırılara karşı koruma sağlar ve hizmetler düzeyinde kimlik doğrulama sağlar, yalnızca ağ düzeyinde değil.
Proxy trafiğinin izlenmesi ve günlüğe kaydedilmesi
Proxy sunucuları, mikroservis sistemindeki tüm trafiği merkezi olarak izlemek için benzersiz bir fırsat sunar. Tüm trafik, proxy üzerinden geçer (API Gateway aracılığıyla dış ve Service Mesh aracılığıyla iç), bu da her hizmeti izlemek için ek bir araç eklemeden sistemin çalışmasını tam olarak görmenizi sağlar.
Proxy düzeyinde izleme için ana metrikler:
- Gecikme — her aşamada isteğin işlenme süresi: proxy, hizmet, dış API'ler
- Yüksek Hız — saniyede istek sayısı, iletilen veri hacmi
- Hata Oranı — hata yüzdesi (4xx, 5xx), hata türleri, sorunlu endpoint'ler
- Bağlantı Metrikleri — aktif bağlantı sayısı, bağlantı havuzu kullanımı
- Circuit Breaker Durumu — her hizmet için devre kesicilerin durumu
- SSL/TLS Metrikleri — sertifikaların durumu, protokol sürümleri, handshake hataları
# NGINX yapılandırması metrikleri Prometheus'a aktarmak için
server {
listen 9113;
location /metrics {
stub_status;
access_log off;
allow 10.0.0.0/8; # Sadece Prometheus sunucusu için
deny all;
}
}
# Yapılandırılmış günlüğe kaydetme için JSON formatında günlüğe kaydetme
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;
Dağıtık İzleme, proxy üzerinden izleme için en güçlü olanaklardan biridir. Her isteğe benzersiz bir izleme kimliği atanır, bu proxy başlıklara ekler ve hizmetler zinciri boyunca iletir. İzleme sistemleri (Jaeger, Zipkin), tüm proxy'lerden bilgi toplar ve sistemdeki isteğin tam yolunu oluşturur, her hizmette ne kadar zaman geçirdiğini gösterir.
// Node.js: proxy middleware'da izleme ekleme
const express = require('express');
const { v4: uuidv4 } = require('uuid');
const axios = require('axios');
const app = express();
// İzleme kimliği eklemek için middleware
app.use((req, res, next) => {
// Başlıktan izleme kimliğini al veya yeni oluştur
const traceId = req.headers['x-trace-id'] || uuidv4();
const spanId = uuidv4();
// Devam ettirmek için başlıklara ekle
req.traceId = traceId;
req.spanId = spanId;
res.setHeader('x-trace-id', traceId);
// İşlemenin başlangıcını günlüğe kaydet
const startTime = Date.now();
res.on('finish', () => {
const duration = Date.now() - startTime;
// Analiz için yapılandırılmış günlüğe kaydet
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();
});
// İzleme başlıklarını ileten proxy endpoint'i
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() // Aşağı akış isteği için yeni span
}
});
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: 'Hizmet mevcut değil' });
}
});
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);
Proxy metriklerine dayalı uyarılar, sorunları hızlı bir şekilde tespit etmeyi sağlar. Örneğin, gecikmenin ani artışı (bir hizmetin kötüleşiyor olabileceği), hata oranının belirli bir eşiğin üzerine çıkması (kod veya bağımlılıklarda sorunlar), trafik desenlerindeki değişiklikler (olası DDoS saldırısı veya virüs yükü) için uyarılar ayarlanabilir.
Python ve Node.js ile uygulama örnekleri
Farklı senaryolar için proxy entegrasyonunun Python ve Node.js'de pratik örneklerini inceleyelim: iç iletişim, dış API'lerle çalışma, yük dengeleme.
Python: Dış API'ler için proxy ile hizmet
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:
# Her dakika sayaçları sıfırla
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
# Kullanılabilir istekleri olan proxy'yi bul
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
# Tüm proxy'ler limitini doldurmuş
raise HTTPException(status_code=429, detail="Tüm proxy'ler rate limitlendi")
# Proxy havuzunu başlat
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"{proxy_url} üzerinden {endpoint} adresinden başarıyla alındı")
return response.json()
except httpx.HTTPStatusError as e:
logger.error(f"{endpoint} adresinden HTTP hatası {e.response.status_code}")
raise HTTPException(status_code=e.response.status_code, detail=str(e))
except httpx.RequestError as e:
logger.error(f"{endpoint} adresine istek hatası: {e}")
raise HTTPException(status_code=503, detail="Dış API mevcut değil")
api_client = ExternalAPIClient(proxy_pool)
@app.get("/data/{resource_id}")
async def get_external_data(resource_id: str):
"""Dış API'den verileri proxy üzerinden alan endpoint"""
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"Beklenmedik hata: {e}")
raise HTTPException(status_code=500, detail="İç sunucu hatası")
@app.get("/health")
async def health_check():
return {"status": "healthy", "service": "external-api-proxy"}
# Başlatma: uvicorn main:app --host 0.0.0.0 --port 8000
Node.js: Yük dengelemesi ile API Gateway
const express = require('express');
const axios = require('axios');
const rateLimit = require('express-rate-limit');
const app = express();
app.use(express.json());
// Mikroservislerin yapılandırması
const services = {
users: [
{ url: 'http://user-service-1:8001', healthy: true, activeConnections: 0 },
{ url: 'http://user-service-2:8001', healthy: true, activeConnections: 0 },
// Diğer kullanıcı hizmetleri...
],
orders: [
{ url: 'http://order-service-1:8002', healthy: true, activeConnections: 0 },
{ url: 'http://order-service-2:8002', healthy: true, activeConnections: 0 },
// Diğer sipariş hizmetleri...
]
};
// Yük dengeleme ve istek yönlendirme
app.use('/api/users', async (req, res) => {
// Yük dengeleme mantığı
const service = services.users.find(s => s.healthy);
if (!service) {
return res.status(503).json({ error: 'Tüm kullanıcı hizmetleri mevcut değil' });
}
try {
const response = await axios({
method: req.method,
url: `${service.url}${req.path}`,
data: req.body,
headers: req.headers
});
res.status(response.status).json(response.data);
} catch (error) {
res.status(500).json({ error: 'Hizmet mevcut değil' });
}
});
// Diğer API endpoint'leri...
app.listen(3000, () => {
console.log('API Gateway 3000 portunda çalışıyor');
});