{"id":"IL-0057","org":"Prezi","date":"2019-10-03","docs":["https://tech.xing.com/a-reason-for-unexplained-connection-timeouts-on-kubernetes-docker-abd041cf7e02","https://docs.aws.amazon.com/eks/latest/userguide/external-snat.html","https://github.com/awsdocs/amazon-eks-user-guide/pull/53","https://github.com/aws/amazon-vpc-cni-k8s","http://nginx.org/en/docs/http/ngx_http_upstream_module.html#variables"],"title":{"en":"Higher p99 latency after moving a reverse proxy to EKS, from outgoing connections delayed by a SNAT conntrack race","ko":"EKS 노드의 SNAT 과정에서 conntrack 경합으로 바깥으로 나가는 TCP 연결이 1초나 3초씩 늦어져, 서비스 간 호출이 많은 서비스의 p99 지연이 늘었다."},"domain":["kubernetes","aws","networking"],"impact":{"scope":"tail latency (p99) of a few services that make many sequential service-to-service calls through the reverse proxy","users":"unknown","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"Alerting on tail latency instead of averages caught a problem that would otherwise have gone unnoticed, and tracing turned a vague slowdown into a measured connect delay. Delays of exactly 1 or 3 seconds on new outgoing connections point to dropped SYN packets, and on EKS the SNAT done by the VPC CNI is where to look.","ko":"쿠버네티스 같은 복잡한 시스템을 디버깅할 때는 관측 가능성이 핵심이다. 평균 응답 시간 대신 p99 를 보고 있었기에 문제를 알아챘고, 추적을 붙여 느린 요청의 특징을 알게 되자 원인 가까이 갈 수 있었다. 실제 해법을 찾으려면 SNAT 가 어떻게 동작하는지, EKS 내부와 amazon-vpc-cni-k8s 플러그인이 어떤 역할을 하는지까지 이해해야 했다. EKS 에서는 노드 AMI 의 iptables 가 무작위 포트 할당을 지원하지 않을 수 있고, 그때는 외부 SNAT 설정이 대안이 된다."},"related":[],"sources":[{"url":"https://engineering.prezi.com/https-engineering-prezi-com-a-kubernetes-crime-story-2e8d75a77630","kind":"blog","license":"unknown","archived":"https://web.archive.org/web/20191104181113/https://engineering.prezi.com/https-engineering-prezi-com-a-kubernetes-crime-story-2e8d75a77630?gi=f5adf29025d0"}],"summary":{"en":"When a pod connects to an external service, meaning one with a public IP, the outgoing packet goes through source network address translation (SNAT) on the worker node, set up by iptables rules. A race condition in the Netfilter module sometimes drops SYN packets while new connection entries are inserted into the conntrack table, which leads to connection timeouts of 1 or 3 seconds. A search for \"kubernetes slow outgoing connections\" led Prezi to a XING article describing exactly these symptoms.\n\nThe fix that article proposes, switching the port allocation to fully random, was not usable on EKS: the amazon-vpc-cni-k8s plugin supports AWS_VPC_K8S_CNI_RANDOMIZESNAT=prng, but the iptables version in the official AMI did not. Prezi instead set AWS_VPC_K8S_CNI_EXTERNALSNAT=true, which turns off SNAT on the node altogether. The write-up calls the EKS documentation for that option misleading and points to an open pull request about it.\n\nAfter the setting was applied on 8/15, latency returned to the baseline from before the proxy migration. Some improvement from 8/10 came only from running more pods on more nodes, so each pod saw less traffic and hit the race less often.","ko":"Prezi 는 Nginx 기반 리버스 프록시 smartgateway 를 ElasticBeanstalk 에서 AWS EKS 로 옮겼다. Prezi 에서는 서비스 간 원격 호출도 이 프록시를 거친다. 옮긴 뒤 서비스 간 호출을 연달아 많이 하는 몇몇 서비스의 p99 지연이 올라갔다. 예전처럼 평균 응답 시간만 봤다면 놓쳤을 차이였다.\n\n팀은 AWS X-Ray 로 추적을 붙이고 $upstream_connect_time 을 기록해, 프록시가 다음 서비스로 TCP 연결을 맺는 데 1초나 3초가 걸린다는 것을 확인했다. \"kubernetes slow outgoing connections\" 로 검색해 찾은 XING 의 글이 같은 증상을 설명하고 있었다. 파드가 공인 IP 를 가진 서비스로 연결하면, 나가는 패킷은 기본적으로 워커 노드에서 iptables 규칙에 따라 SNAT 를 거친다. 그런데 Netfilter 모듈에 경합 조건이 있어서, conntrack 테이블에 새 연결 항목을 넣을 때 SYN 패킷이 가끔 버려지고 1초나 3초의 연결 타임아웃이 생긴다.\n\nXING 글이 제안한 해법은 포트 할당 방식을 완전 무작위로 바꾸는 것이었다. amazon-vpc-cni-k8s 플러그인은 AWS_VPC_K8S_CNI_RANDOMIZESNAT=prng 설정을 지원하지만, 공식 AMI 에 들어 있는 iptables 버전이 이를 지원하지 않았다. 팀은 대신 AWS_VPC_K8S_CNI_EXTERNALSNAT=true 로 노드의 SNAT 를 아예 껐다. 8/15 에 이 환경 변수를 적용하자 지연이 프록시 이전 기준으로 돌아왔다. 8/10 무렵 지연이 조금 나아진 것은 파드를 더 많은 노드에 더 많이 띄워 파드 하나가 받는 트래픽을 줄였기 때문이었다."},"trigger":{"en":"Moving the reverse proxy onto shared EKS worker nodes, where its outgoing connections went through source NAT on the node and some SYN packets were dropped by a race in Netfilter's conntrack.","ko":"리버스 프록시를 전용 ElasticBeanstalk 머신에서 공용 EKS 워커 노드로 옮기자, 프록시가 다른 서비스로 보내는 패킷이 노드에서 iptables 규칙에 따라 SNAT 를 거치게 되었다."},"severity":"unknown","symptoms":["high-latency","intermittent-timeouts"],"timeline":{"detected_after":null,"resolved_after":null},"date_kind":"published","detection":{"en":"Prometheus alerts on p99 latency fired after the reverse proxy migration.","ko":"Prometheus 가 몇몇 서비스의 p99 지연 증가에 알림을 보냈다. 예전처럼 평균 응답 시간만 봤다면 꼬리 지연만 오른 이번 문제는 십중팔구 놓쳤을 것이다."},"components":["conntrack","vpc-cni","linux-kernel","node-image"],"root_cause":"dns-network","remediation":[{"text":{"en":"added AWS X-Ray tracing and an $upstream_connect_time trace attribute to locate the delay","ko":"지연이 생기는 곳을 찾으려고 AWS X-Ray 추적을 붙이고, 추적에 $upstream_connect_time 속성을 더했다."}},{"text":{"en":"ran more pods of the service on more nodes, which reduced but did not end the delays","ko":"해당 서비스의 파드를 더 많은 노드에 더 많이 띄웠다. 지연은 줄었지만 사라지지 않았다."}},{"text":{"en":"set AWS_VPC_K8S_CNI_EXTERNALSNAT=true on the AWS VPC CNI to turn off SNAT on the nodes","ko":"AWS VPC CNI 에 AWS_VPC_K8S_CNI_EXTERNALSNAT=true 를 설정해 노드에서 SNAT 를 껐다."}}],"action_items":[],"contributing":["default-config-unchanged","known-bug-unpatched"],"recurrence_of":null,"symptoms_text":{"en":"Prometheus alerts fired on tail latency: from 7/24, the p99 response time of a few services went up after Prezi moved its Nginx-based reverse proxy, smartgateway, from dedicated Elastic Beanstalk machines onto shared Kubernetes worker nodes. The bump affected only the tail, so the earlier monitoring of average response times would most certainly have missed it.\n\nThe slow requests were in services that make many sequential service-to-service calls, which at Prezi also pass through the proxy. Stress tests reproduced it. AWS X-Ray traces, added for this investigation, showed a call chain smartgateway → prezipage → smartgateway → presentationservice taking 1.3 seconds, of which a full second was spent between smartgateway and presentationservice, while presentationservice itself answered in 12.8 ms.\n\nThe extra delay was always exactly 1 second or, less often, 3 seconds. A custom trace attribute carrying Nginx's $upstream_connect_time confirmed that the time went into opening the outgoing TCP connection.","ko":"Nginx 기반 리버스 프록시를 쿠버네티스로 옮긴 뒤, Prometheus 가 몇몇 서비스의 p99 지연 증가에 알림을 보냈다. 그래프에서 p99 지연은 7/24 부터 올라가 있었다.\n\n지연은 서비스 간 호출을 연달아 많이 하는 서비스에서 보였고, 부하 테스트로 재현할 수 있었다. 바뀐 것은 리버스 프록시가 전용 ElasticBeanstalk 머신 대신 공용 쿠버네티스 워커 노드에서 돈다는 점 하나였다. 컨테이너는 같았고, 비슷한 사설 VPC 서브넷에서 비슷한 양의 자원을 썼다.\n\n팀은 AWS X-Ray 추적을 붙였다. 느린 추적은 smartgateway → prezipage → smartgateway → presentationservice 순서로 흘렀다. 1.3초 걸린 추적에서 smartgateway 가 presentationservice 로 요청을 넘기는 데 꼬박 1초가 걸렸고, presentationservice 는 12.8ms 만에 응답했다. 지연은 늘 정확히 1초였고, 드물게 3초였다.\n\n추적에 Nginx 의 $upstream_connect_time 값을 속성으로 붙여 보니, 바깥으로 나가는 TCP 연결을 맺는 단계에서 시간이 걸린다는 가정이 맞았다."},"updated_at":"2026-11-08T19:10:30.943129Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0057","org_slug":"prezi"}