Architecture

AWS ThrottlingException: API-Rate-Limits verstehen und beheben

2026-03-29 · 8 Min. Lesezeit

Ihre Deployment-Pipeline ist gerade zum Stillstand gekommen. Das CI/CD-System protokolliert Fehler, Ihr Auto-Scaling funktioniert nicht, und Ihre Monitoring-Dashboards sind leer. Die Logs zeigen:

An error occurred (Throttling) when calling the DescribeInstances operation
(reached max retries: 4): Rate exceeded

Oder aus einer Lambda-Funktion:

TooManyRequestsException: Rate exceeded

Oder aus CloudFormation:

API rate limit exceeded for account 123456789012.

Die ThrottlingException bedeutet, dass Sie das API-Rate-Limit eines AWS-Dienstes überschritten haben. Anders als DynamoDB-Durchsatzlimits handelt es sich hier um Limits der AWS Control Plane API selbst — also die Aufrufe, die Sie zur Verwaltung von AWS-Ressourcen machen. Jeder AWS-Dienst hat Rate Limits, und sie sind oft niedriger als erwartet.

Hier ist der systematische Ansatz zur Diagnose, Behebung und Prävention von API-Throttling.

Schritt 1: Identifizieren, welche API gedrosselt wird

Die Fehlermeldung nennt meist die Operation, aber nicht immer das spezifische Limit. Beginnen Sie mit einer CloudTrail-Prüfung auf gedrosselte Events:

aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=DescribeInstances \
  --start-time "2026-03-29T10:00:00Z" \
  --end-time "2026-03-29T11:00:00Z" \
  --query 'Events[?contains(CloudTrailEvent, `ThrottlingException`)].{
    Time: EventTime,
    Event: EventName,
    Source: EventSource
  }' \
  --output table

Für eine breitere Übersicht aller gedrosselten Aufrufe über Dienste hinweg:

# Mit CloudTrail Lake, falls verfügbar
aws cloudtrail start-query \
  --query-statement "SELECT eventTime, eventSource, eventName, errorCode,
    userIdentity.arn, sourceIPAddress
    FROM cloudtrail_events
    WHERE errorCode IN ('Throttling', 'ThrottlingException',
      'TooManyRequestsException', 'RequestLimitExceeded')
    AND eventTime > '2026-03-29 10:00:00'
    ORDER BY eventTime DESC"

Schritt 2: Aktuelle Service Quotas prüfen

AWS Service Quotas ermöglicht es, Rate Limits einzusehen und Erhöhungen anzufordern:

# Alle Quotas für EC2 auflisten
aws service-quotas list-service-quotas \
  --service-code ec2 \
  --query 'Quotas[?contains(QuotaName, `Rate`)].{
    Name: QuotaName,
    Value: Value,
    Adjustable: Adjustable
  }' \
  --output table
# Ein bestimmtes Quota prüfen
aws service-quotas get-service-quota \
  --service-code ec2 \
  --quota-code L-0E3CBDE5 \
  --query 'Quota.{Name: QuotaName, Value: Value, Adjustable: Adjustable}'

Einige häufige Standard-API-Rate-Limits, die Teams überraschen:

DienstOperationStandardlimit
EC2DescribeInstances100 Aufrufe/Sek.
EC2RunInstances5 Aufrufe/Sek.
LambdaInvoke500-3000/Sek. (je nach Region)
S3PUT/COPY/POST/DELETE3.500/Sek. pro Prefix
S3GET/HEAD5.500/Sek. pro Prefix
CloudFormationCreateStack1 Aufruf/Sek.
IAMMeiste Operationen15 Aufrufe/Sek.
STSAssumeRole500 Aufrufe/Sek.
CloudWatchPutMetricData500 Aufrufe/Sek.
SSMGetParameter40 Aufrufe/Sek.

Ursache 1: Polling-Schleifen ohne Backoff

Die häufigste Ursache für API-Throttling ist Code, der eine AWS-API in einer engen Schleife pollt. Klassische Beispiele:

  • Ein Skript, das jede Sekunde DescribeInstances aufruft, um zu prüfen, ob eine Instanz läuft
  • Ein Monitoring-System, das ListMetricData für Hunderte von Metriken in schneller Folge aufruft
  • Ein Deployment-Tool, das DescribeStackEvents in einer Schleife aufruft und auf CloudFormation wartet

So macht man es falsch:

# FALSCH: Enge Polling-Schleife
import boto3
import time

ec2 = boto3.client('ec2')

while True:
    response = ec2.describe_instances(InstanceIds=['i-1234567890abcdef0'])
    state = response['Reservations'][0]['Instances'][0]['State']['Name']
    if state == 'running':
        break
    time.sleep(1)  # 1 Sekunde ist zu aggressiv für die meisten APIs

Und so macht man es richtig:

# RICHTIG: Waiters verwenden (eingebauter exponentieller Backoff)
import boto3

ec2 = boto3.client('ec2')
waiter = ec2.get_waiter('instance_running')
waiter.wait(
    InstanceIds=['i-1234567890abcdef0'],
    WaiterConfig={
        'Delay': 15,       # 15 Sekunden zwischen Polls warten
        'MaxAttempts': 40   # Nach 10 Minuten aufgeben
    }
)

AWS SDKs bieten Waiters für die meisten gängigen Polling-Szenarien. Verwenden Sie diese immer anstelle eigener Polling-Schleifen.

Ursache 2: Gleichzeitige Infrastruktur-Automatisierung

Mehrere Automatisierungstools, die gleichzeitig gegen denselben Account laufen, können gemeinsam die Rate Limits überschreiten, auch wenn jedes einzelne Tool innerhalb der Grenzen bleibt. Das passiert besonders häufig, wenn:

  • CI/CD-Pipelines parallel laufen
  • Auto-Scaling mehrere CloudFormation-Updates auslöst
  • Mehrere Microservices ein Monitoring-Konto teilen und gleichzeitig Metriken pushen
  • Terraform-Plans gleichzeitig mit CloudFormation-Deployments laufen

Prüfen Sie, welche Principals die meisten API-Aufrufe machen:

# Die Top-API-Aufrufer der letzten Stunde über CloudTrail finden
aws cloudtrail lookup-events \
  --start-time "2026-03-29T09:00:00Z" \
  --end-time "2026-03-29T10:00:00Z" \
  --max-results 1000 \
  --query 'Events[].{Source: Username, Event: EventName}' \
  --output json | jq 'group_by(.Source) | map({user: .[0].Source, count: length}) | sort_by(.count) | reverse | .[0:10]'

Ursache 3: SDK-Standard-Retry-Verhalten verstärkt Throttling

Wenn ein API-Aufruf gedrosselt wird, versucht das SDK es erneut. Wenn viele Clients gleichzeitig retrien, können die Retries selbst mehr Throttling verursachen — ein klassisches Thundering-Herd-Problem.

Die Standard-Retry-Konfiguration der meisten AWS SDKs verwendet exponentiellen Backoff, aber ohne Jitter retrien mehrere Clients im Gleichschritt und zur gleichen Zeit. Konfigurieren Sie das SDK korrekt:

import boto3
from botocore.config import Config

# Adaptiven Retry-Modus mit Jitter verwenden
config = Config(
    retries={
        'max_attempts': 10,
        'mode': 'adaptive'
    },
    max_pool_connections=25
)

client = boto3.client('ec2', config=config)

Für die AWS CLI setzen Sie die Retry-Konfiguration in Ihrer Config-Datei:

# ~/.aws/config
[profile my-profile]
retry_mode = adaptive
max_attempts = 10

Die drei verfügbaren Retry-Modi:

  • legacy (Standard): Exponentieller Backoff, begrenzter Jitter
  • standard: Exponentieller Backoff mit vollem Jitter, respektiert Retry-After-Header
  • adaptive: Wie Standard, passt aber zusätzlich die Request-Rate basierend auf Throttling-Feedback an

Verwenden Sie in der Produktion immer den adaptive-Modus.

Ursache 4: Geteilte Rate Limits über Dienste hinweg

Einige Rate Limits werden über alle Operationen eines Dienstes oder sogar über Accounts in einer Organisation geteilt. Zum Beispiel:

  • EC2-API-Rate-Limits gelten für alle EC2-API-Aufrufe kombiniert aus einem Account in einer Region
  • Organizations-API-Aufrufe von jedem Mitgliedskonto zählen gegen die Limits des Management-Accounts
  • Cross-Account-API-Aufrufe über IAM-Rollen zählen gegen beide Accounts

Das bedeutet, dass die Automatisierung eines Teams die Produktions-Workloads eines anderen Teams drosseln kann, wenn sie denselben Account teilen.

Ursache 5: Fehlendes Request-Batching

Viele AWS-APIs unterstützen Batch-Operationen, die in einem Aufruf erledigen, was sonst Hunderte erfordern würde. Sie nicht zu nutzen, verschwendet Ihr Rate-Limit-Budget:

# FALSCH: 100 einzelne Aufrufe (verschwendet Rate Limit)
for id in $(cat instance-ids.txt); do
  aws ec2 describe-instances --instance-ids "$id"
done

# RICHTIG: 1 Batch-Aufruf (nutzt Rate Limit effizient)
aws ec2 describe-instances \
  --instance-ids $(cat instance-ids.txt | tr '\n' ' ')
# FALSCH: Einzelne SSM-Parameter-Lookups
aws ssm get-parameter --name /app/db-host
aws ssm get-parameter --name /app/db-port
aws ssm get-parameter --name /app/db-name

# RICHTIG: Batch-Lookup
aws ssm get-parameters \
  --names /app/db-host /app/db-port /app/db-name \
  --query 'Parameters[*].[Name,Value]' \
  --output table

Limit-Erhöhung anfordern

Wenn Ihre Nutzung legitim ist und Sie einfach höhere Limits benötigen, fordern Sie eine Erhöhung über Service Quotas an:

# Quota-Erhöhung anfordern
aws service-quotas request-service-quota-increase \
  --service-code ec2 \
  --quota-code L-0E3CBDE5 \
  --desired-value 200
# Status der Anfrage prüfen
aws service-quotas list-requested-service-quota-changes-by-service \
  --service-code ec2 \
  --query 'RequestedQuotas[*].{
    QuotaName: QuotaName,
    DesiredValue: DesiredValue,
    Status: Status,
    Created: Created
  }' \
  --output table

Nicht alle Limits sind anpassbar. Einige sind harte Limits, die nicht erhöht werden können. Prüfen Sie das Feld Adjustable in der Quota-Beschreibung.

Client-seitigen Rate Limiter implementieren

Für kritische Anwendungen implementieren Sie einen Client-seitigen Rate Limiter, der proaktiv unter den API-Limits bleibt, anstatt auf Throttling zu reagieren:

import time
import threading

class TokenBucketRateLimiter:
    def __init__(self, rate_per_second, burst_size=None):
        self.rate = rate_per_second
        self.burst_size = burst_size or rate_per_second
        self.tokens = self.burst_size
        self.last_refill = time.monotonic()
        self.lock = threading.Lock()

    def acquire(self):
        with self.lock:
            now = time.monotonic()
            elapsed = now - self.last_refill
            self.tokens = min(
                self.burst_size,
                self.tokens + elapsed * self.rate
            )
            self.last_refill = now

            if self.tokens >= 1:
                self.tokens -= 1
                return True

            wait_time = (1 - self.tokens) / self.rate
            time.sleep(wait_time)
            self.tokens = 0
            self.last_refill = time.monotonic()
            return True

# Nutzung: EC2-API-Aufrufe auf 80/Sek. begrenzen (Puffer unter dem 100/Sek.-Limit)
ec2_limiter = TokenBucketRateLimiter(rate_per_second=80)

def safe_describe_instances(**kwargs):
    ec2_limiter.acquire()
    return ec2_client.describe_instances(**kwargs)

Best Practices zur Prävention

  1. Verwenden Sie Caching für AWS-API-Antworten. Wenn Sie alle 10 Sekunden DescribeInstances aufrufen, cachen Sie das Ergebnis und aktualisieren Sie nur bei Bedarf. Tools wie AWS Config bieten nahezu Echtzeit-Ressourceninventar ohne Polling.

  2. Implementieren Sie Circuit Breaker. Wenn eine API beginnt zu drosseln, ziehen Sie sich für einen Zeitraum vollständig zurück, anstatt sofort erneut zu versuchen.

  3. Separate Accounts für separate Workloads. API-Rate-Limits gelten pro Account. Die Verwendung separater Accounts für Produktion, Staging und CI/CD verhindert, dass einer den anderen drosselt.

  4. Verwenden Sie CloudWatch Events/EventBridge statt Polling. Anstatt Zustandsänderungen zu pollen, abonnieren Sie Events:

# EventBridge-Regel für EC2-Zustandsänderungen erstellen
aws events put-rule \
  --name "ec2-state-change" \
  --event-pattern '{
    "source": ["aws.ec2"],
    "detail-type": ["EC2 Instance State-change Notification"],
    "detail": {
      "state": ["running", "stopped", "terminated"]
    }
  }'
  1. Überwachen Sie die API-Nutzung mit CloudTrail Insights. Aktivieren Sie Insights zur automatischen Erkennung ungewöhnlicher API-Aufrufvolumen:
aws cloudtrail put-insight-selectors \
  --trail-name my-trail \
  --insight-selectors '[{"InsightType": "ApiCallRateInsight"}, {"InsightType": "ApiErrorRateInsight"}]'
  1. Richten Sie CloudWatch-Alarme für Throttling-Metriken über kritische Dienste hinweg ein, damit Sie erfahren, wann Throttling beginnt — nicht erst, nachdem es einen Ausfall verursacht hat.

Wenn Throttling auf ein Architekturproblem hinweist

Wenn Sie regelmäßig auf API-Rate-Limits stoßen, bedeutet das meist, dass Ihre Architektur zu eng an die AWS Control Plane gekoppelt ist. Produktions-Workloads sollten selten Control-Plane-API-Aufrufe machen — sie sollten Data-Plane-APIs nutzen (wie S3 GetObject, DynamoDB PutItem), die wesentlich höhere Limits haben.

Wenn Ihre Anwendungsarchitektur auf hochfrequente Control-Plane-Aufrufe angewiesen ist, ist es Zeit, das Design zu überdenken. Event-getriebene Muster, Caching-Schichten und ordentliches Ressourcenmanagement eliminieren die meisten Throttling-Probleme auf architektonischer Ebene.

Wir helfen Teams, ihre AWS-Architekturen so umzugestalten, dass Rate Limiting vermieden wird und resiliente Systeme entstehen, die mit AWS-API-Beschränkungen elegant umgehen. Wenn API-Throttling Ihre Deployments oder Produktions-Workloads stört, kontaktieren Sie uns für eine kostenlose Beratung — wir analysieren Ihre API-Nutzungsmuster und empfehlen konkrete Änderungen, um das Throttling zu eliminieren.

Brauchen Sie Hilfe mit Ihrer AWS-Infrastruktur?

Buchen Sie ein kostenloses 30-Minuten-Gespräch.