IL-0386 incident.io · 2023-09-26 (게시일)kubernetesgcpdatabasenetworking
Google Cloud 로 옮긴 뒤 GKE 노드에서 Postgres 연결 타임아웃과 memcached i/o timeout 이 간헐적으로 튀었다
incident.io 는 인프라를 Google Cloud 로 모두 옮겼고, 옮긴 뒤 Postgres 연결 타임아웃이 평소보다 많이 나서 인시던트를 선언했다. 초당 새 연결이 수백 개씩 오르내리는 것을 보고 연결이 만료될 때의 경쟁 조건을 의심했다. 그래서 연결 최대 수명을 15m 에서 30m 로 늘리고 연결 풀을 고정 크기로 바꿨다. 새 연결은 초당 약 200개에서 약 1개로 줄었다. memcached 에서도 연결 타임아웃이 났고, MaxIdleConns 를 2 에서 20 으로 올리자 바로 나아졌지만 며칠 뒤 read i/o 타임아웃이 훨씬 많아졌다. 변수를 줄이려고 Google 이 운영하는 memcached 를 쿠버네티스 클러스터 안의 자체 memcached 로 옮겼지만 거의 달라지지 않았다.
같은 때 실수로 들어간 데이터베이스 join 때문에 외부 제3자 서비스로 중복 네트워크 호출을 수천 번 보내던 문제가 따로 있었다. 이 문제를 고친 코드가 운영에 배포되자 데이터베이스 연결 문제와 캐시 문제가 거의 사라졌다. 남은 캐시 오류를 쫓아 영향받은 요청의 트레이스와 노드 로그를 보니, 요청 하나에서 캐시 set 수백 번과 Google Cloud Storage URL 생성 호출이 한꺼번에 일어났다. 그 노드에서는 새 연결 수와 드롭된 패킷이 함께 늘었고, 다른 요청인 헬스 체크까지 캐시에 닿지 못했다. 문제는 프로세스 하나가 아니라 노드 전체에 걸쳐 있었다.
클러스터 설정에서 관련 있어 보이는 것은 Dataplane V2 를 켠 것 하나였다. GKE 문서는 노드에서 TCP 연결을 짧게 열고 닫는 일이 많으면 GKE Dataplane V2 에이전트 파드인 anetd 가 인스턴스마다 vCPU 2~3개까지 쓸 수 있다고 적고, HTTP 호출의 keep-alive 와 연결 풀링을 권한다. anetd 로그에는 눈에 띄는 것이 없었지만 CPU 가 꽤 뛰었다. incident.io 는 지금까지의 관찰과 조치가 이 설명과 맞는다고 봤다. 연결 풀을 고쳐 새 연결을 줄이자 데이터베이스와 캐시 타임아웃이 대부분 사라졌다. 상황을 키운 것은 잘못된 쿼리가 goroutine 수천 개를 띄워 외부 연결을 연 일이었다. 외부 요청을 병렬로 많이 보낼 때는 문제가 드물게나마 계속 났다. Dataplane V2 를 끄는 방안도 검토했지만 택하지 않았다. 끄는 것은 스스로 일으킨 문제를 덮는 일이었다. 끄려면 새 클러스터를 만들어 워크로드를 옮겨야 했다. Dataplane V2 는 앞으로 Autopilot 클러스터에서 끌 수 없는 기본값이 될 가능성이 컸고, incident.io 는 엄격한 네트워크 정책 같은 장점도 쓰고 싶었다.
- 심각도
- –
- 영향 범위
- A small share of requests hit Postgres connection timeouts and memcached i/o timeouts; at times health checks on an affected node failed
- 영향 사용자
- –
- 지역
- –
- 감지까지
- –
- 복구까지
- –
증상
인프라를 Google Cloud 로 모두 옮긴 뒤 Postgres 연결 타임아웃이 평소보다 많이 나서 인시던트를 선언했다. 초당 새로 여는 연결 수가 수백 개 수준에서 크게 오르내렸다.
일부 API 응답을 빠르게 하려고 쓰는 memcached 에서도 연결 타임아웃이 띄엄띄엄 났다. memcache 클라이언트의 기본 네트워크 타임아웃은 100ms 였고, memcache 서버까지는 보통 1ms 도 걸리지 않았다.
memcache 클라이언트의 MaxIdleConns 를 올리고 며칠이 지나자 "read i/o" 타임아웃이 훨씬 많이 보였다. 앱은 캐시에 값을 쓰다가 saving value to cache: setting cache value: read tcp 10.16.4.33:35586->10.67.0.5:11211: i/o timeout 오류를 냈다.
이 오류는 사고 타임라인 이벤트 목록을 캐시에 넣을 때 가장 자주 났다. 수십만 건의 요청 가운데 몇 건에서만 났고, 사용자, 조직, 노드, 요청 어느 쪽으로도 일정한 패턴이 보이지 않았다.
영향받은 요청 하나의 트레이스를 보니 캐시 set 이 수백 번 거의 동시에 일어났고, 같은 때 Google Cloud Storage 객체의 URL 을 만드는 호출도 아주 많았다. 캐시 호출 시간은 처음에 약 1ms 이하였다가 몇 자릿수만큼 늘어났고, 편차도 크게 벌어졌다.
그 요청을 처리한 쿠버네티스 노드의 지표에서는 새로 여는 연결 수가 크게 튀었고, 같은 때 드롭된 패킷이 늘었다. 노드 로그에는 전혀 다른 요청인 헬스 체크까지 캐시에 닿지 못해 실패한 기록이 있었다.
처음에는 연결이 만료될 때 여러 goroutine 이 같은 죽은 연결을 한꺼번에 다시 쓰려다 새 연결을 대량으로 여는 경쟁 조건을 의심했다. 연결 설정을 바꾸자 새 연결은 초당 약 200개에서 약 1개로 줄었지만, 캐시 오류는 완전히 사라지지 않았다.
변수를 줄이려고 memcached 를 Google 이 운영하는 서비스에서 클러스터 안의 자체 memcached 로 옮겼지만 거의 달라지지 않았다. 그러다 외부 서비스로 중복 호출을 보내던 별개의 문제를 고친 코드가 운영에 배포되자 문제가 거의 사라졌다. incident.io 는 이것을 보고 GKE 나 GCP 네트워크 자체에는 문제가 없을 가능성이 크다고 봤다.
원인
- 촉발
- 노드에서 짧게 열고 닫는 TCP 연결이 대량으로 생겼다. 연결 풀이 초당 수백 개씩 새 연결을 열었고, 실수로 들어간 데이터베이스 join 때문에 외부 제3자 서비스로 가는 중복 호출 수천 번이 한꺼번에 나갔다.
감지
Postgres 연결 타임아웃이 평소보다 많이 나는 것을 보고 인시던트를 선언했다.
조치
- Postgres 연결의 최대 수명을 15m 에서 30m 로 두 배 늘렸다.
- 연결 풀을 늘 N개의 연결을 열어 두는 고정 크기로 바꿨다.
- memcache 클라이언트의 MaxIdleConns 를 2 에서 20 으로 올렸다.
- 변수를 줄이려고 Google 이 운영하는 memcached 대신 쿠버네티스 클러스터 안에서 직접 돌리는 memcached 로 옮겼다. 이 전환으로는 거의 달라지지 않았다.
- 실수로 들어간 데이터베이스 join 때문에 외부 제3자 서비스로 중복 호출을 수천 번 보내던 문제의 수정을 운영에 배포했다. 그 뒤 데이터베이스 연결 문제와 캐시 문제가 거의 사라졌다.
후속 조치
- 외부로 나가는 네트워크 호출에 더 알맞은 동시성 한도를 둔다. 공급자의 rate limit 안에 있어도 노드에 영향을 줄 수 있기 때문이다.
교훈
가설을 너무 빨리 좁히지 않는다. 이런 네트워크 타임아웃을 보면 같은 파드만이 아니라 같은 노드에서 도는 모든 것을 포함해 시스템 전체의 활동을 봐야 한다. 오류와 그 영향은 대개 요청 하나에 머물지만 늘 그렇지는 않다. 외부로 나가는 네트워크 호출의 동시성도 제한해야 한다. 이전에는 공급자의 rate limit 이 주된 제약이었지만, rate limit 안에 있어도 노드에 영향을 줄 수 있다.
출처
관련 사례
같은 원인 · 공통 인메모리 캐시, 데이터베이스
같은 원인 · 공통 인메모리 캐시, 데이터베이스
IL-0202갑자기 몰린 쿼리와 데이터베이스 쓰기로 Honeycomb 수집 호스트가 메모리 부족으로 죽었고, 쿠버네티스 CrashLoopBackOff 가 용량 회복을 막아 US1 이벤트 수집이 한 시간 넘게 불안정했다Honeycomb · 2023 · sev1같은 원인 · 공통 인메모리 캐시, 데이터베이스
같은 원인 · 공통 인메모리 캐시, 데이터베이스
같은 원인 · 공통 인메모리 캐시, 데이터베이스
같은 원인 · 공통 인메모리 캐시
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0290GitLab.com 의 Redis Sidekiq 클러스터에서 노드 여러 대가 메모리를 다 써 멈추고 쿼럼을 잃어, 웹과 Git 과 CI 전반에서 500 오류가 늘었다GitLab · 2026 · sev1같은 원인 · 공통 인메모리 캐시
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0288CDN77 의 ClickHouse 데이터 파이프라인에서 이중화된 인스턴스 세 곳의 ZooKeeperWait 가 수천 초로 치솟아 복제가 한 시간 넘게 느려졌다CDN77 · 2026같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0305Intercom 의 PlanetScale 샤드 하나에서 복제본이 CPU 100% 로 주 데이터베이스를 따라가지 못해 받은편지함에 최대 2.2시간 전의 데이터가 보였다Intercom · 2026같은 원인 · 공통 데이터베이스
IL-0390PostHog US Cloud 의 Persons Postgres 데이터베이스 쓰기가 크게 느려져 이벤트와 persons 수집이 최대 2일 지연됐다PostHog · 2025같은 원인 · 공통 데이터베이스
같은 원인 · 공통 인메모리 캐시
IL-0287Atlas 와 Cloud Manager 의 모니터링을 받치는 내부 데이터베이스 클러스터의 샤드 하나가 과부하되어 지표 수집과 클러스터 작업이 늦어졌다MongoDB · 2025같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0067Redis 마스터의 50Mi 영구 볼륨이 가득 차 AOF 가 깨졌고, Redis 파드가 크래시 루프에 빠져 Klamm 운영 서비스가 멈췄다BC Government · 2025 · sev1같은 원인 · 공통 인메모리 캐시
같은 원인 · 공통 데이터베이스
IL-0298Wikimedia sessionstore 의 Cassandra 노드가 디스크가 가득 차 잇따라 죽고 쿼럼을 잃어 편집이 실패했다Wikimedia Foundation · 2025같은 원인 · 공통 데이터베이스
IL-0312max_connections 를 올리려고 재시작한 주 PostgreSQL 데이터베이스가 다시 올라오지 않아 Gadget 의 모든 앱 요청이 멈췄다Gadget · 2024같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0110Grafana Agent 파드가 메모리를 많이 쓰던 노드에 Hangfire 파드가 함께 올라가 시스템 OOM 으로 CrashLoopBackOff 를 반복했고, 노드가 응답을 멈추고 NotReady 가 됐다.DFDS · 2024같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 인메모리 캐시
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0206GKE 파드 안의 Consul 에이전트가 메모리 급증으로 거듭 OOM kill 되어 Rails 파드가 데이터베이스 복제본을 찾지 못했고, 모든 쿼리가 primary 로 몰려 GitLab.com 이 느려졌다.GitLab · 2022같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
IL-0496전역 복제 Cassandra 클러스터에서 모든 리전의 인스턴스 CPU 가 100% 로 치솟아 쿼리가 타임아웃됐고, 같은 부하가 이틀 저녁 더 찾아왔다Ably · 2020같은 원인 · 공통 데이터베이스
IL-0443Aurora MySQL reader 가 이유 없이 재시작한 뒤 writer 의 insert latency 가 7배쯤 오르고 replication lag 가 하루 넘게 이어졌다Repro · 2019같은 원인 · 공통 데이터베이스
IL-0037imagePullPolicy가 Always인 DaemonSet이 크래시 루프를 돌며 이미지를 계속 받아, NAT 세 대를 같이 쓰던 리전 전체가 이미지 레지스트리에서 429로 막혔다Datadog · 2019같은 원인 · 공통 데이터베이스
IL-0211Mandrill 의 PostgreSQL 샤드 하나가 트랜잭션 ID 랩어라운드를 막으려고 쓰기를 멈춰 약 40시간 동안 메일 발송이 줄었다Mailchimp · 2019같은 원인 · 공통 데이터베이스
IL-0064CPU 를 많이 쓰는 파드가 Google Cloud 노드 하나에 몰려 노드가 커널 패닉으로 죽었고, 다시 배치된 파드가 다음 노드를 또 죽이며 웹사이트와 API 가 멈췄다.Moonlight · 2019같은 원인 · 공통 데이터베이스
같은 원인 · 공통 CNI 플러그인
같은 원인 · 공통 데이터베이스
IL-0334RDS MySQL 의 bookmarks 테이블이 2TB 파일 크기 한도에 닿아 INSERT 가 실패하고 Instapaper 가 31시간 동안 멈췄다Instapaper · 2017같은 원인 · 공통 데이터베이스
IL-0333사양을 낮춘 RDS PostgreSQL 인스턴스가 피크 부하를 못 버텨 헬스 체크가 실패하고 Buildkite 대시보드가 몇 시간 동안 내려갔다Buildkite · 2016같은 원인 · 공통 데이터베이스
같은 원인 · 공통 인메모리 캐시
같은 원인 · 공통 인메모리 캐시
IL-0282US-East 리전의 DynamoDB 스토리지 서버들이 멤버십 정보를 받지 못해 스스로 요청 처리에서 빠지면서 고객 요청의 약 55% 가 실패했다Amazon Web Services · 2015같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
같은 원인 · 공통 데이터베이스
내 클러스터에도 있는지 확인하기
AI 도구와 스크립트용
- 이 사례의 JSON: https://incidentlib-api.benchlet.com/cases/IL-0386
- 가장 비슷한 사례들: https://incidentlib-api.benchlet.com/cases/IL-0386/similar
- MCP 서버(Streamable HTTP, 키 없음):
https://incidentlib-mcp.benchlet.com/mcp
API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.