API Tekrar Deneme Mantığı ve Üstel Geri Çekilme: Gerçekten İşe Yarayan Desenler

Tam titreşimli üstel geri çekilme, Retry-After başlıkları, idempotentlik anahtarları ve devre kesiciler konusunda ustalaşın, ardından API yeniden deneme mantığınızı Apidog sahte sunucularıyla test edin.

INEZA Felin-Michel

INEZA Felin-Michel

31 August 2026

API Tekrar Deneme Mantığı ve Üstel Geri Çekilme: Gerçekten İşe Yarayan Desenler

Kurumsal İçin Apidog

Şirket İçi (On-Premises) Dağıtım

SSO ve RBAC

SOC 2 Uyumlu

Apidog Enterprise'ı Keşfedin

Ödeme API çağrınız sabah 2'de başarısız oldu. Bu bir ağ arızası mıydı, bir hız sınırı mıydı, yoksa çökmüş bir sunucu mu? Cevap, yeniden denemenin işlemi kurtarıp kurtarmayacağını veya müşteriyi iki kez ücretlendirip ücretlendirmeyeceğini belirler.

Yeniden denemeler, dağıtılmış sistemlerde en yaygın esneklik modelidir ve en sık yanlış yapılır. Bir HTTP çağrısının etrafına sarılmış bir döngü, savunma programlama gibi hissettirir. Yanlış yapıldığında, binlerce istemci aynı anda zor durumdaki bir sunucuya yük bindiği için 30 saniyelik bir kesintiyi 30 dakikaya dönüştürür. Doğru yapıldığında, yeniden denemeler geçici arızaları o kadar temiz bir şekilde emer ki kullanıcılarınız bunları asla fark etmez.

Bu kılavuz, üretim sistemlerinin güvendiği yeniden deneme mantığını kapsar: hangi durum kodlarını yeniden denemeli, tam jitter'lı üstel geri çekilme formülü, Retry-After başlıkları, idempotens anahtarları, yeniden deneme bütçeleri ve devre kesiciler. Ayrıca, Apidog sahte sunucularıyla 429'ları ve 503'leri simüle ederek istemcinizin doğru davrandığını nasıl kanıtlayacağınızı da göreceksiniz, çünkü başarısız bir sunucuya karşı hiç test etmediğiniz bir yeniden deneme deseni bir tahmindir, bir tasarım değil. Fintek API yeniden deneme mantığı geliştiren ekipler bunu pahalı yoldan öğrenir; sizin öğrenmenize gerek yok.

Neden basit yeniden denemeler kesintileri daha kötü hale getirir

Saniyede 1.000 istek işleyen bir hizmet düşünün. Beş saniye boyunca aksıyor. Her istemci hemen, her biri üç kez yeniden deniyor. 1.000 rps'lik talebiniz, zaten diz çökmüş bir sunucuya yönelik 4.000 rps'ye dönüşüyor. Tamamen çöküyor. Şimdi her istemci tekrar yeniden deniyor.

Bu geri bildirim döngüsünün bir adı var: yeniden deneme fırtınası. Sunucu geri geldiğinde oluşan senkronize yığılma, gürleyen sürüdür. Google'ın SRE kitabı, basamaklı hataları ele alma bölümünde bu deseni vurgular: geri çekilme olmaksızın yapılan yeniden denemeler, sistemin en az kaldırabileceği anda yükü artırır ve orijinal hata düzeltildikten çok sonra bile bir hizmeti kapalı tutabilir.

Çoğu yeniden deneme fırtınasına iki tasarım hatası neden olur:

Çözüm "asla yeniden deneme" değildir. Çözüm, seçici olarak, artan rastgele gecikmelerle ve yeniden denemelerinizin eklediği ekstra yükün kesin bir tavanı ile yeniden denemektir.

Bu arızaları yeniden dene, asla şunları deneme

Herhangi bir geri çekilme matematiğinden önce, istemcinizin bir karar tablosuna ihtiyacı vardır. Sunucunun geçersiz olarak zaten reddettiği bir isteği yeniden denemek kapasiteyi boşa harcar ve günlükleri kirletir. Geçici bir hatayı yeniden denemek asıl amaçtır.

Şunları yeniden dene:

Sinyal Anlamı
429 Çok Fazla İstek Bir hız sınırına ulaştınız. Geri çekilin ve daha yavaş gelin.
502 Hatalı Ağ Geçidi Yukarı akış bir atlama çöplük döndürdü. Genellikle geçici.
503 Hizmet Kullanılamıyor Sunucu aşırı yüklü veya yeniden başlatılıyor.
504 Ağ Geçidi Zaman Aşımı Yukarı akış bir bağımlılık çok yavaştı.
Bağlantı sıfırlamaları, DNS hataları, soket zaman aşımları İstek hiçbir zaman ulaşmamış olabilir.

Bir 504 ağ geçidi zaman aşımı özel dikkat gerektirir: ağ geçidi beklemeyi bırakmış olsa bile kaynak isteğinizi işlenmiş olabilir. Bu ayrım, idempotensi'ye geldiğimizde önem kazanır.

Şunları asla yeniden deneme:

Sinyal Anlamı
400 Hatalı İstek Yükünüz hatalı biçimlendirilmiş. Bir dahaki sefere de hatalı biçimlendirilmiş olacak.
401 Yetkilendirilmemiş Kimlik bilgileriniz yanlış veya süresi dolmuş. Tokeni yenileyin, döngü yapmayın.
403 Yasak İzniniz yok. Yeniden denemek onu sağlamaz.
422 İşlenemeyen Varlık Doğrulama başarısız oldu. Veriyi düzeltin, zamanlamayı değil.

Kural: hata sunucunun durumu veya ağ ile ilgili olduğunda yeniden dene. Hata isteğinizle ilgili olduğunda hızla başarısız ol. 429 ikisinin arasında yer alır; yeniden denenebilir, ancak aynı zamanda genel istek hızınızın iyileştirilmesi gerektiğine dair bir sinyaldir; bu, herhangi bir yeniden deneme döngüsünün yukarısında çözülmesi gereken bir oran sınırlama sorunudur.

Üstel geri çekilme formülü ve jitter'ın neden önemli olduğu

Üstel geri çekilme, her yeniden denemenin bir öncekinden daha uzun beklemesi anlamına gelir, varsayılan olarak iki katına çıkar:

delay = base * 2^retry_count

500 ms'lik bir tabanla, bu 0.5s, 1s, 2s, 4s, 8s demektir. Gecikmelerin dakikalara dönüşmemesi için bir üst sınır (örneğin 30 saniye) ekleyin:

delay = min(cap, base * 2^retry_count)

Bu, "yüklenme" sorununu çözer ancak senkronizasyon sorununu çözmez. Eğer 5.000 istemci aynı anda başarısız olursa, basit üstel geri çekilme ile hepsi t=0.5s, sonra t=1s, sonra t=2s'de geri gelir. Hala dalgalar halinde. Hala bir sürü, sadece daha kibar bir sürü.

Jitter, gecikmeyi rastgele hale getirerek senkronizasyonu bozar. AWS Mimari Blogu, üstel geri çekilme ve jitter analizinde, çekişmeli bir kaynağa karşı yarışan istemcileri simüle ederek sayıları inceledi. Jitter'sız geri çekilme hala kümelenmiş çağrı zirveleri üretti. Sıfır ile üstel tavan arasında rastgele bir gecikme seçen tam jitter, hem en az toplam çağrıyı hem de en kısa tamamlama sürelerine yakın sonuçları üretti:

delay = random_between(0, min(cap, base * 2^retry_count))

Bu sonuç insanları şaşırtır. Sıfıra kadar tamamen rastgeleleştirme, düzenli bir ikiye katlama programına kıyasla özensiz gelebilir. Ancak istemcileri pencere boyunca düzgün bir şekilde dağıtmak, sunucu yükünü düz tutan şeydir. AWS analizi ayrıca "eşit jitter" (yarısı sabit, yarısı rastgele) ve "ilişkisiz jitter"ı da test etti; tam jitter ve ilişkisiz jitter öne çıktı ve tam jitter doğru bir şekilde yazılması en basit olanıdır. Aksini söyleyen ölçümleriniz olmadığı sürece bunu varsayılan yeniden deneme deseniniz olarak kullanın.

Sunucu size söylediğinde Retry-After'a uyun

Geri çekilme, istemcinizin ne kadar beklemesi gerektiğini tahmin etmesidir. Bazen sunucu bu tahmini ortadan kaldırır. 429 ve 503 yanıtları için tanımlanan Retry-After başlığı, ya saniye cinsinden bir sayı ya da bir HTTP tarihi taşır:

HTTP/1.1 429 Too Many Requests
Retry-After: 12

Bu başlık mevcut olduğunda, hesaplanan geri çekilmenizi geçersiz kılar. Sunucu, hız sınırlama penceresinin ne zaman sıfırlandığını veya bakımının ne zaman bittiğini bilir; sizin üstel programınız bilmez. Retry-After'ı göz ardı eden istemciler, sağlayıcıların kısıtlamadan doğrudan yasaklamaya geçmelerinin nedenlerinden biridir. Ayrıştırın, saygı gösterin ve kötü niyetli veya hatalı bir Retry-After: 86400'ün işçinizi bir gün boyunca takılı bırakmaması için yine de üst sınırınızı ve maksimum yeniden deneme sayınızı uygulayın.

Idempotens: POST'u yeniden denemek için ön koşul

İşte o önceki 504'teki tuzak. GET, PUT ve DELETE sözleşme gereği idempotenttir: onları iki kez göndermek sistemi aynı durumda bırakır. POST değildir. Eğer POST /v1/payments sunucu tarafından işlendikten sonra zaman aşımına uğrarsa, yeniden denemeniz ikinci bir ödeme oluşturur. Tebrikler, mükemmel çalışma süresine sahip bir çift ücretlendirme makinesi inşa ettiniz.

Çözüm bir idempotens anahtarıdır: her mantıksal işlemde başlık olarak gönderilen benzersiz bir istemci tarafından oluşturulmuş kimlik (genellikle bir UUID). Sunucu anahtarı ilk yanıtla birlikte saklar ve herhangi bir kopya için depolanan bu yanıtı tekrar oynatır. Stripe'ın idempotent istekleri tam olarak bu şekilde çalışır ve çoğu ödeme ve provizyon API'si bunu takip etmiştir.

Anahtarları çalıştıran iki kural:

Çağırdığınız API idempotens anahtarlarını desteklemiyorsa, idempotent olmayan yazmaları otomatik olarak yeniden denemeyin. Hatayı yüzeye çıkarın ve bir insanın veya bir uzlaştırma işinin karar vermesine izin verin.

Yeniden deneme bütçeleri ve devre kesiciler: acil çıkış

Geri çekilme, yeniden denemelerin ne zaman olacağını şekillendirir. Kaç tane olacağını sınırlamaz. Uzun bir kesinti sırasında, iyi jitter'lanmış istemciler bile yeniden deneme yükünü biriktirir ve katmanlı yeniden denemeler çoğalır: eğer API ağ geçidiniz 3 kez ve hizmet istemciniz 3 kez yeniden denerse, tek bir kullanıcı tıklaması 9 isteğe dönüşebilir.

Hasarı sınırlayan iki mekanizma:

Yeniden deneme bütçeleri. "İstek başına 3 yeniden deneme" yerine, kayan bir pencere üzerinde ölçülen "yeniden denemeler en fazla %10 ekstra yük ekleyebilir" kuralını uygulayın. Bütçe harcandığında, hatalar hemen geri döner. Bu, aynı anda kaç isteğin başarısız olduğuna bakılmaksızın yeniden deneme amplifikasyonunu sınırlı tutar. Linkerd ve Envoy, bunu birinci sınıf bir yapılandırma olarak sunar.

Devre kesiciler. Her bir aşağı akış için hata oranını izleyin. Bir eşiği aştığında, kesici açılır: çağrılar ağı etkilemeden anında başarısız olur. Bir soğuma süresinden sonra, kesici tekrar kapanmadan önce bağımlılığın düzelip düzelmediğini test etmek için birkaç yoklama isteği gönderilir. Geri çekilme nazikçe yığılmayı yavaşlatırken, kesici onu iptal eder. Her ciddi yeniden deneme tasarımı ikisini eşleştirir, çünkü tek başına geri çekilme hala her isteği sonunda gönderir.

Python'da üretime hazır bir örnek

İşte tüm desen tek bir yerde: yeniden denenebilir durum filtreleme, tam jitter, Retry-After desteği, bir idempotens anahtarı ve katı bir yeniden deneme üst sınırı.

import random
import time
import uuid
import requests

RETRYABLE = {429, 502, 503, 504}
BASE = 0.5     # seconds
CAP = 30.0     # ceiling on any single delay
MAX_RETRIES = 5

def create_payment(payload):
    idempotency_key = str(uuid.uuid4())  # one key per logical payment
    headers = {"Idempotency-Key": idempotency_key}

    for retry_count in range(MAX_RETRIES + 1):
        try:
            resp = requests.post(
                "https://api.acmepay.com/v1/payments",
                json=payload, headers=headers, timeout=10,
            )
            if resp.status_code < 400:
                return resp.json()
            if resp.status_code not in RETRYABLE:
                resp.raise_for_status()  # 400/401/403/422: fail fast
            retry_after = resp.headers.get("Retry-After")
        except (requests.ConnectionError, requests.Timeout):
            retry_after = None  # network fault: fall through to backoff

        if retry_count == MAX_RETRIES:
            raise RuntimeError("payment failed after all retries")

        if retry_after and retry_after.isdigit():
            delay = min(CAP, float(retry_after))
        else:
            delay = random.uniform(0, min(CAP, BASE * 2 ** retry_count))
        time.sleep(delay)

Dikkat çekmeye değer: anahtar döngünün dışında, bir kez üretilir. Retry-After, hesaplanan geri çekilmeyi yener ancak yine de üst sınırı dikkate alır. Yeniden denenemeyen durumlar hemen yükseltilir. JavaScript tarafındaysanız, axios-retry kütüphanesi size retryCondition ve retryDelay kancalarıyla aynı şekli verir; karar tablosu aynı kalır.

Üretim ortamı sizin için yapmadan önce yeniden deneme davranışını nasıl test edersiniz

Çoğu ekip, hata dalını hiçbir zaman çalıştırmamış yeniden deneme kodu gönderir. Başarılı yol test edildi; 503 yolu gerçek bir kesinti sırasında ilk kez çalışır. İki Apidog özelliğiyle daha iyisini yapabilirsiniz.

Bu, "yeniden denemeler ekledik" ile "istemcimizin hız sınırlı, yarı kapalı bir bağımlılıkta hayatta kaldığını doğruladık" arasındaki farktır. Apidog'u ücretsiz indirin ve yaklaşık on dakika içinde istemcinize karşı çalışan başarısız bir sahte sunucuya sahip olabilirsiniz.

SSS

429'u yeniden denemeli miyim?

Evet, ve sunucunun size genellikle nasıl yapılacağını söylediği tek durum budur. Retry-After başlığını okuyun ve en az o kadar bekleyin; başlık eksikse jitter ile üstel geri çekilmeye geri dönün. Ayrıca tekrarlanan 429'ları, normal bir işlem olarak değil, istemci tarafı kısıtlaması veya önbelleğe alma ile istek hızınızı düzeltmek için bir sinyal olarak kabul edin.

Tam jitter nedir?

Tam jitter, her yeniden deneme gecikmesini sıfır ile üstel tavan arasında rastgele, tekdüze bir şekilde seçer: random(0, min(cap, base * 2^n)). Birçok istemciden gelen senkronize yeniden deneme dalgalarını önler. AWS'nin simülasyonlarında, hem yapılan toplam çağrılarda hem de tamamlama süresinde basit geri çekilme ve eşit jitter'ı geride bıraktı, bu yüzden AWS SDK'larında varsayılan olarak kullanılır.

POST isteklerini yeniden denemek güvenli midir?

Yalnızca istek pratik olarak idempotent olduğunda, ki POST için bu, sunucunun tekrarlayanları ayıkladığı bir idempotens anahtarı göndermek anlamına gelir. Böyle bir anahtar olmadan, bir zaman aşımından sonra yapılan yeniden deneme bir ödemeyi, siparişi veya kaydı çoğaltabilir, çünkü sunucu başarısız olduğunu düşündüğünüz isteği işlemiş olabilir. Yazma API'lerini çağıran yapay zeka ajanları sürekli olarak bununla karşılaşır; ajan hata kurtarma modelleri burada ele alınanlarla aynıdır: anahtarlı yazmalar, sınırlı yeniden denemeler ve bir devre kesici.

Kaç kez yeniden denemeliyim?

Üç ila beş deneme neredeyse her geçici hatayı halleder; bunun ötesinde, başarı oranları sabitlenirken yük ve gecikme artmaya devam eder. Tam bir kesintinin yükünüzü artırmaması için istek başına üst sınırı global bir yeniden deneme bütçesiyle (örneğin, yeniden denemeler %10 ekstra trafik ekleyebilir) eşleştirin. Eğer bir bağımlılık son yeniden denemenizden sonra da kapalı kalıyorsa, bu yeniden deneme alanı değil, devre kesici alanıdır.

API Tasarım-Öncelikli Yaklaşımı Apidog'da Uygulayın

API'leri oluşturmanın ve kullanmanın daha kolay yolunu keşfedin