Katman Nasıl Bozulur: Throttle, Retry ve Döngüler
API Gateway throttle kovasını ön kapınızla paylaşır, Lambda entegrasyonunu asla retry etmez ve kendi üzerinden geçen döngüleri göremez. Neyi yeniden kurmalısınız.
Katman kuruldu, kimliği iki yönde de yerine oturdu ve hesaplara yayıldı. Şimdi dürüst kısım: nasıl bozulduğu. Her iç çağrının arasına bir gateway koymanın bedeli, çağrı başına eklenen fiyattan ibaret değil. Bozulmanın şeklini de değiştiriyor ve direct invoke’un size bedavaya verdiği iki şeyi sessizce geri alıyor: Lambda’nın özyinelemeli döngü kesicisi ve retry’ın kendisi. 103. bölümdeki katman yine de kurulmaya değer. Bu bölümün konusu şu: katmanın geri aldığı işleri artık siz üstleniyorsunuz ve eksilen parçalar, çoğu yazının uyardığı parçalar değil.
Bu bölüm hata modlarının envanteri: doğu-batı trafiğinizin artık public ön kapınızla paylaştığı hesap düzeyindeki throttle kovası, gateway’in çağırana geri verdiği status kodları, artık bu yolu izlemeyen döngü dedektörü, idempotency’nin neden opsiyonel olmaktan çıktığı ve tasarımı bitiren kotalar. POC dağıtılmadı; buradaki hiçbir şey bir ölçüm değil. Aşağıdaki her sayı, kaynağı verilmiş, dokümante edilmiş bir kota.
İç trafiğiniz ön kapınızla aynı kovayı paylaşıyor
İlk değişiklik bir gecikme değişikliği değil. Bir etki alanı değişikliği.
API Gateway kota sayfasındaki tek bir satır, bu katmanın tamamının şeklini belirliyor. Satırın adlandırdığı kaynak şu: “Throttle quota per account, per Region across HTTP APIs, REST APIs, WebSocket APIs, and WebSocket callback APIs”. Varsayılan değeri ise “10,000 requests per second (RPS) with an additional burst capacity provided by the token bucket algorithm, using a maximum bucket capacity of 5,000 requests” (API Gateway kotaları). Rakama değil, satır başlığına bakın. Kova hesap ve bölge başınadır ve işlettiğiniz bütün API tiplerine ortaktır. Burst tarafını da aynı satır kapatıyor: “It is not a quota that a customer can control or request changes to.”
Throttling sayfası aynı şeyi bir kez daha, doğrudan yazıyor: “API Gateway examines the rate and a burst of request submissions against all APIs in your account, per Region” (istek throttling). Aynı sayfa, rakamı bir duvar sanmamanız gerektiğini de söylüyor: “Both throttles and quotas are applied on a best-effort basis and should be thought of as targets rather than guaranteed request ceilings.”
Şimdi aritmetik. Bu katmandan önce dışarıdan gelen bir istek o kovadan tek bir token çekiyordu; içerideki fan-out hiç çekmiyordu, çünkü direct invoke API Gateway’e hiç dokunmaz. Bu katmandan sonra, N iç hop’a dağılan bir dış istek N+1 token çeker. Bir checkout düşünün: orders’ı çağırıyor, orders inventory’yi, inventory de pricing’i çağırıyor. O tek isteğin kovadaki maliyeti artık dört kat ve aynı kovadan public API’leriniz de içiyor.
İşler yolundayken sorun yok. Bir olay anında ise var. İç katmandaki bir retry fırtınası kendi ön kapınızı throttle’lar ve müşteriye giden 429’lar, kimsenin dokunmadığı bir API’den gelir. Bir iç hatanın etki alanı artık servis değil, hesap ve bölgedir.
10.000’i varsaymadan önce bölgenizi kontrol edin. AWS’in listelediği bazı bölgelerde varsayılan 2.500 RPS, burst ise 1.250: Cape Town, Milano, Cakarta, BAE, Haydarabad, Melbourne, İspanya, Zürih, Tel Aviv, Calgary, Malezya, Tayland ve Mexico Central. Bu bölgelerden birindeki geniş bir yapıda pay dört kat daha hızlı tükenir.
Timeout ayarı işi düzeltmez, kötüleştirir. Private REST API’lerde entegrasyon timeout’u yükseltilebilir; kota tablosu bunu yazıyor. Satırın adı “Integration timeout for private APIs”, varsayılan değeri “50 milliseconds - 29 seconds for all integration types” ve artırılabilir olarak işaretli. Herkesin kaçırdığı kısım dipnotta: “You can raise the integration timeout to greater than 29 seconds, but this might require a reduction in your Region-level throttle quota for your account” (API Gateway kota tablosu). Edge-optimized API’lerde bunu hiç yükseltemezsiniz; private olanlarda yükseltebilirsiniz ve tuzak tam olarak burada.
O ayarı bir özellik değil, bir fiyat olarak okuyun. Tek bir yavaş zincir çağrısı için pay satın almak, hesaptaki bütün API’lerin RPS tavanından harcar; public olanlar dahil. Bir doğu-batı çağrısı gerçekten 29 saniyeden fazlasına ihtiyaç duyuyorsa o bir istek/yanıt çağrısı değildir. O bir iş akışıdır ve iş akışlarının nereye ait olduğunu son bölüm anlatıyor.
Retry eden yok, o iş çağıranın
101. bölüm, direct invoke’un retry semantiğinin kafa karıştırıcı olduğundan yakınmıştı: davranışı, çağrılanın yayımladığı bir sözleşme değil, çağıranın seçtiği bir bayrak belirliyordu. Gateway’in bunu düzelttiği anlamına gelmez. Gateway retry’ı tamamen kaldırır.
Lambda geliştirici rehberi net: “API Gateway does not retry any Lambda invocations. If Lambda returns an error, API Gateway returns an error response to the client” (API Gateway hataları). Retry sayfası aynı şeyi öbür taraftan söylüyor: “API Gateway always relays the error response back to the requester”; buna karşılık asenkron invoke’ta Lambda kendi başına “retries function errors twice” (invocation retries).
Yani retry politikası artık tümüyle çağıranın sorunu. Üstelik çağıran bu kararı tek bir status koduna bakarak vermek zorunda. O haritayı öğrenmeye değer, çünkü beklediğiniz şeyi söylemiyor: “API Gateway treats all invocation and function errors as internal errors. If the Lambda API rejects the invocation request, API Gateway returns a 500 error code. If the function runs but returns an error, or returns a response in the wrong format, API Gateway returns a 502. In both cases, the body of the response from API Gateway is {“message”: “Internal server error”}.”
| Status | Anlamı | Çağıran ne yapmalı |
|---|---|---|
| 504 | INTEGRATION_TIMEOUT veya INTEGRATION_FAILURE. Gateway beklemeyi bıraktı. | Backoff ile retry edin; ama çağrılan servis commit etmiş olabilir. Yalnızca idempotency key ile güvenli. |
| 502 | Fonksiyon çalıştı ve hata döndü ya da bozuk bir proxy yanıtı döndü. | Bozuk yanıt tekrar edecektir. En fazla bir kez retry edin, sonra bırakın. |
| 500 | Lambda API invoke’u reddetti. Gövde: {"message": "Internal server error"}. | Opak. Throttle’lanmış bir çağrılan servis olabilir. Öyleymiş gibi geri çekilin. |
| 429 | THROTTLED veya QUOTA_EXCEEDED; “when usage plan-, method-, stage-, or account-level throttling limits exceeded” durumunda döner. | Geri çekilin. Gerçekten görebildiğiniz tek throttle sinyali budur. |
| 403 | INVALID_SIGNATURE veya EXPIRED_TOKEN. | Sizin imzanız, onların hatası değil. Yeniden imzalayın; körlemesine retry etmeyin. |
| 413 | REQUEST_TOO_LARGE. | Asla retry etmeyin. Payload’ı düzeltin. |
Yukarıdaki status eşlemesi gateway response tipleri referansından geliyor.
Şimdi dokümante edilmiş iki olguyu birleştirin. Reserved concurrency’si tükenmiş bir çağrılan servisi Lambda throttle’lar ve Lambda API invoke’a retryAfterSeconds alanı taşıyan bir TooManyRequestsException ile cevap verir; doküman bu alanı “The number of seconds the caller should wait before retrying” diye tanımlıyor (Invoke). API Gateway’in kuralı ise şu: Lambda API’nin bir invoke isteğini reddetmesi 500 olur. Sonuç şu: throttle’lanmış bir çağrılan servis ile bozuk olanı birbirinden ayırt edemezsiniz. Çağıranın akıllıca geri çekilmesini sağlayacak retryAfterSeconds ipucu da ona hiç ulaşmaz. İki olgu da AWS’in; ikisini birleştiren yorum bu yazıya ait, AWS’in kurduğu bir cümle değil. Yine de buna göre tasarlayın, çünkü operasyonel sonucu somut: çağıranın görebildiği tek throttle sinyali, çağrılan servisin değil, gateway’in kendi 429’udur.
İmzaların ömrü var ve bu hata retry döngünüzün içinde saklanıyor. AWS pencereyi açıkça yazıyor: “In most cases, a request must reach AWS within five minutes of the time stamp in the request. Otherwise, AWS denies the request” (AWS isteklerini imzalama). Süresi dolmuş bir imza INVALID_SIGNATURE olarak, yani 403 olarak görünür; 5xx olarak değil. Dolayısıyla yalnızca 5xx’i retry eden bir sarmalayıcı bunları sessizce düşürür. Daha kötüsü, önceden imzalanmış bir isteği tutup uzun bir backoff’tan sonra yeniden gönderen bir sarmalayıcı sonsuza kadar 403 alır ve bütün log satırları IAM’i gösterir. Kural tek cümle: her denemede yeniden imzalayın ve bayatlamış bir imzayı asla retry etmeyin.
Elden çıkardığınız döngü kesici
Asıl gerileme bu ve mimari değerlendirmenize götürmeniz gereken madde de bu.
Lambda’nın bir özyinelemeli döngü dedektörü var. Varsayılan olarak açık, ücretsiz ve X-Ray tracing header’ları ile SDK metadata’sı üzerinden çalışıyor. Tetik noktası dokümante edilmiş: “If your function is invoked approximately 16 times in the same chain of requests, then Lambda automatically stops the next function invocation in that request chain and notifies you” (özyinelemeli döngü tespiti).
Şimdi neyi kapsadığını okuyun. AWS kapsamı açıkça daraltıyor: “Lambda can detect only recursive loops that include certain supported AWS services.” Liste geliyor: “Lambda currently detects recursive loops between your functions, Amazon SQS, Amazon S3, and Amazon SNS. Lambda also detects loops comprised only of Lambda functions, which may invoke each other synchronously or asynchronously.” Listede olmayan bir servis için dışlama da açıkça yazılmış: “When another AWS service such as Amazon DynamoDB forms part of the loop, Lambda can’t currently detect and stop it.”
API Gateway o listede yok ve liste, örnek sıralaması gibi değil, tam sayım gibi okunuyor. A’dan gateway’e, oradan B’ye, tekrar gateway üzerinden A’ya dönen bir çağrıyı düşünün. Bu, içinde desteklenmeyen bir servis bulunan bir döngüdür. Trafik, desteklenen bir servise yapılan SDK yazımı olarak değil, SigV4 imzalı HTTPS olarak akar. Tespit edilmez ve durdurulmaz.
Neyin değiştiğine dikkat edin. Yalnızca Lambda fonksiyonlarından oluşan döngüler, direct invoke’un ürettiği şeydir ve onlar kapsam içindeydi. O yolda bedava bir 16 invoke’luk devre kesiciniz vardı. Araya gateway’i koyduğunuz anda onu elden çıkardınız. Gateway size bir sözleşme sınırı sattı ve karşılığında emniyet ağınızı aldı.
Yerine koyacağınız şey el yapımı ve her servise değil, 103. bölümdeki paylaşılan imzalama istemcisine ait. Bir hop sayacı taşıyın ve sabit bir bütçenin üstünde reddedin.
const MAX_HOPS = 8;
// Çağrılan taraf: her iç route, iş yapmaya başlamadan önce bunu çalıştırır.
// Header aramaları, handler'ın event.headers'ı küçük harfe indirdiğini varsayar.
export function assertHopBudget(headers: Record<string, string | undefined>): number {
const hops = Number(headers['x-hop-count']);
if (!Number.isInteger(hops) || hops < 1) {
throw new Error('missing or invalid x-hop-count');
}
if (hops >= MAX_HOPS) {
// Lambda'nın direct invoke yolunda sağladığı devre kesicinin yerine geçen kontrol.
throw new Error(`hop budget exhausted at ${hops}`);
}
return hops;
}
// Çağıran taraf: paylaşılan SigV4 istemcisi, artı taşınan iki header.
// Zincirin başındaki fonksiyona hop sayacı gelmez; zincir 0'dan başlar.
export async function callService(
url: URL,
body: string,
inbound: Record<string, string | undefined>,
) {
const hops = Number(inbound['x-hop-count'] ?? '0');
const request = new HttpRequest({
protocol: url.protocol,
hostname: url.hostname,
path: url.pathname,
method: 'POST',
headers: {
host: url.hostname,
'content-type': 'application/json',
'x-hop-count': String(hops + 1),
'x-correlation-id': inbound['x-correlation-id'] ?? crypto.randomUUID(),
},
body,
});
// Her denemede yeniden imzalayın. Bir imza yalnızca beş dakika geçerlidir.
const signed = await signer.sign(request);
return fetch(url, { method: signed.method, headers: signed.headers, body: signed.body });
}
Bunun ne olduğu konusunda dürüst olun. Bu bir güvenlik kontrolü değil, iş birliğine dayanan bir kontrol. Yapıdaki her çağıran aynı istemciyi kullandığı için çalışır ve bir takım kendi istemcisini yazdığı gün çalışmayı bırakır. O yüzden yaptırım alan tarafta olmalı: hiç hop sayacı görmeyen bir route, sıfır varsaymak yerine reddetmelidir. assertHopBudget eksik header’ı bu yüzden varsayılana çekmeden reddediyor. Correlation id’yi de aynı yerde taşıyın, çünkü bir döngü kaçtığında ilk isteyeceğiniz şey bütün zinciri tek bir sorguyla log’lardan çekebilmek olacak.
Idempotency artık opsiyonel değil
Buradaki mantık zinciri kısa ve kaçış kapısı yok.
API Gateway hiç retry etmez. Dolayısıyla çağıran retry etmek zorundadır, yoksa çağrı düpedüz başarısız olur. Ama 504 belirsizdir: size gateway’in beklemeyi bıraktığını söyler, çağrılan servisin çalışmayı bıraktığını değil. Çağrılan servis yazmayı commit etmiş ve sadece 29 saniyeyi aşarak cevap vermiş olabilir. Dolayısıyla GET olmayan her doğu-batı route’unun bir idempotency key’e ihtiyacı vardır. Bu katmanın, o adımın opsiyonel olduğu bir sürümü yok.
AWS aynı şeyi, size retry etmenizi söyledikten hemen sonra tek cümlede yazıyor: “If you retry, ensure that your function’s code can handle the same event multiple times without causing duplicate transactions or other unwanted side effects” (invocation retries).
Key çağırandan gelir ve denemeler boyunca sabit kalmak zorundadır. Payload artı zaman damgasından türetilen bir şey key değildir, çünkü her retry’da değişir. Çağıran niyetini oluştururken bir kez üretin, x-idempotency-key olarak gönderin ve o niyetin her retry’ında aynısını kullanın. Desen egzotik değil: AWS’in kendi API’leri EC2, ECS ve DynamoDB TransactWriteItems üzerinde client token’larla tam olarak bunu yapıyor.
Çağrılan tarafta ise store’u kendiniz yazmayın. Powertools for AWS Lambda (TypeScript), ilk özelliği “Prevent Lambda handler from executing more than once on the same event payload during a time window” diye sıralanan bir Idempotency aracı sunuyor; persistence katmanı DynamoDB, Valkey veya Redis (Powertools Idempotency). Decorator, Middy middleware veya makeIdempotent sarmalayıcısı olarak kullanılıyor ve Lambda geliştirici rehberi de doğrudan bu aracın adını veriyor.
import { makeIdempotent, IdempotencyConfig } from '@aws-lambda-powertools/idempotency';
import { DynamoDBPersistenceLayer } from '@aws-lambda-powertools/idempotency/dynamodb';
import type { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
const persistenceStore = new DynamoDBPersistenceLayer({ tableName: 'orders-idempotency' });
// Key payload'dan değil, çağıranın header'ından gelsin. Aynı iş niyeti,
// içindeki bir zaman damgası değişse bile aynı key'i üretmeli.
const config = new IdempotencyConfig({
eventKeyJmesPath: 'headers."x-idempotency-key"',
throwOnNoIdempotencyKey: true,
});
const reserve = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
// Commit. Geçerlilik penceresi içinde key başına en fazla bir kez çalışır.
return { statusCode: 200, body: JSON.stringify({ reserved: true }) };
};
export const handler = makeIdempotent(reserve, { persistenceStore, config });
Ödün gerçek ve adını koymak gerekiyor. Idempotency, değişiklik yapan her çağrının sıcak yoluna yazma işlemleri koyar: işten önce koşullu bir put, işten sonra bir update. Bu, eklenen gecikme artı sahiplenilecek bir tablo demek. Kendine ait bir hata modu da getirir: rezervasyon ile tamamlanma arasında ölen bir istek, geride yarım kalmış bir kayıt bırakır. Bir sonraki deneme de beklemek mi devralmak mı gerektiğine karar vermek zorunda kalır. Powertools bunu bir geçerlilik penceresiyle çözüyor; yani ayarlamanız gereken bir timeout daha. Yine de bedelini ödeyin. Alternatifi şu: çağrılan servis her yavaş cevap verdiğinde sipariş ikiye katlanır. Üstelik bunun ne sıklıkla olduğunu sayamazsınız bile, çünkü 504 yazmanın gerçekleşip gerçekleşmediğini söylemez.
Çarpacağınız duvarlar
Concurrency, throttle sorununu katlıyor. Bölgesel varsayılan, hesap başına 1.000 eşzamanlı çalıştırmadır ve bütün fonksiyonlar bunu paylaşır; her fonksiyon 10 saniyede 1.000 çalıştırma ortamı ekleyebilir (Lambda kotaları). Şimdi senkron bir zincire bakın. Çağıran, çağrılanın bütün süresi boyunca boşta bekleyerek bir çalıştırma ortamını tutar. AWS bu sonucu, serinin başlangıç noktası olan anti-pattern sayfasında yazıyor: “The concurrency of all three functions must be equal. In a busy system, this uses more concurrency than would otherwise be needed” (olay güdümlü mimariler). Yani iki adımlık bir zincir, kullanıcı isteği başına concurrency tüketimini üçe katlar ve bunu tek bir paylaşılan havuzdan yapar. Throttle kovasındaki çarpanın aynısı, farklı bir kotaya uygulanmış hâli.
Çağrılan servise konan reserved concurrency hesap havuzunu korur ve geri basıncı yukarıdaki tablodaki opak 500’e çevirir. Bir hatadan kaçınmıyorsunuz; hangi hatayı tercih ettiğinizi seçiyorsunuz.
IAM duvarı deploy anında gelir; kimsenin geldiğini görememesinin sebebi bu. Bir role’deki bütün inline policy’lerin toplam boyutu 10.240 karakteri aşamaz ve IAM bu sınırı, artış talep edemeyeceğiniz sınırlar arasında sayıyor. Tek tavizi şu: “IAM doesn’t count white space when calculating the size of a policy against these limits” (IAM kotaları). CDK’nın grant yardımcıları ise varsayılan olarak inline role policy yazar.
Şimdi aritmetik; bu AWS’in değil, bu yazının aritmetiği. Tam nitelikli bir route ARN’i adlandıran tek bir execute-api:Invoke statement’ı, sadeleştirildiğinde kabaca 150-200 karakter tutar. Yani bir çağıran role’ü, deploy edilemez hâle gelmeden önce kabaca 50-70 route bazlı yetki taşıyabilir. Hata da birileri fazladan bir route eklediği gün, cdk deploy sırasında LimitExceeded olarak çıkar. İki kaçış yolu var ve ikisinin de bedeli var. Yetkileri customer managed policy’lere taşıyın: her biri 6.144 karakterle sınırlı, role başına varsayılan 10 tanesi eklenebiliyor, kota yükseltilirse 25. Ya da yetkiyi path öneki düzeyinde kabalaştırın; bu da katmanı kurma sebebiniz olan route bazlı hassasiyeti takas eder.
| Duvar | Sınır | Artırılabilir mi |
|---|---|---|
| IAM role başına toplam inline policy boyutu | 10.240 karakter | Hayır |
| Customer managed policy boyutu | her biri 6.144 karakter | Hayır |
| Role’e eklenen managed policy sayısı | varsayılan 10 | Evet, 25’e kadar |
| REST API başına resource sayısı | 300 | Evet |
| API Gateway resource policy uzunluğu | 8.192 karakter | Evet |
| Hesap ve bölge başına private API sayısı | 600 | Hayır |
| VPC endpoint policy boyutu | 20.480 karakter | Hayır |
| Hesap ve bölge başına eşzamanlı çalıştırma | 1.000 | Evet |
Bu duvarlardan ikisi birbirini itiyor. AWS’in 300 resource sınırından kaçış önerisi şu: “Use {proxy+} paths to reduce the number of resources”. İşe yarar ve aynı hamlede route bazlı yetki verme kabiliyetinizi çökertir, çünkü bir {proxy+} route’u tek bir ARN’dir. 8.192 karakterlik resource policy ise öbür taraftan sıkıştırır: çok takımlı bir yapıda izin verilen her principal ve her endpoint o tek dokümana yazılır.
Bir de iyi haber, çünkü endpoint insanların beklediği duvar değil. AWS şunu yazıyor: “each VPC endpoint can support a bandwidth of up to 10 Gbps per Availability Zone, and automatically scales up to 100 Gbps” (PrivateLink kotaları). Paylaşılan interface endpoint, bir iç servis katmanı için bir throughput darboğazı değildir. Aynı sayfada birlikte okunması gereken iki detay var, çünkü ilki tek başına ürkütücü duruyor. Bir VPC endpoint 8.500 byte MTU destekliyor ve path MTU discovery desteklemiyor. Bu, insanı büyük payload’larda sessiz askıda kalma aramaya iten türden bir cümle. Bir sonraki satır o aramayı iptal ediyor: “VPC endpoints enforce Maximum Segment Size (MSS) clamping for all packets.” Sıradan TCP, ki bu tasarımdaki bütün HTTPS trafiği odur, düşürülmüyor, clamp ediliyor. İki satırı birlikte okuyun, ilkini tek başına değil.
Bu katmana hiç ihtiyacınız olmayabilir
Yukarıdaki her şey, bir istek/yanıt çağrısına gateway koymanın bedeli. Bu bedeli ödemeden önce sorulacak dürüst soru şu: çağrı gerçekten istek/yanıt mı?
AWS’in anti-pattern sayfası, yani Lambda fonksiyonlarının birbirini çağırmamasını söyleyen sayfa, kendi kuralına bir istisna açıyor: “this doesn’t apply to durable functions, which are specifically designed to orchestrate multi-step workflows by invoking other functions”. Bu istisna, atlanmayı değil ciddiye alınmayı hak ediyor.
Durable functions, AWS’in çok adımlı zincire verdiği cevap. AWS’in ifadesiyle: “With AWS Lambda durable functions, you can build resilient multi-step applications and AI workflows that can execute for up to one year while maintaining reliable progress despite interruptions” ve mekanizma “uses checkpoints to track progress and automatically recover from failures through replay”. Programlama modeli işi step’lere ve wait’lere ayırıyor: “Steps execute business logic with built-in retries and progress tracking, while waits suspend execution without incurring compute charges” (durable functions).
Bunu, bu yazının size elle kurmanızı söylediği listenin karşısına koyun. Yerleşik retry. İlerleme takibi. Replay ile toparlanma. Doğu-batı çağrınız aslında tek bir takımın sahibi olduğu bir iş akışının adımıysa, durable functions bunların hepsini veriyor ve gateway hiçbirini vermiyor.
Yine de sınırını dürüstçe çizin, çünkü bu bir doğu-batı cevabı değil. Zincirleme çağrı hesap sınırında duruyor ve AWS bunu doğrudan yazıyor: “Cross-account chained invocations are not supported. The invoked function must be in the same AWS account as the calling function” (durable function çağırma). Tek hesap, tek takım, iş akışı şeklinde iş. Alanı bu. Hesaplara yayılmış çok takımlı bir yapı ise tam olarak kapsamadığı şekil ve bu seri o yapı için kuruluyor.
Yani bunu bir yarış değil, bir filtre olarak kullanın ve herhangi bir şey kurmadan önce uygulayın. Yanıtı bekleyen kimse yoksa bir event bus kullanın. Çağıran, kendi sahibi olduğu adımları tek bir hesap içinde orkestre ediyorsa durable functions veya Step Functions kullanın. Geriye kalan, yani takım sınırını aşan gerçek bir istek/yanıt çağrısı, bu katmanın işidir. Bu küme, çoğu takımın sandığından küçüktür ve buradan çıkardığınız her çağrı, throttle kovasından içmeyen bir çağrıdır.
Sık yapılan hatalar
- 500’ü çağrılan servisteki bir bug olarak okumak. Aslında throttle’lanmış bir servis olabilir. Lambda API’nin invoke’u reddetmesi, gövdesi
{"message": "Internal server error"}olan bir 500’e dönüşür veretryAfterSecondsipucu yolda kaybolur. 500’lerde, 429 gibi geri çekilin. - Yalnızca 5xx’te retry etmek ve önceden hazırlanmış bir imzayı tekrar göndermek. Süresi dolmuş imza 403’tür; yalnızca 5xx’e bakan bir politika bunu sessizce düşürür ve sizi IAM’e bakmaya gönderir. Uzun bir backoff’tan sonra tekrar oynatılan imzalı istek sonsuza kadar başarısız olur. Yeniden imzalamayı retry’ın dışında değil, içinde yapın.
- 504’te idempotent olmayan bir POST’u retry etmek. Çağrılan servis commit etmiş, sadece geç cevap vermiş olabilir. Çağıranın gönderdiği bir idempotency key yoksa, tek bir 504 böyle iki siparişe dönüşür.
- Lambda’nın döngülerinizi hâlâ durdurduğunu varsaymak. Lambda; kendi fonksiyonları, SQS, SNS ve S3 üzerinden geçen döngüleri durduruyor. API Gateway üzerinden geçen bir döngü desteklenen listede yok. Taşınan bir hop sayacı olmadan hiçbir kesiciniz yok.
- Yavaş bir çağrıyı sığdırmak için entegrasyon timeout’unu yükseltmek. Bu, public’ler dahil bütün hesabın bölge düzeyindeki throttle kotasını düşürebilir. 29 saniyeden fazlasına ihtiyaç duyan bir çağrı, istek kılığına girmiş bir iş akışıdır.
- Route bazlı yetkileri inline policy ile verip karakterleri hiç saymamak. 10.240 karakterlik inline sınırı yükseltilemez ve fatura çalışma anında değil,
cdk deploysırasında gelir.
Katman kurulmaya değer ve 103. bölüm ayakta. Değişen şey, katman devreye girdikten sonra üstlendiğiniz iş: çağıranda bir retry politikası, değişiklik yapan her route’ta bir idempotency key, Lambda’nın artık sağlamadığı döngü dedektörünün yerine bir hop sayacı ve doğu-batı trafiğinizin hesap throttle kovasından ne kadar içtiğine dair güncel bir sayı. Bunların hiçbiri egzotik değil ve hepsi ilk olaya kadar görünmez; ikinci servis çıkmadan bunları paylaşılan istemciye yazmanın gerekçesi de bu. POC dağıtılmadı; yukarıdaki hata modlarını gözlemlenmiş davranış olarak değil, karşısında tasarım yapılacak dokümante davranış olarak okuyun.
Katmanın nasıl bozulduğunu artık biliyorsunuz. Son soru şu: çalışırken neyi görebilirsiniz ve neyi log’lamamalısınız. 107. bölüm gözlemlenebilirlik yarısı: çağıran servisi ve route’u zaten yazan access log ve kimlik tasarımının bir header’a binmek zorunda bıraktığı, log group’larınızdan uzak tutmanız gereken kullanıcı token’ı.
Kaynaklar
- Amazon API Gateway quotas - “per account, per Region across HTTP APIs, REST APIs, WebSocket APIs, and WebSocket callback APIs” tanımlı 10.000 RPS throttle kotası ve varsayılanı 2.500 RPS olan bölgeler.
- Throttle requests to your REST APIs - “API Gateway examines the rate and a burst of request submissions against all APIs in your account, per Region” ve her throttle’ın best-effort olduğu kaydı.
- API Gateway quotas table - 29 saniyelik entegrasyon timeout’u ve yükseltmenin “might require a reduction in your Region-level throttle quota for your account” dipnotu.
- Error handling with API Gateway and Lambda - “API Gateway does not retry any Lambda invocations” ve throttle’lanmış bir servisi bozuk gibi gösteren 500 ile 502 eşlemesi.
- Gateway response types - Status kodu haritasının tamamı: INTEGRATION_TIMEOUT 504, THROTTLED 429, INVALID_SIGNATURE 403, REQUEST_TOO_LARGE 413.
- Lambda Invoke API referansı -
TooManyRequestsException’ınretryAfterSecondsalanı, “The number of seconds the caller should wait before retrying” diye tanımlanır; API Gateway bunu opak bir 500’e indirger. - Error handling and automatic retries in Lambda - “API Gateway always relays the error response back to the requester”; asenkron invoke’ta ise Lambda “retries function errors twice”. Idempotency talimatı da burada.
- Recursive loop detection - Desteklenen servis listesi (Lambda, SQS, S3, SNS) ve 16 invoke’luk tetik. API Gateway listede yok.
- Signing AWS API requests - Beş dakikalık SigV4 penceresi: “a request must reach AWS within five minutes of the time stamp in the request”.
- AWS Lambda quotas - Hesap ve bölge başına, bütün fonksiyonların paylaştığı 1.000 eşzamanlı çalıştırma ve fonksiyon başına ölçekleme sınırı.
- Lambda olay güdümlü mimariler - Senkron zincirler üzerine anti-pattern sayfası: “The concurrency of all three functions must be equal. In a busy system, this uses more concurrency than would otherwise be needed.”
- IAM and STS quotas - Role başına artırılamayan 10.240 karakterlik toplam inline policy sınırı ve customer managed policy’lerdeki 6.144 karakterlik tavan.
- AWS PrivateLink quotas - “each VPC endpoint can support a bandwidth of up to 10 Gbps per Availability Zone, and automatically scales up to 100 Gbps”; ayrıca 8.500 byte MTU ve path MTU discovery desteğinin olmaması.
- AWS Lambda durable functions - Checkpoint, replay ve step bazlı yerleşik retry: bu yazının elle kurmanızı söylediği her şey, tek hesap içinde yaşayan iş akışları için hazır geliyor.
- Invoking durable functions - Burada asıl önemli olan sınır, Chained invocations başlığı altında: “Cross-account chained invocations are not supported. The invoked function must be in the same AWS account as the calling function.”
- Powertools for AWS Lambda: Idempotency - Aracın ilk sıradaki özelliği: “Prevent Lambda handler from executing more than once on the same event payload during a time window”; DynamoDB, Valkey veya Redis üzerinde saklanır.
Serverless İç Servis Katmanı: Kurmadığınız, Oluşturduğunuz Mesh
Çok takımlı bir serverless yapıda service mesh benzeri doğu-batı iletişimini private API Gateway üzerine kurmak. Kimlik, şifreleme, wire format'lar, maliyet ve endüstrinin gerçekte nereye gittiği.
Bu Serideki Tüm Yazılar
İlgili yazılar
İç servis katmanı kurmadan önce kurup kurmayacağınıza karar verin. Katmanın çağrı başına maliyeti, VPC Lattice'in kazandığı hacim ve direct invoke'un hâlâ kazandığı an.
Private REST API gRPC’yi yapısal olarak taşıyamaz ve gRPC konuşan her AWS yüzeyi Lambda hedeflerini dışlar. gRPC’den neyi tutmalı, neyi bırakmalı.
Private REST API, onu açan resource policy, route bazlı AWS_IAM yetkileri, iki CDK stack'i ve Node 22 Lambda'dan çağrıyı imzalamak.
SigV4 hangi servisin çağırdığını kanıtlar, kimin adına çağırdığını değil. Doğrulanmış özneyi nasıl taşırsınız ve taşıma katmanı gerçekte neyi şifreler.
Aynı hesapta resource policy ile çağıranın identity policy'si bir OR'dur. Hesaplar arası çağrıda AND'e döner ve sessizlik reddeder. Veri sınırında bunun sonuçları.