IL-0083 Adevinta · 2023-06-13 (게시일)kubernetesnetworking
Adevinta 는 쿠버네티스 위에 SCHIP 이라는 런타임을 만들어 20개가 넘는 테넌트의 마이크로서비스를 여러 클러스터에서 돌린다. 클러스터 DNS 는 CoreDNS 가 맡고, 노드마다 dnsmasq 가 로컬 DNS 캐시로 돌며 CoreDNS 로 가는 요청을 줄인다. DNS 품질은 내부 질의가 16ms 안에, 외부 질의가 64ms 안에 풀리는 비율로 잰다.
한 클러스터에서 간헐적인 5xx 가 이어지는 동안 팀은 Ingress 컨트롤러와 노드 네트워크를 차례로 의심했지만 둘 다 원인이 아니었다. 영향받은 앱이 서비스 이름으로 내부 호출을 하는 프록시라는 점, fluent-bit 도 서비스 이름으로 로그 포워더를 부른다는 점에서 DNS 로 범위를 좁혔다. 이 클러스터의 DNS Latency SLI 는 꽤 오래 나빴지만, 다른 클러스터에 영향이 없어서 무시해 왔다.
세 가지 원인이 겹쳐 있었다. 첫째, dnsmasq 는 기본으로 노드당 동시 DNS 질의를 150개까지만 받는데 이 클러스터는 그 한도를 넘었다. 한도를 1500으로 올리자 SLI 가 바로 좋아졌지만 한 주 만에 다시 나빠졌다. 둘째, dnsmasq 가 외부 질의만 캐시하고 cluster.local 질의는 전부 CoreDNS 로 넘기고 있었다. 최근 CoreDNS 버전의 변경으로 응답에 Recursion Available 플래그가 빠졌고, dnsmasq 는 이 플래그가 없는 응답을 캐시하지 않는다. CoreDNS 가 RA 비트를 항상 넣도록 바꾸자 캐시 적중률이 크게 좋아졌지만, 한 주 뒤 SLI 가 다시 떨어졌다. 셋째, 문제 노드에서 DNStop 을 돌려 보니 ndots 문제로 생긴 풀 수 없는 도메인 질의가 초당 수백 건씩 쏟아지고 있었다. 점이 5개보다 적은 이름은 밖으로 나가기 전에 로컬 검색 도메인을 하나씩 붙여 질의한다. schip.io.svc.cluster.local, cluster.local.cluster.local 같은 이름이 그 결과였다.
이 질의를 dnsmasq 에서 NXDOMAIN 으로 끊고 fluent-bit 의 로그 라우터 호스트 이름을 FQDN 으로 바꾸자, CoreDNS 로 가는 요청이 초당 4000건이 넘던 데서 1000건 아래로 줄었다. DNS Latency SLI 는 99.9% 를 넘는 수준으로 돌아왔다. 설정은 모든 클러스터에 같았으므로 다른 큰 클러스터 두세 곳의 DNS 지연도 나빠져 있었다. 이 클러스터가 유독 심했던 것은 파드 밀도가 높고, 몇 시간마다 도는 CronJob 이 많아 DNS 질의가 가장 많았기 때문이다. 이 문제를 푸는 데 한 달이 걸렸다.
어느 금요일 오후, 고객 한 곳이 SCHIP 에서 돌리는 일부 서비스에서 HTTP 5xx 오류가 튄다고 알려 왔다. 팀은 바로 장애를 선언했다.
처음에는 클러스터 전체 트래픽을 받는 Ingress 컨트롤러를 의심했다. 그 시간대에 컨트롤러 인스턴스 수가 2개에서 5개 사이를 오갔고, CPU 스로틀링도 조금 있었다. 최소 인스턴스 수를 피크에 맞추고 CPU 를 늘렸지만, 월요일에 같은 문제가 계속된다는 보고가 다시 들어왔다. 인스턴스 수는 더 이상 흔들리지 않았고 스로틀링도 없었다. 문제는 하루에도 여러 번 짧게 되풀이됐다.
다음에는 네트워크 문제를 의심했다. 성능이 떨어질 때 "A fluent-bit agent stopped processing logs" 알림이 함께 왔고, 5xx 를 낸 서비스가 그 fluent-bit 와 같은 노드에 있었다. 팀은 전부터 이 알림을 노드 문제로 보고 노드를 드레인한 뒤 네트워크 계층을 재시작해 왔다. 이번에도 그렇게 했지만 보고는 계속 들어왔고, 모든 보고가 kubenurse_errors_total 같은 네트워크 오류 지표와 맞아떨어지지도 않았다. 오류는 대체로 한 시간마다, 특히 자정 무렵에 많이 났다.
영향받은 애플리케이션을 직접 들여다보니 품질 저하는 소수의 앱에서, 그중에서도 주로 프록시 앱 하나에서 나타났다. 이 앱은 http://foo/api 처럼 쿠버네티스 서비스 이름으로 내부 호출을 했다. fluent-bit 도 log-router-ingress-forward 라는 서비스 이름으로 로그 포워더를 불렀다. 이 클러스터의 DNS Latency SLI 는 다른 클러스터보다 한참 낮았고, 서비스가 나빠진 시각은 DNS 캐시 미스가 늘어난 시각과 겹쳤다. dnsmasq 로그에는 다음 줄이 찍혀 있었다.
I0920 12:39:44.923951 6 nanny.go:146] dnsmasq[25]: Maximum number of concurrent DNS queries reached (max: 150)
원인 ? DNS·네트워크 장애
고객이 SCHIP 에서 돌리는 일부 서비스의 HTTP 5xx 가 튄다고 알려 와서 알았다. DNS 와의 관계는 한참 뒤에야 드러났고, 그때 보니 그동안 무시해 온 이 클러스터의 DNS Latency SLI 가 다른 클러스터보다 낮아져 있었다.
–
SLO 를 보기 좋은 지표로만 두지 말고 안전장치로 써야 한다. 이번에는 나빠진 DNS Latency SLI 를 오래 무시한 탓에 원인을 늦게 찾았다. SLO 를 안전장치로 쓰려면 믿을 수 있는 SLI 가 먼저 있어야 한다. 조사가 여러 당직자에게 흩어져 있었고, 관찰 결과와 가설을 한곳에 모으지 않아 같은 가설이나 이미 버린 가설을 다시 붙잡기도 했다. 가설 하나를 버린 뒤에 다음 가설로 넘어가야 한다. 기존 지표에 없는 데이터는 DNStop 처럼 직접 모아야 한다. 멀티 테넌트 환경에서는 DNS 를 한 번 개선하면 모든 고객이 그 효과를 본다.
같은 원인 · 공통 CoreDNS
같은 원인 · 공통 클라이언트 쪽 DNS 리졸버와 캐시