문제 노드 찾기

문제 노드 찾기 (Find The Misbehaving Nodes)

Cassandra 문제를 해결하는 첫 단계는 오류 메시지·메트릭·모니터링 정보를 활용해, 문제가 클라이언트 쪽인지 서버 쪽인지, 그리고 서버 쪽이라면 Cassandra 클러스터의 어느 노드가 문제인지 식별하는 것이에요. 목표는 이것이 전체적인(systemic) 문제인지(예: 클러스터 전체에 영향을 주는 쿼리 패턴) 아니면 일부 노드에 국한된 문제인지(예: 공유 토큰 범위를 가진 이웃 노드들, 또는 하드웨어가 고장 난 단일 노드)를 판별하는 것입니다.

문제가 어디에 있는지 파악하는 데 도움이 되는 정보 소스는 많습니다. 가장 흔한 몇 가지를 아래에서 다루겠습니다.

출처: 문제 노드 찾기 (Find The Misbehaving Nodes)

본문

클라이언트 로그와 오류

클러스터의 클라이언트는 추적하기 가장 좋은 단서를 남기는 경우가 많아요. 예를 들어 특정 데이터센터에서 클라이언트 지연 시간이나 오류율이 증가했다면(다른 데이터센터의 노드 가능성은 배제됨), 또는 클라이언트가 특정 종류의 오류 코드를 받고 있다면 특정 종류의 문제를 나타냅니다. 문제 해결자는 오류 메시지를 읽는 것만으로도 많은 실패 원인을 배제할 수 있어요. 실제로 많은 Cassandra 오류 메시지는 마지막으로 접촉한 코디네이터(coordinator)를 포함하고 있어, 운영자가 어느 노드부터 조사할지 시작점을 잡는 데 도움이 됩니다.

클라이언트가 Datastax의 drivers와 유사한 오류 이름을 가진다고 가정할 때, 몇 가지 흔한 오류(괄호 안은 주요 원인)는 다음과 같아요.

  • SyntaxError (client). 이 오류와 다른 QueryValidationException 계열은 클라이언트가 잘못된 형식의 요청을 보냈음을 나타내요. 이것은 거의 서버 문제가 아니며, 보통 잘못된 쿼리를 의미합니다.

  • UnavailableException (server): Cassandra 코디네이터 노드가 사용 가능한 복제본 노드가 충분하지 않다고 판단해 쿼리를 거부했음을 의미해요. 많은 코디네이터가 이 오류를 던진다면 클러스터에 (보통) 여러 노드가 실제로 다운되어 있을 가능성이 높으며, nodetool status로 해당 노드들을 식별할 수 있습니다. 단 하나의 코디네이터만 이 오류를 던진다면, 그 노드가 나머지와 파티션(격리)되었음을 의미할 수 있어요.

  • OperationTimedOutException (server): 클라이언트가 타임아웃을 설정했을 때 가장 자주 발생하는 타임아웃 메시지로, 쿼리가 지정한 타임아웃보다 오래 걸렸다는 뜻이에요. 이것은 클라이언트 쪽 타임아웃으로, 클라이언트가 지정한 타임아웃보다 오래 걸렸다는 의미입니다. 오류 메시지에는 마지막으로 시도한 코디네이터 노드가 포함되어 있으며, 보통 좋은 시작점이 됩니다. 이 오류는 보통 공격적인 클라이언트 타임아웃 값이나 느린 서버 코디네이터/복제본을 의미해요.

  • ReadTimeoutException 또는 WriteTimeoutException (server): 이 오류는 클라이언트가 더 낮은 타임아웃을 지정하지 않았을 때 발생하며, cassandra.yaml 설정 파일에 지정된 값에 기반한 코디네이터 타임아웃입니다. 기본값이 보통 수 초이므로, 이 오류는 대개 심각한 서버 쪽 문제를 나타내요.

메트릭

Cassandra를 GraphiteGrafana 같은 중앙 집중형 시스템으로 메트릭을 보고하고 있다면, 이를 활용해 문제를 좁혀 나갈 수 있습니다. 이 단계에서는 문제를 특정 데이터센터, 랙, 또는 노드 그룹으로 좁히는 것이 주된 목표예요. 살펴볼 만한 유용한 메트릭은 다음과 같습니다.

오류

Cassandra는 노드 간 메시징 오류를 "드롭(drops)"이라고 부르며, 오류를 좁히는 데 도움이 되는 다양한 Dropped Message Metrics를 제공합니다. 특정 노드가 메시지를 활발히 드롭하고 있다면, 그 노드가 문제와 관련되어 있을 가능성이 높아요.

지연 시간

타임아웃이나 지연 관련 문제는 table metrics로 시작해 보세요. 코디네이터 레벨 메트릭(예: CoordinatorReadLatency, CoordinatorWriteLatency)과 그에 대응하는 복제본 메트릭(예: ReadLatency, WriteLatency)을 비교하는 방식입니다. 문제는 보통 mean이나 50th 백분위수보다 99th 백분위수에 먼저 나타나요. 코디네이터의 maximum 지연은 내부적으로 사용하는 지수 감소 저장소(reservoir) 때문에 그다지 유용하지 않지만, 코디네이터의 99th 백분위수 상승과 상관관계가 있는 복제본의 maximum 지연은 문제를 좁히는 데 도움이 됩니다.

보통 세 가지 주요 가능성이 있습니다.

  • 모든 노드에서 코디네이터 지연은 높지만, 몇몇 노드의 로컬 읽기 지연만 높은 경우. 이것은 느린 복제본 노드를 가리키며, 코디네이터의 지연은 그저 부수효과입니다. 이는 보통 클라이언트가 토큰 인지(token aware)가 아닐 때 발생해요.

  • 몇몇 노드에서 코디네이터 지연과 복제본 지연이 동시에 증가하는 경우. 클라이언트가 토큰 인지라면 거의 항상 이렇게 되며, 일부 토큰 범위(링의 일부)의 복제본이 느리다는 것을 가리킵니다.

  • 많은 노드에서 코디네이터 지연과 로컬 지연이 모두 높은 경우. 보통 클러스터 용량의 임계점(초당 너무 많은 쓰기/읽기)에 도달했거나, 새로운 쿼리 패턴이 나타났음을 의미해요.

중요한 점은, 클라이언트의 로드 밸런싱 동작과 일관성 레벨에 따라 코디네이터와 복제본 메트릭이 상관관계를 가질 수도, 아닐 수도 있다는 것입니다. 특히 TokenAware 정책을 사용하면 같은 노드의 코디네이터 지연과 복제본 지연이 함께 증가하는 경우가 많지만, 일반 DCAwareRoundRobin만 사용하면 서로 관련 없는 복제본 노드의 지연과 함께 코디네이터 지연이 증가할 수 있어요. 예를 들어:

  • TokenAware + LOCAL_ONE: 같은 노드의 코디네이터 지연과 복제본 지연이 항상 함께 상승해야 합니다
  • TokenAware + LOCAL_QUORUM: 같은 데이터센터의 코디네이터 지연과 여러 복제본 지연이 항상 함께 상승해야 합니다
  • TokenAware + QUORUM: 다른 데이터센터의 복제본 지연이 코디네이터 지연에 영향을 줄 수 있어요
  • DCAwareRoundRobin + LOCAL_ONE: 코디네이터 지연과 무관한 복제본 노드의 지연이 함께 상승합니다
  • DCAwareRoundRobin + LOCAL_QUORUM: 서로 다른 코디네이터와 복제본 지연이 상관관계가 거의 없이 함께 상승합니다

쿼리 처리율

때로는 table metric의 쿼리 처리율 메트릭이 부하 문제를 좁히는 데 도움이 될 수 있어요. 코디네이터의 초당 쿼리 수(QPS)가 "작게" 증가해도 복제본 레벨 QPS는 아주 크게 증가할 수 있기 때문입니다. 이는 BATCH 쓰기에서 가장 흔하게 발생하는데, 클라이언트가 50개의 스테이트먼트를 포함한 단일 BATCH 쿼리를 보내고 그것을 9개 복사본(RF=3, 데이터센터 3개)이 처리한다면, 모든 코디네이터 BATCH 쓰기가 450개의 복제본 쓰기로 바뀌기 때문이에요! 그래서 BATCH를 같은 파티션에 유지하는 것이 그토록 중요한 것이며, 그렇지 않으면 "단일" 쿼리로 상당한 CPU 용량을 소진할 수 있습니다.

다음 단계: 노드 조사

문제를 최대한 좁혔다면(데이터센터, 랙, 노드), SSH로 그중 한 노드에 로그인해 logs, nodetool, os tools를 사용해 디버깅을 진행하세요. 로그인할 수 없더라도 logsnodetool에는 원격으로 접근할 수 있을 수 있어요.

더 알아보기 (Learn more)