IL-0029 Buffer · 2020-08-31 (게시일)kubernetesaws
Buffer 는 2016년부터 쿠버네티스를 썼다. kops 로 관리하는 AWS 클러스터에 노드 약 60대, 컨테이너 약 1500개를 운영했다. 컨테이너가 노드의 CPU 를 다 써서 kubelet 같은 핵심 프로세스가 응답하지 않는 일을 막으려고 CPU 한도를 걸었다. CPU 한도는 컨테이너가 한 주기 동안 쓸 수 있는 최대 CPU 시간이고, 주기의 기본값은 100ms 다. 쿠버네티스는 CFS 쿼터로 컨테이너를 스로틀링해 이 한도를 지킨다.
그런데 리눅스 커널 버그 때문에 CPU 한도가 걸린 컨테이너는 사용량이 낮을 때도 스로틀링되었고, 그만큼 서비스가 느려졌다. 수정은 4.19 이상 커널에 들어갔다. 하지만 Buffer 가 쓰던 kops 버전의 기본 호스트 이미지에는 아직 수정이 없었다. kops 는 1.18 부터 Ubuntu 20.04 를 기본 이미지로 쓴다.
팀은 긴 논의 끝에 사용자에게 직접 또는 간접으로 닿는 경로의 서비스에서 CPU 한도를 모두 없앴다. 한도를 없앤 서비스는 테인트를 건 노드로 모아 한도가 있는 서비스와 떼어 놓았다. Datadog 에 쌓인 몇 달 치 사용량을 보고 최대 CPU 사용량에 20% 넘는 여유를 더해 CPU 요청값으로 정했고, 메모리 요청값도 같은 방식으로 정했다. 몇 주 뒤 바꾼 서비스 전반에서 지연 시간이 줄었고, 메인 랜딩 페이지 buffer.com 은 최대 22배 빨라졌다.
Buffer 엔지니어가 컨테이너의 스로틀링 지표를 살펴보니, CPU 사용량이 한도 근처에도 가지 않은 컨테이너가 많이 스로틀링되고 있었다.
주요 API 하나는 CPU 한도가 800m 이었고 최대 사용량은 200m 정도였다. 그런데도 스로틀링이 일어났다. 원문은 CPU 사용량 그래프와 스로틀링 그래프를 나란히 놓고, 사용량이 한도보다 훨씬 낮을 때도 스로틀링이 일어나는 모습을 보여 준다.
팀은 GitHub 이슈, Zalando 발표, Omio 글에서 스로틀링이 서비스 성능을 떨어뜨리고 지연 시간을 늘린다는 이야기를 찾았다. 원인은 CPU 한도가 걸린 컨테이너를 필요 없이 스로틀링하는 리눅스 커널 버그였다.
한편 팀은 CPU 한도를 걸지 않았을 때의 위험도 이미 겪었다. 자원을 많이 쓰는 서비스 때문에 노드의 kubelet 이 응답하지 않았고, 노드가 NotReady 가 되었다. 그 노드의 파드가 다른 노드로 다시 스케줄되면서 새 노드에서도 같은 문제가 생겼다.
원인 ? 소프트웨어 결함
엔지니어가 컨테이너의 스로틀링 지표를 살피다가, CPU 사용량이 한도보다 훨씬 낮은 컨테이너도 많이 스로틀링되는 것을 보고 알았다.
리눅스에서 컨테이너를 돌리면 쿠버네티스든 Mesos 든 Swarm 이든 스로틀링 때문에 컨테이너가 제 성능을 내지 못할 수 있다. 먼저 커널을 수정된 버전으로 올리고 스로틀링 지표를 지켜보는 편이 낫다. CPU 한도를 없애면 지연 시간은 줄지만 위험하다. 한도를 없앤다면 CPU 요청값을 제대로 잡고, 노드의 CPU 와 메모리 사용량을 꼼꼼히 모니터링한다. 사용량이 높으면 Horizontal Pod Autoscaler 로 파드를 늘려 여유 있는 노드에 배치되게 한다. 클러스터에 여유가 없으면 알림을 받거나 노드 오토스케일러로 노드를 늘린다.
같은 원인 · 공통 노드 운영체제 이미지, 리눅스 커널
같은 원인 · 공통 컨테이너 CPU 한도, 리눅스 커널
같은 원인 · 공통 노드 운영체제 이미지, 리눅스 커널
같은 원인 · 공통 노드 운영체제 이미지
같은 원인 · 공통 노드 운영체제 이미지
같은 원인 · 공통 리눅스 커널
같은 원인 · 공통 컨테이너 CPU 한도
같은 원인 · 공통 노드 운영체제 이미지