Zurück zur Startseite

429-Fehler mit RPS-Limit: Poisson und Sharding

Der Artikel analysiert die Ursachen konstanter 429-Fehler im RPS-Limiter, wenn der durchschnittliche Traffic unter dem Limit liegt. Unter Verwendung der Poisson-Verteilung werden die Wahrscheinlichkeit von Bursts und die bedingte Erwartung berechnet. Die Berücksichtigung von Sharding über 6 Pods und Client-Retries erklärt die beobachteten 7 RPS-Ablehnungen.

Warum 7 RPS 429 bei 150 Limit: Poisson + Sharding
Advertisement 728x90

Modellierung von 429-Fehlern in einem verteilten RPS-Limiter mit Poisson-Fluss

Bei einem durchschnittlichen Traffic von 129 erfolgreichen Anfragen pro Sekunde und 7,429-Fehlern bei einem Limit von 150 RPS stellt sich die Frage: Warum löst der Limiter konsistent aus? Ein 40-minütiges Diagramm zeigt ein konstantes Fehlerniveau in 15-Sekunden-Intervallen. Die Poisson-Verteilung des Anfragevolumens erklärt das Phänomen: Mit λ = 136,28 beträgt die Wahrscheinlichkeit, 150 Anfragen in 1 Sekunde zu überschreiten, 11,27 %.

Code zur Berechnung der Wahrscheinlichkeit:

def get_prob_at_least(border, lmbd):
    sum = 1
    mult = 1
    for i in range(1, border):
        mult = mult * lmbd / i
        sum += mult
    return 1 - sum * math.exp(-lmbd)

get_prob_at_least(151, 129.01 + 7.27)
# 0.1127

Dieser Wert >1 in einem 15-Sekunden-Intervall entspricht dem beobachteten Diagramm.

Google AdInline article slot

Bedingte Erwartung von Fehlern

Eine einfache Berechnung der erwarteten Anzahl von Anfragen bei Überschreitung des Limits ergibt 156,4, und Fehler – nur 0,6 RPS. Die Abweichung von 7,27 RPS bedarf einer Klärung.

Code für bedingte Erwartung:

def get_expectation_via_conditional_at_least(border, lmbd):
    sum_prob = 0
    exp_sum = 0
    mult = 1
    for i in range(1, 10000):
        mult = mult * lmbd / i
        if (i >= border):
            exp_sum += i * mult
            sum_prob += mult
    return exp_sum / sum_prob

def get_expected_errors_num(events, border):
    return (get_expectation_via_conditional_at_least(border, events) - border) * get_prob_at_least(border, events)

Modellanpassungen: Wiederholungen und Sharding

Die Berücksichtigung von 1 Wiederholung pro Fehler (ursprünglicher Traffic 132,64 RPS) erhöht die Fehler auf 0,72 RPS – immer noch unzureichend.

Google AdInline article slot

Schlüsselfaktor: ein 6-Pod-Service (2 Pods pro 3 DCs). Mit Sharding teilt jeder Limiter 150/6 = 25 RPS, Grenze = 26.

Berechnung für einen Limiter:

limiters_num = 6
retry_num = 2
rps_one_limiter=(129.01 + 7.27 / 2)/limiters_num
border_one_limiter=int(150/limiters_num) + 1

one_limiter_erros = get_expected_errors_num(rps_one_limiter, border_one_limiter)
limited_num = one_limiter_erros * limiters_num * retry_num
# limited_num ≈ 6.85

Das Modell erklärt 6,85 RPS Fehler gegenüber 7,27 beobachteten. Der Limiter arbeitet ohne Berechtigungssynchronisation, mit periodischem Nachrichtenaustausch und Zählerrücksetzung.

Google AdInline article slot

Implementierungsmerkmale eines verteilten Limiters

Mögliche Optionen:

  • Leaky Bucket: konstantes Token-Leck.
  • Reset zu Beginn einer Sekunde: fester Zeitraum, anfällig für Spitzen.
  • Dynamische Aufteilung: Heartbeat-Austausch für Anteilsberechnung.

In einem Sharding-Szenario ohne Synchronisation entscheidet jeder Pod unabhängig über das Limit, was die Gesamtfehler linear mit der Anzahl der Shards erhöht.

Wichtige Erkenntnisse

  • Die Poisson-Verteilung modelliert Consumer-Traffic ohne Bots genau (ein Grenzfall unendlicher Benutzer).
  • Sharding von RPS-Limitern ohne Synchronisation erhöht Fehler proportional zu Pods.
  • Client-Wiederholungen verschärfen das Problem und erfordern Anpassungen in Modellen.
  • Bedingte Erwartung (E[X | X ≥ Grenze]) ist entscheidend für die Vorhersage von Fehlern.
  • Eine 11 %-ige Wahrscheinlichkeit einer Spitze erklärt stabile 429s in aggregierten Diagrammen.

— Editorial Team

Advertisement 728x90

Weiterlesen