[논문 리뷰] Automatic Reliability Testing for Cluster Management Controllers
클레온의 MLOps팀에는 infra파트와 data파트가 있습니다. 이번에는 infra팀에서 논문을 하나 소개드리려고 합니다. OSDI 2022에 accept된 “Automatic Reliability Testing for Cluster Management Controllers”라는 논문 입니다.
paper and video link: https://www.usenix.org/conference/osdi22/presentation/s
github link: https://github.com/sieve-project/sieve
큰 스케일의 서비스를 운영하는 것은 쉽지 않습니다. 이렇듯 복잡한 서비스 관리 및 배포를 도와주는 것이 쿠버네티스 입니다. 쿠버네티스를 사용하면 배포 프로세스를 단순화할 수 있으며, 사용중인 리소스들에 대한 정보도 손쉽게 얻을 수 있고, 지속적인 상태 확인 및 셀프 힐링, 그리고 오토 스케일링까지 가능합니다.
이러한 쿠버네티스를 손쉽게 사용할 수 있도록 도와주는 패턴 중의 하나가 operator 입니다. operator는 custom resources를 사용하여 어플리케이션을 관리할 수 있도록 해줍니다. 이러한 operator는 쿠버네티스의 control loop에 기반하여 동작하며, custom resource의 state를 주시(watch)하다가 변화가 생기면 (change events), 쿠버네티스 API를 통하여 클러스터의 상태를 변화시킵니다 (adjust state).
Operator와 같이 클러스터를 관리하는 컨트롤러들은 쿠버네티스 클러스터를 관리함에 있어 정말 중요하고 편리한 요소입니다. 하지만, 서로 다른 수많은 framework들을 위한 컨트롤러들이 따로 개발되고 있으며, 그로 인해 쿠버네티스 커뮤니티 상에는 수천 개의 컨트롤러들이 있습니다. 예를 들어, Cassandra를 위한 컨트롤러, MongoDB를 위한 컨트롤러 등이 다 따로 개발 및 유지 되고 있습니다.
이러한 컨트롤러들을 개발할 때, 개발자가 모든 장애 상황들을 고려하여 개발하면 좋겠지만, 수많은 장애 상황들을 모두 고려하며 만들기에는 한계가 있습니다. 이번 논문에서는 이러한 컨트롤러들에 대해서 reliability test를 자동으로 해줄 수 있는 framework인 Sieve를 제안합니다.
쿠버네티스 컨트롤러는 위에서 말씀드렸던 것처럼, 쿠버네티스 클러스터의 상태를 원하는 상태 (desired state)로 만들기 위해 계속해서 상태를 주시합니다. 만약 현재 상태가 원하는 상태와 동일하다면 변화가 없겠지만, 다르다면 상태를 update하는 API를 통해서 원하는 상태를 만듭니다. 아무런 장애가 없는 상황에서는 개발자가 예측한 대로 원하는 상태에 도달하겠지만, 예상치 못한 장애는 컨트롤러가 원하는 상태를 만들어주지 못하는 경우가 생깁니다. 이러한 상황들에 도달하는 시나리오들은 뒤에서 더 깊이 있게 다루겠습니다.
다음으로 Sieve가 컨트롤러의 bug를 찾는 방법을 말씀 드리겠습니다. 컨트롤러는 state를 보고 결정을 내립니다. Sieve는 이러한 컨트롤러의 특성을 활용하여, 다양한 장애 환경에서 state가 어떻게 변하는지를 기록합니다. 즉, 장애가 없는 상황에서의 state 변화와 장애 상황에서의 state 변화를 비교합니다. 이렇게 state object의 semantic 없이 bug 여부를 판단하는 방법을 저자는 differential oracle 이라고 이야기 합니다.
Sieve의 reliability test 방식은 다음의 다섯스텝으로 이루어집니다.
1. 장애 없는 환경에서의 reference trace를 수집합니다.
2. 어떤 fault를 언제 inject 할지를 정해 test plan을 생성합니다.
3. 테스트 효율성을 위해 명백하게 bug가 없을 테스트는 제외합니다.
4. test plan을 실행합니다.
5. test results를 확인합니다.
Test plan을 생성할때, Sieve는 다음 세가지 state에 도달하는 bug들을 찾습니다.
- Intermediate state
Intermediate state는 컨트롤러가 최종 state까지 도달하지 못하고 중간 state에 있는 상황을 이야기 합니다. 이렇게 multi-step update가 있는 경우에, atomicity를 보장할 수 있도록 구현하면 좋겠지만, 보장하지 못하는 경우에는 중간 state에서 멈추는 bug가 생길 수 있습니다.
2. Stale state
어플리케이션의 퍼포먼스와 scalability를 위해 asynchrony와 cache를 많이 사용하게 되면 stale state에 도달하는 상황이 생깁니다. 위의 figure 2 처럼 컨트롤러가 strongly consistent data store와 직접적으로 통신하는 것이 아닌, API server를 통해 통신하는 경우가 많습니다. 이 경우에 stale view가 latest state로 업데이트 되기까지 생기는 “time travel”로 인해 컨트롤러가 잘못된 결정을 내릴 수 있습니다. 논문에서는 이러한 stale-state bug로 인해 live MongoDB cluster를 컨트롤러가 실수로 삭제하는 경우를 보여줍니다.
3. Unobserved state
마지막으로 unobserved state의 경우는, 컨트롤러가 모든 state의 변화를 관리하기에는 비용이 비쌉니다. 이로 인해, 컨트롤러는 level-triggered 시스템으로 디자인이 됩니다 (모든 state의 변화를 관리하는 것은 edge-triggered 시스템) 입니다. 이렇게 모든 state의 변화를 관리하는 것이 아니다보니, 특정 state 변화들이 컨트롤러와의 협동을 잘못하였을 경우에는 원하지 않는 state에 도달하게 됩니다.
Evaluation 결과는 컨트롤러들에 꽤나 많은 bug들이 있다는 것을 보여줍니다. 저자는 Sieve를 열 개의 유명 쿠버네티스 컨트롤러에 적용하였습니다. 그리고 46개의 bug를 찾아내었습니다. 또한, 46–99%의 필요없는 테스트를 진행하지 않았으며, false positive의 비율은 3–5% 였습니다.
찾아낸 46개의 bug 중에 35개가 커뮤니티에 의해 confirmed 되었으며, 총 22개가 고쳐졌다고 합니다!
컨트롤러를 개발하는 것은 쉽지 않은 일입니다. 그러나, 열심히 개발한 컨트롤러가 여러 장애 상황들에 대해 reliable하지 않는다면, 실 서비스에서 사용하기 어려울 것입니다. 이번 논문에서 제안한 Sieve는 이러한 컨트롤러의 reliability test를 자동화 해주었습니다. Sieve의 경우는 open source로도 나와있으니, 사용하시는 컨트롤러에 bug가 없는지 한 번 테스트 해 보는 것도 좋을 것 같습니다!
클레온에서도 안정적으로 서비스를 제공하기 위해 항상 공부하고 여러 테스트로 준비해 두겠습니다. 클레온의 서비스를 많이많이 이용해 주세요 :)