AWS RDS limit połączeń przekroczony: too many connections
Naprawa błędu too many connections w RDS PostgreSQL: identyfikacja idle connections, zakończenie wyciekających sesji i wdrożenie connection pooling z RDS Proxy lub PgBouncer.
Ten runbook opisuje wyczerpanie limitu połączeń RDS PostgreSQL. Aby zapewnić bieżące zarządzanie bazami danych i monitoring, zobacz CloudOps Maintenance. W kwestii architektury connection pooling umów konsultację.
Objaw
Logi aplikacji pokazują błędy połączeń. Użytkownicy doświadczają timeoutów lub błędów 500:
# Application error logs show:
# FATAL: too many connections for role "app_user"
# FATAL: remaining connection slots are reserved for non-replication superuser connections
# Check current connection count from a superuser session
# (if you can still connect via psql as superuser)
psql -h my-rds-instance.abcdefg.eu-west-1.rds.amazonaws.com \
-U master_user -d mydb -c "SELECT count(*) FROM pg_stat_activity;"
# Check max_connections setting
psql -h my-rds-instance.abcdefg.eu-west-1.rds.amazonaws.com \
-U master_user -d mydb -c "SHOW max_connections;"
# Check via CloudWatch if you can't connect at all
aws cloudwatch get-metric-statistics \
--namespace AWS/RDS \
--metric-name DatabaseConnections \
--dimensions Name=DBInstanceIdentifier,Value=my-rds-instance \
--start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%S) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
--period 60 --statistics Maximum \
--query 'Datapoints | sort_by(@, &Timestamp) | [-5:].[Timestamp,Maximum]'
Liczba połączeń osiąga lub zbliża się do max_connections. Nowe połączenia nie mogą zostać nawiązane.
Przyczyna
RDS PostgreSQL ma stały limit max_connections zależny od klasy instancji (np. db.t3.micro = 87, db.t3.medium = 150, db.r5.large = 1600). Połączenia wyczerpują się, gdy:
- Wycieki połączeń: Kod aplikacji otwiera połączenia, ale nie zamyka ich na ścieżkach błędów lub przy timeoutach. Z czasem wyciekające połączenia się kumulują.
- Brak connection pooling: Każda instancja aplikacji otwiera własną pulę połączeń. Przy autoscalingu nowe instancje przynoszą nowe pule, szybko wyczerpując limit.
- Idle transactions: Długo trwające zapytania lub porzucone transakcje trzymają połączenia otwarte w nieskończoność.
- Nagły skok ruchu: Gwałtowny wzrost żądań tworzy więcej połączeń niż baza danych jest w stanie obsłużyć, a po wysyceniu powstaje efekt kaskady.
Domyślna formuła max_connections dla RDS to LEAST({DBInstanceClassMemory/9531392}, 5000), co jest często niższe niż zespoły zakładają dla mniejszych klas instancji.
Rozwiązanie
A) Natychmiastowa ulga: zakończ idle connections:
# Connect as superuser (RDS master user)
psql -h my-rds-instance.abcdefg.eu-west-1.rds.amazonaws.com \
-U master_user -d mydb
# Check connection breakdown by state and application
SELECT state, application_name, count(*)
FROM pg_stat_activity
GROUP BY state, application_name
ORDER BY count DESC;
# Identify idle connections older than 5 minutes
SELECT pid, usename, application_name, state,
now() - state_change AS idle_duration
FROM pg_stat_activity
WHERE state = 'idle'
AND now() - state_change > interval '5 minutes'
ORDER BY idle_duration DESC;
# Terminate idle connections (careful: this kills sessions)
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle'
AND now() - state_change > interval '5 minutes'
AND usename != 'rdsadmin';
# Verify connections freed
SELECT count(*) FROM pg_stat_activity;
B) Wdróż connection pooling z RDS Proxy:
# Create RDS Proxy (via AWS CLI)
aws rds create-db-proxy \
--db-proxy-name my-service-proxy \
--engine-family POSTGRESQL \
--auth Description="proxy auth",AuthScheme=SECRETS,SecretArn=arn:aws:secretsmanager:eu-west-1:123456789012:secret:rds-creds,IAMAuth=DISABLED \
--role-arn arn:aws:iam::123456789012:role/rds-proxy-role \
--vpc-subnet-ids subnet-abc123 subnet-def456 \
--vpc-security-group-ids sg-12345678
# Register target (your RDS instance)
aws rds register-db-proxy-targets \
--db-proxy-name my-service-proxy \
--db-instance-identifiers my-rds-instance
# Update application connection string to point to the proxy endpoint
# Proxy endpoint: my-service-proxy.proxy-abcdefg.eu-west-1.rds.amazonaws.com
C) Dostosuj parametr max_connections (doraźne rozwiązanie):
# Check current parameter group
aws rds describe-db-instances \
--db-instance-identifier my-rds-instance \
--query 'DBInstances[0].DBParameterGroups[0].DBParameterGroupName'
# Modify max_connections (requires custom parameter group, not default)
aws rds modify-db-parameter-group \
--db-parameter-group-name my-custom-pg \
--parameters "ParameterName=max_connections,ParameterValue=300,ApplyMethod=pending-reboot"
# Reboot to apply (causes brief downtime)
aws rds reboot-db-instance --db-instance-identifier my-rds-instance
Prewencja: Zawsze używaj connection pooling w produkcji (RDS Proxy dla zarządzanego AWS, PgBouncer dla samodzielnego). Ustaw idle_in_transaction_session_timeout, aby automatycznie ubijać porzucone transakcje. Skonfiguruj alarmy CloudWatch na DatabaseConnections przy 80% wartości max_connections, aby wykrywać problemy zanim staną się awarią.
Walidacja
# 1. Confirm connections are below limit
psql -h my-rds-instance.abcdefg.eu-west-1.rds.amazonaws.com \
-U master_user -d mydb -c \
"SELECT count(*) as current, current_setting('max_connections')::int as max FROM pg_stat_activity;"
# Expected: current is well below max
# 2. Verify application can connect
curl -s https://my-app.example.com/health | jq '.database'
# Expected: "connected" or equivalent health check pass
# 3. Check no connection leak pattern in CloudWatch
aws cloudwatch get-metric-statistics \
--namespace AWS/RDS \
--metric-name DatabaseConnections \
--dimensions Name=DBInstanceIdentifier,Value=my-rds-instance \
--start-time $(date -u -d '30 minutes ago' +%Y-%m-%dT%H:%M:%S) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
--period 300 --statistics Average
# Expected: stable connection count, not continuously rising
# 4. If using RDS Proxy, verify it's handling connections
aws rds describe-db-proxy-targets \
--db-proxy-name my-service-proxy \
--query 'Targets[0].TargetHealth'
# Expected: State = "AVAILABLE"
Jeśli aplikacja obsługuje żądania bez błędów połączeń i metryka CloudWatch jest stabilna, problem jest rozwiązany. Monitoruj przez 24 godziny, aby potwierdzić, że nie pojawia się powolny wzorzec wycieku.
Połączenia z bazą się wyczerpują?
Umów bezpłatną 30-minutową rozmowę. Przejrzymy konfigurację RDS i wdrożymy connection pooling, aby zapobiec przyszłym awariom.