이 글과 관련된 다른 글 보기
- 쿠키런: 킹덤 런칭 회고 - DevOps 관점에서 본 쿠키런: 킹덤 런칭 회고
- CockroachDB in Production - CockroachDB에 대한 소개와 킹덤에서 CockroachDB를 사용한 이유 설명
- 쿠키런: 킹덤 데이터베이스 스토리지 레이어 복원기 - 엔지니어 관점 기록한 개괄적인 장애 대응 과정과 회고
- CTO가 커리어를 걸고 비트 레벨까지 내려가서 DB를 해킹했던 이야기 - CockroachDB의 소스코드를 참고하며 바이너리 파일로부터 데이터를 복구한 이야기
- 입사 첫날에 36시간 점검 경험하기 - 신규입사자의 관점에서 서술된 장애 대응 기록
- 쿠키런: 킹덤 길드 업데이트 이후 서비스 이슈 되돌아보기 - 쿠키런: 킹덤에 길드 기능이 추가된 이후 발생한 서비스 이슈 회고
안녕하세요, 데브시스터즈 진저랩 플랫폼셀에서 소프트웨어 엔지니어로 일하고 있는 박새미, 인프라셀에서 일하고 있는 데브옵스 엔지니어 이창원입니다. 이 글에서는 2022년 NDC에서 함께 발표한 쿠키런: 킹덤, 총 56시간의 긴급 점검 회고 - 그때 그 명검은 왜 뽑아야 했는가 세션에서도 다룬 바 있는, 2021년 2월 19일에 발생한 AWS 도쿄 리전 데이터센터 장 애에 대해 공유해 드리고자 합니다. 만약 정보를 접할 때 글보다 영상을 선호하는 편이시라면, 해당 세션 영상을 보시는 것을 권해드립니다.
CockroachDB? 분산 데이터베이스!
어느 평화로운 봄날, 회식 자리에서 DB 노드 한 대가 내려갔다는 에러 알람이 슬랙에 나타났지만, 데브옵스 엔지니어들은 크게 당황하지 않았습니다. AWS 같은 거대한 클라우드 벤더사라고 해서 100% SLA를 보장하지는 못하기도 하고요. 무엇보다도 CockroachDB는 이러한 장애를 견딜 수 있게 설계된 분산 데이터베이스이기 때문입니다.
기본적으로 분산 DB는 일부 노드가 정상적으로 동작하지 않아도 견딜 수 있게끔 설계됩니다. CockroachDB는 기본적으로 3대의 레플리카를 두게 되어 있으며, 각 Range[1] 는 레플리카들에 복사되어 저장됩니다. CockroachDB는 Raft 알고리즘을 채택하였고 이에 따라 DB가 N대 있다고 했을 때 (N/2) + 1 이상의 값, 즉 과반수를 정족수로 사용합니다. 결과적으로 정족수가 깨지지 않는 한 일부 노드가 죽어도 영향을 받지 않게 설계된 것이지요. 예를 들어 Replication을 5대로 설정한다면, (5/2)-1대 미만의 노드가 죽어도 DB를 이용하는 데는 문제가 없습니다. CockroachDB에 더 자세히 알고싶으시다면 진저랩 인프라셀 이준성 님이 쓰신 CockroachDB in Production을 읽어보시는 것을 추천드립니다.
다만 분산 DB라 하더라도 3분 만에 또 2대, 6분 뒤에 2대, 20분 후에 2대… 22분 만에 총 60대[2] 중 6대의 노드가 작동 불능이 되는 것은 조금 다른 이야기입니다. 엔지니어들은 빠르게 상황 파악 및 대응에 나섰습니다.
무슨 일이 일어나고 있나요?
애플리케이션 레벨에서 DB 호출과 관련된 치명적인 로직이 없고 DB 설계 자체에도 결함이 없다면, 12분만에 6대의 노드가 장애를 겪는 건 뭔가 다른 곳에 원인이 있다는 뜻일 것입니다. 이렇게 다발적이고 급격하게 Failure가 발생할 경우에는 문제의 Scope를 정확히 파악하는 것이 중요하다고 생각합니다. 여러 커뮤니티 사이트들을 살펴보니 저희만 겪는 문제가 아닌 것도 같았습니다. 또한 AWS 고객사로 알려진 다른 서비스들도 문제가 발생했다는 정황을 다양한 경로에서 파악할 수 있었습니다. 상황을 파악해본 결과, 해당 장애의 원인은 AWS 도쿄리전 데이터센터의 냉각 시스템 고장이었습니다. 서버 머신들이 과열되어 작동에 문제가 발생한 것이었습니다. 안타까운 점은 저희의 경우 고장 난 냉각 시스템의 범위에 있던 서버들이 게임 서버가 아니라 하필 DB였고, AZ 장애에 대한 고려가 배제되었었다는 점입니다. 게임 서버였다면 큰 문제 없이 자동으로 새 서버 인스턴스가 떴을 것이고, 순간적인 서비스 불안정 정도는 발생했을 수 있었겠지만, 점검을 걸 필요까지는 없었을 것입니다.
AZ 장애는 왜 고려하지 않았는가?
CockroachDB는 AZ 혹은 Region 장애까지도 대비할 수 있는 Locality라는 기능이 있습니다. 하지만 자동으로 지정되는 것이 아니고, 당연하게도 (사람) Operator가 알맞은 Topology 설 정을 따로 해줘야 합니다. 그러면 노드가 클러스터에 합류한 이후에 Replica를 분배받을 때, 하나의 Topology가 완전히 날아가더라도 데이터 유실이 발생하지 않도록 분배받게 됩니다.
저희는 Kubernetes 위에 CockroachDB를 배포하였고, 데이터베이스라는 하나의 논리적인 단위이니만큼 하나의 통일된 Helm Chart를 사용해서 배포를 관리하고자 했습니다. Multi-AZ 배포를 위한 Topology는 CockroachDB Pod이 생성되는 시점에 배정이 되어야 하는데, 이 정보는 배포를 준비하는 차트 작성 단계에는 알 수가 없고, Pod이 특정 노드에 물리적으로 배정이 되고 난 이후에야 비로소 정해지며 Kubernetes API를 통해서도 제공이 되지 않습니다. 작성에 필요한 정보가 부재한 상황을 우회하려면 기술적 복잡성이 과도하게 가중되는 상황이었기 때문에, 자연스레 이 정도의 중요도가 있는 작업인지를 따져보게 되었습니다. 데브시스터즈는 2013년 쿠키런 for Kakao 시절부터 AWS를 사용해왔지만, AZ 장애가 한번도 발생하지 않았다는 점을 고려했을때, 차라리 보다 시급한 조치가 필요한 다른 일부터 진행하기로 결정했습니다. 대표적으로, Instance Retirement 같이 보다 흔하고 동시다발적으로 발생할 수 있는 시나리오에 대비하기로 하였습니다. 이전 기록들을 기반으로 동시에 여러 노드가 Retire될 확률을 경험적으로 계산하여 3대까지는 동시에 내려가도 데이터 손실이 발생하지 않도록 Replication Factor를 7로 설정해두었습니다. 물론 이 결정은 오랜 기간 안정적으로 사용해왔던 클라우드 프로바이더에 대한 신뢰가 있었기에 할 수 있었던 결정이었습니다. 으레 플래그들이 그렇듯이, 그때는 이것이 아주 완벽한 플래그로 작용하게 될 결정이라는 것을 몰랐습니다…
장애 영향 범위
결과적으로 안전 마진으로 설정해둔 3대를 넘어서는 6대의 노드에서 Host Status Failure가 발생했기 때문에 전체 25,000개의 Range 중 Data Range 2개, System Range 32개가 소실되었습니다. Range의 레플리카는 7로 설정되어 있었고, 각 Range의 레플리카 중 과반인 4개 이상의 Replica가 하필 문제의 노드 6대에 들어있을 확률을 계산해보면 대략 0.09%입니다. Range 각각에 대해 독립사건이라고 가정했을 때, 동전을 25000번 던지는 것과 유사하니 B(25000, 0.09)라고 할 수 있습니다. 평균적으로는 약 23개가 영향을 받는 정도의 확률이고, 32개의 Range가 소실될 확률까지 계산해보면 약 2.3% 정도에 불과합니다.
System Range의 경우 클러스터에 저장된 데이터들의 위치를 포함한 각종 메타 정보가 포함되어 있습니다. Cockroach Labs 서포트 엔지니어 측에 확인해보니 System Range는 소실되어도 복구할 수 있다고 하여, 저희는 실제 유저분들의 데이터가 저장된 Data Range 2개를 복구하는 데 최대한 집중하였습니다.