İçeriğe geç

API Gateway ve Service Discovery — İstek Doğru Kapıyı Nasıl Bulur

Orta 9 dk Çok sık karşılaşılır

Önce şunu oku: Mikroservis Katmanları — İstek Nereden Geçiyor

30 saniyede özet

Gateway, bütün isteklerin geçtiği tek kapıdır: yönlendirir, kimliği kontrol eder, aşırı isteği durdurur. Arkadaki servislerin adresleri ise sürekli değişir; discovery onları çalışırken bulur ama hep biraz geriden gelir.

Fiyat servisinin üç kopyası vardı, dördüncüsü eklendi. Kısa süre sonra tuhaf şeyler olmaya başladı.

  1. Bayt: Fiyat servisinin üç kopyası vardı, yük artınca dördüncüsünü ekledik.

  2. Sen: Yük dağıldı mı?

  3. Bayt: Tuhaf şeyler oldu! Kopyalardan biri çökünce de hatalar başladı.

  4. Bayt: Kapıcı kargoyu dağıtırken dairelerin listesine nereden bakıyor?

Herkes aynı kapıdan girer

Bir API gatewayDışarıdan gelen her isteğin girdiği tek kapı. Auth, rate limit, TLS sonlandırma ve yönlendirme gibi her servisi ilgilendiren işleri tek yerde toplar.Gateway yönlendirir, birleştirmez. Sayfa için beş servis gerekiyorsa istemci yine beş kez gidip gelir — gecikmeyi çözen şey gateway değil, sunucu tarafında birleştirme yapan BFF'tir.Sözlükte gör →, dışarıdan gelen her isteğin girdiği yerdir. Her servisi ilgilendiren işleri tek yerde toplar: yönlendirme, kimlik doğrulama, TLS, rate limitingBir istemcinin belirli sürede yapabileceği istek sayısını sınırlamak. Aşan istek 429 Too Many Requests alır; birden çok gateway varsa sayaç paylaşılmalıdır.Sözlükte gör →.

Gateway’e iş kuralı ya da ekran başına veri birleştirme girmez. Girerse, bütün ekiplerin aynı anda değiştirmek zorunda kaldığı bir darboğaz olur.

Kafam karıştı, daha basit anlat

Gateway binanın tek giriş kapısıdır. Kimlik kontrolü ve yönlendirme her oda için ayrı ayrı değil, kapıda bir kez yapılır.

Hızlı kontrolBaşlangıç

Mikroservislerde service discovery neden gerekir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

API Gateway'in sorumluluklarına en uygun liste hangisi?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Adresler sürekli değişir

Fiyat servisinin pod adresleri application.yml'a elle yazıldı. Bir pod çöküp yenisi başka bir IP'yle gelirse ne olur? Cevabı göster

Ölü adrese istek gitmeye devam eder, yeni pod hiç iş almaz. Liste, dosyayı biri elle güncelleyene kadar değişmez.

Eski bir defter mi, herkesin kendini yazdırdığı canlı bir liste mi?
Adım adım oku
  1. Gateway, kapıcı gibi gelen her isteği uygun servis kopyasına yönlendirir.
  2. Adresler bir dosyaya elle yazılmışsa ölen kopyaya istek gitmeye devam eder, yeni kopya hiç iş almaz.
  3. Servis keşfinde her kopya açılınca kendini bir kayıt defterine yazdırır ve düzenli olarak yaşadığını bildirir.
  4. Ölen kopya listeden düşer, yeni kopya eklenir; trafik her zaman canlı listeye göre dağıtılır.

service discoveryBir servisin o an çalışan instance'larının adreslerini çalışma anında bulmak. Kayıt servisi (Eureka, Consul) ya da platform (Kubernetes Service) bu listeyi güncel tutar.Sözlükte gör →, çalışan instance’ları çalışma anında bulur. İki yaygın model var:

ModelListeyi kim tutarÖrnek
Kayıt servisiInstance’lar kendini kaydeder, çağıran listeyi alırEureka, Consul
PlatformAltyapı hazır pod’lara yönlendirirKubernetes Service

Kayıt servisiyle çalışırken seçimi çağıran yapar; buna client-side load balancingÇağıranın, bildiği instance listesinden hangisine gideceğini kendisinin seçmesi (ör. Spring Cloud LoadBalancer). Arada ayrı bir yük dengeleyici yoktur.Sözlükte gör → denir. Kubernetes’te çoğu zaman ayrı bir kayıt servisine gerek yoktur.

Kafam karıştı, daha basit anlat

Servisler sık sık taşınır, adresleri değişir. Service discovery, güncel adresleri tutan bir rehberdir: sen adı söylersin, o sana şu an nerede olduğunu verir.

Hızlı kontrolOrta

Her aracı, listeyi kimin tuttuğuna göre ayır.

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Sınıflandırılmamış

Kayıt servisi + istemci tarafı dengeleme

Instance'lar bir kayıt servisine yazılır, çağıran listeyi alıp kendisi seçer

    Platform / sunucu tarafı

    Çağıran tek bir adres bilir, altyapı yönlendirir

      Pricing servisi ölçeklendi ama yeni pod'lar hiç trafik almıyor; biri çökünce de hatalar başlıyor. Sorun hangi satırlarda?

      Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

      Hatalı satıra dokun, sonra kontrol et.

      application.yml
      ShellUTF-8LF

      Kendin gör

      Service discovery — ölen instance, yeni gelen instance

      Tohum 710195
      PeriyotCanlıÇağıranın bildiğiİstekler

      Oynat ya da adımla.

      Hız
      Adım 0

      Şu an ne oldu?

      Sabit adres listesi, retry kapalı

      Üç instance: A, B, C. 3. periyotta B çökecek, 6. periyotta yeni bir D gelecek.

      Görevler0/3

      • Ölen bir instance'a sonsuza kadar istek gönderaçık

        İpucu

        Adres listesi hiç değişmezse?

      • Hiç hata görme — ama yeni instance'a da tek istek gitmesinaçık

        İpucu

        Retry hataları gizleyebilir; listenin güncel olup olmadığını söylemez.

      • Sıfır kullanıcı hatası ve yeni instance trafik alıyoraçık

        İpucu

        Listeyi güncel tutan bir discovery ve aradaki boşluk için retry.

      Olay günlüğü (0)

      Henüz olay yok. Oynat veya adımla.

      1. Varsayılanla oynat. Sabit liste: B çöktükten sonra her üç istekten biri boşluğa gidiyor, D hiç iş almıyor.
      2. Retry’ı aç. Hatalar kayboldu — ama D hâlâ boşta.
      3. Kayıt servisi seç, retry’ı kapat. Birkaç periyot hata, sonra toparlanma.
      4. Platform seç ve retry’ı aç. Hata yok, yeni instance trafik alıyor.
      Hızlı kontrolOrta

      Adres listesi yapılandırmada sabit yazılı ve retry açık. Bir instance çöktü, yerine yenisi geldi. Kullanıcılar hata görmüyor. Sorun var mı?

      Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

      Satır satır: bir gateway rotası

      Yönlendir, sınırla, gerekirse bir kez daha dene

      GatewayRoutes.java
      1@Bean
      2RouteLocator routes(RouteLocatorBuilder builder) {
      3 return builder.routes()
      şu an çalışan satır .route("pricing", r -> r.path("/api/prices/**")
      5 .filters(f -> f
      6 .stripPrefix(1)
      7 .requestRateLimiter(c -> c.setRateLimiter(redisRateLimiter()))
      8 .retry(c -> c.setRetries(1).setMethods(HttpMethod.GET)))
      9 .uri("lb://pricing"))
      10 .build();
      11}

      Debug

      Adım 1/4

      gateway /api/prices/... ile başlayan her istek bu rotaya düşer.

      Java 21UTF-8LF4:1

      Sol/sağ ok tuşlarıyla da gezebilirsin.

      Adresi değil, servisin adını yaz. Hangi instance’ın yaşadığını bilmek discovery’nin işi.

      Şimdi aynı fikri bir bankanın kapısında görelim. Bakiye sorgusu ve para transferi aynı kapıdan girer, ama her biri kendi kuralıyla geçer.

      Derinleş · Bankanın kapısı: bakiye, transfer ve canlı adres listesi 4 dosya · ~79 satır · ilk okumada atlayabilirsin
      Proje dosyaları

      gateway/src/main/resources/ application.yml Rotalar adres değil servis adı kullanır; yalnızca bakiye okuma gibi GET istekleri bir kez yeniden denenir.

      gateway/src/main/resources/application.yml
      spring:
      application:
      name: edge-gateway
      data:
      redis:
      host: redis # shared by every gateway pod
      cloud:
      gateway:
      server:
      webflux: # Spring Cloud Gateway 4.3+; older versions: spring.cloud.gateway.routes
      routes:
      - id: accounts
      uri: lb://accounts-service # a service name; discovery knows the live instances
      predicates:
      - Path=/api/accounts/**
      filters:
      - StripPrefix=1
      - name: Retry
      args:
      retries: 1
      methods: GET # reading a balance twice is harmless
      - id: transfers
      uri: lb://transfer-service
      predicates:
      - Path=/api/transfers/**
      - Method=POST
      filters:
      - StripPrefix=1
      - name: RequestRateLimiter
      args:
      key-resolver: "#{@customerKeyResolver}"
      redis-rate-limiter.replenishRate: 5
      redis-rate-limiter.burstCapacity: 10
      # No Retry here: a timed-out transfer may already have moved the money.

      gateway/src/main/java/com/bank/gateway/ RateLimitConfig.java Hız sınırı müşteri başına Redis'te tutulur, böylece bütün gateway pod'ları aynı sayacı görür.

      gateway/src/main/java/com/bank/gateway/RateLimitConfig.java
      @Configuration
      class RateLimitConfig {
      // One bucket per customer, kept in Redis, so three gateway pods do not mean three limits.
      @Bean
      KeyResolver customerKeyResolver() {
      return exchange -> exchange.getPrincipal()
      .map(Principal::getName) // JWT subject: the customer number
      .defaultIfEmpty("anonymous");
      }
      }

      accounts-service/src/main/resources/ application.yml Hesap servisi açılınca kendini kayıt defterine bu adla yazdırır ve düzenli olarak yaşadığını bildirir.

      accounts-service/src/main/resources/application.yml
      spring:
      application:
      name: accounts-service # the name behind lb://accounts-service
      # Eureka registration. On Kubernetes a Service object does this job instead.
      eureka:
      client:
      service-url:
      defaultZone: http://discovery:8761/eureka/
      instance:
      prefer-ip-address: true
      # A dead instance stays on the list until its lease expires: the short gap retry covers.
      lease-renewal-interval-in-seconds: 10
      lease-expiration-duration-in-seconds: 30

      gateway/src/main/resources/ application-static.yml Şöyle de yazılabilirdi: sabit IP ve her metotta tekrar. Bak, yeni pod iş almıyor ve yavaş bir havale iki kez gidebiliyor.

      gateway/src/main/resources/application-static.yml
      # Another way to write it: fixed addresses and a retry on every method.
      spring:
      cloud:
      gateway:
      server:
      webflux:
      routes:
      - id: accounts
      uri: http://10.0.3.17:8080 # one pod's IP; its replacement comes up elsewhere
      predicates:
      - Path=/api/accounts/**
      - id: transfers
      uri: http://10.0.4.21:8080
      predicates:
      - Path=/api/transfers/**
      filters:
      - name: Retry
      args:
      retries: 3
      methods: GET,POST # a slow transfer can be sent again: a double debit
      Kafam karıştı, daha basit anlat

      Rotaya adres yazma, servisin adını yaz. Adresin güncel olup olmadığını rehber zaten takip ediyor.

      Hızlı kontrolOrta

      Gateway'de 'başka instance'ta bir kez dene' retry'ı açıldı. Hangi isteklerde bu tehlikelidir?

      Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

      Rate limit aşıldığında istemciye ne dönmelisin?

      Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

      Tuzaklar

      Gateway’de iş kuralı. Sipariş toplamını hesaplayan gateway, her ekibin kuyruğuna girer.

      Pod başına rate limit. Üç gateway pod’u kendi sayacını tutarsa gerçek sınır üç katıdır.

      POST’u yeniden denemek. Timeout isteğin işlenmediği anlamına gelmez.

      Retry ile gizlenen liste. Hata görünmüyor diye liste güncel değil; kapasite sessizce düşer.

      Kendini sına

      Şimşek turu1/5

      API gateway, dışarıdan gelen isteklerin girdiği ortak kapıdır.

      Soru 1/2İleri

      Gateway üç pod'la çalışıyor ve her pod kendi bellek içi sayacıyla dakikada 100 istek sınırı uyguluyor. Gerçek sınır nedir?

      Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

      Aklında kalacak üç şey

      1. 1 Gateway yönlendirme, kimlik kontrolü ve istek sınırı gibi ortak işleri toplar. İş kuralı ve ekran birleştirmesi içermez.
      2. 2 Adresleri elle yazmak sistemin hiç değişmeyeceğini varsaymaktır. Discovery güncel listeyi bulur, ama bir sunucunun öldüğünü her zaman biraz geç öğrenir.
      3. 3 Tekrar deneme, discovery'nin geriden geldiği kısa boşluğu kapatır; yalnızca tekrarlanması zararsız isteklerde güvenlidir.
      Sonraki kapı Siparişi veritabanına yazdın, mesajı gönderemeden uygulama çöktü. Sipariş var ama kimsenin haberi yok. Ne yapmalı? Outbox ve Idempotent Consumer — Olay Kaybolmasın, İki Kez de İşlenmesin · 9 dk

      5 kart sonraki derste seni bekliyor

      0/5 kart bu dersten toplandı

      Bu dersin üstüne kurulanlar

      Bunlar bu dersi temel alıyor; hazır olduğunda devam edebilirsin.