IL-0193 Grafana Labs · 2019-12-07kubernetesgcpobservability
Grafana Labs 는 호스팅 Graphite 서비스를 여러 지역의 쿠버네티스 클러스터에서 돌린다. 클러스터마다 Metrictank 클러스터가 하나 이상 있고, 대부분은 역시 쿠버네티스 위에서 도는 Cassandra 를 저장소로 쓴다.
12월 7일 GCP SSD 영구 디스크 장애로 노드에서 커널 교착과 파일 시스템 손상이 생겼고 노드가 자동으로 재부팅됐다. 다시 올라온 노드 일부는 Cassandra 파드의 볼륨을 붙이지 못했다. Cassandra StatefulSet 의 Pod Management Policy 는 OrderedReady 였다. 이 정책은 파드를 하나씩 순서대로 띄우고, 앞 파드가 정상이 되어야 다음 파드를 띄운다. 모든 Cassandra 파드가 죽은 상태에서 두 번째 파드의 볼륨이 여전히 붙지 않았고, 그 뒤 파드는 하나도 뜨지 못했다. Google 은 대부분의 볼륨이 정상이라고 알렸지만 이 볼륨 하나가 전체 복구를 막았다.
GCP 장애가 풀린 뒤 팀은 StatefulSet 을 지우고 정책을 바꿔 다시 만들었다. 파드 하나를 빼고 모두 떴고, Cassandra 클러스터는 정상으로 돌아왔다. 그런데 Metrictank 는 다시 연결하지 못했다. Metrictank 는 Cassandra 노드 하나에라도 연결되어 있으면 그 노드에서 다시 만들어진 노드의 IP 를 받아 온다. 이번에는 모든 Cassandra 노드가 새 IP 로 다시 만들어져 연결이 완전히 끊겼다. 아무도 이런 장애를 미리 생각해 두지 않았다.
연결을 되살리려고 모든 Metrictank 인스턴스를 재시작했고, 이 작업은 20시간 넘게 걸렸다. 긴 장애 동안 데이터를 잃지 않으려고 Kafka 토픽 보존 기간을 늘려 두었기 때문에, 재시작한 인스턴스는 평소보다 많은 데이터를 다시 읽어야 했다. 이 과정에서 오래된 Metrictank 버그가 복구를 더 늦췄다. Cassandra 쓰기 큐가 가득 찬 상태에서 이미 큐에 항목이 있는 시리즈의 데이터가 들어오면 교착이 생겼다. 수집기는 큐가 차면 일부러 멈추는데, 멈춘 자리에서 시리즈 상태를 지키는 내부 잠금을 쥐고 있었다. 큐가 비려면 Cassandra 에 저장한 뒤 부르는 콜백이 같은 잠금을 얻어야 했다. 결국 수집기는 큐가 비기를 기다리고, 큐는 잠금이 풀리기를 기다렸다. 팀은 이 버그를 고치려면 큰 리팩터링이 필요하다고 여겨 미뤄 왔고, 보통은 쓰기 큐 크기를 넉넉히 늘리는 설정 변경으로 피해 왔다.
Metrictank 인스턴스 일부가 쓰기 큐를 비우지 못한다는 알림이 왔다. Metrictank 가 Cassandra 에 쓰지 못하고 있다는 뜻이었다.
그 무렵 Google 은 아직 장애 보고를 올리지 않았다. 팀원 한 명이 자기 Discord 채팅 서버가 죽은 것을 알아챘는데, 그 서버도 GCP 에 있었기 때문에 GCP 쪽 문제라고 짐작했다. 장애가 시작되고 약 90분 뒤 Google 이 장애 보고를 올려 짐작이 맞았음을 확인했다.
SSD 영구 볼륨의 성능이 심하게 떨어져 I/O 가 오랫동안 실패했다. 노드에서 커널 교착과 가벼운 파일 시스템 손상이 생겼고, 노드의 모니터링 프로세스가 자동으로 재부팅을 걸었다. 다시 올라온 노드 일부는 Cassandra 파드가 쓸 디스크 볼륨을 붙이지 못했고, 그 때문에 다시 재부팅됐다. Cassandra 쓰기는 완전히 실패하거나 2초 넘게 걸렸다. 새 노드라면 디스크를 붙일 수 있을 것이라 보고 컴퓨트 노드를 늘려 봤지만 소용없었다.
사용자 쪽에서는 US-East 클러스터의 Grafana Cloud Graphite 고객이 메모리 캐시에 없는 데이터를 찾는 쿼리를 실행하지 못했다. 최근 몇 시간치 데이터는 설계상 항상 메모리에 있어서 그 범위의 쿼리는 계속 성공했다. 실패한 쿼리는 가장 많을 때 20%였고, 오류율은 아주 천천히 올라갔다.
Cassandra 를 되살린 뒤에도 Metrictank 인스턴스는 하나도 새 클러스터에 다시 연결하지 못했다. Metrictank 에 설정된 서비스 호스트 이름은 맞았지만, Metrictank 가 그 이름을 다시 조회해 새 IP 를 얻지 않았다.
원인 ? 클라우드 제공자 장애
팀은 Metrictank 쓰기 인스턴스가 쓰기 큐를 비우지 못한다는 알림을 받고 장애를 알았다. Metrictank 가 대부분의 쿼리를 메모리에서 계속 처리해서 오류율은 아주 천천히 올라갔기 때문에, 이 알림이 없었다면 발견이 훨씬 늦었을 것이다.
받은 데이터를 처리하기 전에 쓰기 선행 로그인 Kafka 에 먼저 저장해 둔 덕분에, Cassandra 를 되살린 뒤 그동안 받은 데이터를 모두 처리해 저장할 수 있었다. Kafka 가 SSD 가 아닌 디스크를 쓴 것은 운이 좋았다. 그렇지 않았다면 Kafka 도 Cassandra 와 같은 장애를 겪었을 수 있다. 23시간 동안 파라과이, 알바니아, 호주에 있는 세 사람이 시간대를 나눠 대응했다. 두 버그를 고친 지금은 같은 상황이 와도 복구가 23시간이 아니라 3시간 안에 끝날 것으로 본다. 오래 미룬 문제도 새로 보면 생각보다 간단히 풀릴 수 있다. 장애가 주말에 나서 고객 부하가 대부분 캐시 데이터를 읽는 알림 쿼리뿐이었던 것도 운이 좋았다.
같은 원인 · 공통 애플리케이션 데이터베이스
같은 원인 · 공통 애플리케이션 데이터베이스
같은 원인 · 공통 애플리케이션 데이터베이스