nodetool 사용하기
nodetool 사용하기 (Use Nodetool)
Cassandra의 nodetool은 문제를 클러스터에서 특정 노드로 좁히고, Cassandra 프로세스 자체의 상태에 대한 많은 통찰을 제공해요. 유용한 명령이 수십 가지가 있습니다(모든 명령은 nodetool help 참고). 그중 문제 해결에 가장 유용한 것들을 간단히 살펴보겠습니다.
본문
클러스터 상태
nodetool status로 클러스터의 상태를 파악할 수 있어요.
$ nodetool status <optional keyspace>
Datacenter: dc1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
UN 127.0.1.1 4.69 GiB 1 100.0% 35ea8c9f-b7a2-40a7-b9c5-0ee8b91fdd0e r1
UN 127.0.1.2 4.71 GiB 1 100.0% 752e278f-b7c5-4f58-974b-9328455af73f r2
UN 127.0.1.3 4.69 GiB 1 100.0% 9dc1a293-2cc0-40fa-a6fd-9e6054da04a7 r3
이 경우 한 데이터센터에 세 개의 노드가 있고, 각각 약 4.6GB의 데이터를 가지며 모두 "up" 상태입니다. 노드의 up/down 상태는 클러스터의 모든 노드가 각자 독립적으로 판단하므로, 전체 그림을 보려면 여러 노드에서 nodetool status를 실행해야 할 수 있어요.
nodetool status에 grep을 조금 더해 어느 노드가 down인지 확인할 수도 있습니다.
$ nodetool status | grep -v '^UN'
Datacenter: dc1
===============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
Datacenter: dc2
===============
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns (effective) Host ID Rack
DN 127.0.0.5 105.73 KiB 1 33.3% df303ac7-61de-46e9-ac79-6e630115fd75 r1
이 경우 두 개의 데이터센터가 있고 dc2의 r1 랙에 한 노드가 다운되어 있습니다. 이것은 127.0.0.5에 문제가 있을 수 있음을 시사하므로 조사가 필요합니다.
코디네이터 쿼리 지연
nodetool proxyhistograms로 코디네이터의 읽기·쓰기 지연 분포를 확인해 지연 문제를 좁힐 수 있어요.
$ nodetool proxyhistograms
Percentile Read Latency Write Latency Range Latency CAS Read Latency CAS Write Latency View Write Latency
(micros) (micros) (micros) (micros) (micros) (micros)
50% 454.83 219.34 0.00 0.00 0.00 0.00
75% 545.79 263.21 0.00 0.00 0.00 0.00
95% 654.95 315.85 0.00 0.00 0.00 0.00
98% 785.94 379.02 0.00 0.00 0.00 0.00
99% 3379.39 2346.80 0.00 0.00 0.00 0.00
Min 42.51 105.78 0.00 0.00 0.00 0.00
Max 25109.16 43388.63 0.00 0.00 0.00 0.00
여기서 읽기, 쓰기, 범위 요청(예: select * from keyspace.table), CAS 읽기(CAS의 비교 단계), CAS 쓰기(비교·설정의 설정 단계)의 전체 지연 분포를 볼 수 있어요. 이는 상위 수준의 지연 문제를 좁히는 데 유용합니다. 예를 들어 클라이언트가 읽기 타임아웃을 20밀리초로 설정했다면, 이 노드에서 가끔 타임아웃을 경험할 수 있지만 1% 미만일 것입니다(99% 읽기 지연이 3.3밀리초로 20밀리초보다 작기 때문).
로컬 쿼리 지연
어느 테이블이 지연/오류 문제를 겪고 있는지 안다면, nodetool tablehistograms로 노드 로컬에서 무슨 일이 일어나고 있는지 더 잘 파악할 수 있어요.
$ nodetool tablehistograms keyspace table
Percentile SSTables Write Latency Read Latency Partition Size Cell Count
(micros) (micros) (bytes)
50% 0.00 73.46 182.79 17084 103
75% 1.00 88.15 315.85 17084 103
95% 2.00 126.93 545.79 17084 103
98% 2.00 152.32 654.95 17084 103
99% 2.00 182.79 785.94 17084 103
Min 0.00 42.51 24.60 14238 87
Max 2.00 12108.97 17436.92 17084 103
이 출력은 특히 중요한 메트릭의 백분위수 구간을 보여줍니다.
첫 번째 컬럼은 논리적 읽기당 읽힌 sstable 개수를 나타내요. 여기서 값이 매우 높다면 컴팩션 전략을 잘못 선택했을 수 있음을 의미합니다. 예를 들어 SizeTieredCompactionStrategy는 업데이트가 많은 워크로드에서 LeveledCompactionStrategy보다 읽기당 훨씬 많은 읽기를 수행하는 경우가 많습니다.
두 번째 컬럼은 로컬 쓰기 지연의 구간을 보여줘요. 여기서 p50은 73마이크로초로 꽤 좋지만 최대 지연은 12밀리초로 꽤 느린 것을 확인할 수 있습니다. 쓰기 최대 지연이 높은 것은 보통 느린 commitlog 볼륨(fsync가 느림)이나 commitlog 세그먼트를 빠르게 포화시키는 큰 쓰기를 나타냅니다.
세 번째 컬럼은 로컬 읽기 지연의 구간을 보여줘요. 로컬 Cassandra 읽기는 (예상대로) 로컬 쓰기보다 느리며, 읽기 속도는 읽기당 읽힌 sstable 개수와 높은 상관관계가 있음을 알 수 있습니다.
네 번째와 다섯 번째 컬럼은 파티션 크기와 파티션당 컬럼 수의 분포를 보여줘요. 이것은 테이블이 평균적으로 가느다란(skinny) 파티션인지 넓은(wide) 파티션인지 판단하고, 나쁜 데이터 패턴을 격리하는 데 유용합니다. 예를 들어 2메가바이트짜리 단일 셀이 있다면, 읽을 때 힙 압력을 일으킬 가능성이 높습니다.
스레드풀 상태
nodetool tpstats로 특정 노드의 현재 미처리 요청을 확인할 수 있어요. Cassandra 프로세스가 어느 리소스(읽기 스레드, 쓰기 스레드, 컴팩션, 요청 응답 스레드)가 부족한지 찾는 데 유용합니다. 예를 들어:
$ nodetool tpstats
Pool Name Active Pending Completed Blocked All time blocked
ReadStage 2 0 12 0 0
MiscStage 0 0 0 0 0
CompactionExecutor 0 0 1940 0 0
MutationStage 0 0 0 0 0
GossipStage 0 0 10293 0 0
Repair-Task 0 0 0 0 0
RequestResponseStage 0 0 16 0 0
ReadRepairStage 0 0 0 0 0
CounterMutationStage 0 0 0 0 0
MemtablePostFlush 0 0 83 0 0
ValidationExecutor 0 0 0 0 0
MemtableFlushWriter 0 0 30 0 0
ViewMutationStage 0 0 0 0 0
CacheCleanupExecutor 0 0 0 0 0
MemtableReclaimMemory 0 0 30 0 0
PendingRangeCalculator 0 0 11 0 0
SecondaryIndexManagement 0 0 0 0 0
HintsDispatcher 0 0 0 0 0
Native-Transport-Requests 0 0 192 0 0
MigrationStage 0 0 14 0 0
PerDiskMemtableFlushWriter_0 0 0 30 0 0
Sampler 0 0 0 0 0
ViewBuildExecutor 0 0 0 0 0
InternalResponseStage 0 0 0 0 0
AntiEntropyStage 0 0 0 0 0
Message type Dropped Latency waiting in queue (micros)
50% 95% 99% Max
READ 0 N/A N/A N/A N/A
RANGE_SLICE 0 0.00 0.00 0.00 0.00
_TRACE 0 N/A N/A N/A N/A
HINT 0 N/A N/A N/A N/A
MUTATION 0 N/A N/A N/A N/A
COUNTER_MUTATION 0 N/A N/A N/A N/A
BATCH_STORE 0 N/A N/A N/A N/A
BATCH_REMOVE 0 N/A N/A N/A N/A
REQUEST_RESPONSE 0 0.00 0.00 0.00 0.00
PAGED_RANGE 0 N/A N/A N/A N/A
READ_REPAIR 0 N/A N/A N/A N/A
이 명령은 여러 흥미로운 통계를 보여줘요. 첫 번째 섹션은 각 Cassandra 스테이지의 스레드풀 상세 구간을 보여주며, 현재 실행 중인 스레드 수(Active)와 실행을 기다리는 수(Pending)를 포함합니다. 보통 특정 스레드풀에서 미처리 실행을 보게 되면 그 유형의 작업에 국한된 문제가 있음을 나타냅니다. 예를 들어 RequestResponseStage 큐가 쌓이면 코디네이터들이 많은 다운스트림 복제본 요청을 기다리고 있다는 뜻이며, 토큰 인지(token awareness)가 부족하거나 읽기 요청에 매우 높은 일관성 레벨을 사용하고 있음을 의미할 수 있습니다(예: ALL로 읽으면 RF개의 RequestResponseStage 스레드를 점유하는 반면, LOCAL_ONE은 ReadStage 스레드풀의 단일 스레드만 사용합니다). 반면 컴팩션 미처리가 많다면 컴팩션 스레드가 쓰기 볼륨을 따라가지 못한다는 뜻일 수 있으며, 컴팩션 전략이나 concurrent_compactors, compaction_throughput 옵션을 튜닝해야 할 수 있습니다.
두 번째 섹션은 모든 주요 요청 유형에 대한 드롭(오류)과 지연 분포를 보여줘요. 드롭은 프로세스 시작 이후 누적되며, 드롭으로 간주되기 위한 기본 타임아웃이 상당히 높기 때문에(~5-10초) 어느 것이든 심각한 문제를 나타냅니다. 드롭된 메시지는 종종 추가 조사가 필요합니다.
컴팩션 상태
Cassandra는 LSM 데이터스토어이므로, 때때로 sstable을 함께 컴팩션해야 하며 이것이 성능에 부정적인 영향을 줄 수 있어요. 특히 컴팩션은 상당량의 CPU 리소스를 사용하고, OS 페이지 캐시의 큰 부분을 무효화하며, 디스크 드라이브에 많은 부하를 줄 수 있습니다. 이를 판단하는 훌륭한 os tools가 있지만, 먼저 nodetool compactionstats로 컴팩션이 실제로 실행 중인지 확인하는 것이 좋은 경우가 많습니다.
$ nodetool compactionstats
pending tasks: 2
- keyspace.table: 2
id compaction type keyspace table completed total unit progress
2062b290-7f3a-11e8-9358-cd941b956e60 Compaction keyspace table 21848273 97867583 bytes 22.32%
Active compaction remaining time : 0h00m04s
이 경우 keyspace.table 테이블에서 하나의 컴팩션이 실행 중이며, 97메가바이트 중 21.8메가바이트를 완료했고, Cassandra는 (설정된 컴팩션 처리량 기준으로) 4초가 걸릴 것으로 추정합니다. 단위를 사람이 읽기 쉬운 형식으로 보려면 -H를 넘길 수도 있어요.
일반적으로 실행 중인 컴팩션 하나당 코어 하나를 소비할 수 있지만, 병렬로 많이 할수록 데이터는 더 빨리 컴팩션됩니다. 컴팩션은 좋은 읽기 성능을 보장하는 데 매우 중요하므로, 컴팩션이 빠르게 완료되면서도 쿼리 스레드에서 리소스를 너무 많이 빼앗지 않도록 동시 컴팩션의 균형을 맞추는 것이 성능에 매우 중요합니다. 컴팩션이 따라잡지 못한다면 Cassandra의 concurrent_compactors나 compaction_throughput 옵션을 튜닝해 보세요.
데이터 파일에 사용되는 경로
Cassandra는 설정된 디렉토리에 데이터를 디스크에 영속화합니다. 데이터 파일은 data_file_directories로 설정된 디렉토리들에 분산됩니다. Cassandra는 키스페이스와 테이블의 구조를 반영해 data_file_directories 안에 하위 디렉토리를 만듭니다. 하지만 테이블과 키스페이스가 드롭되어도 디렉토리는 제거되지 않습니다. 이러한 디렉토리는 스냅샷을 보관하는 이유로 유지되지만, 제거 대상이 될 수 있습니다. 그래서 운영자는 어떤 디렉토리가 여전히 사용 중인지 알아야 해요. nodetool datapaths 명령을 실행하면 Cassandra가 실제로 어느 디렉토리에 sstable 데이터를 저장하고 있는지 나열하는 쉬운 방법입니다.
% nodetool datapaths -- system_auth
Keyspace: system_auth
Table: role_permissions
Paths:
/var/lib/cassandra/data/system_auth/role_permissions-3afbe79f219431a7add7f5ab90d8ec9c
Table: network_permissions
Paths:
/var/lib/cassandra/data/system_auth/network_permissions-d46780c22f1c3db9b4c1b8d9fbc0cc23
Table: resource_role_permissons_index
Paths:
/var/lib/cassandra/data/system_auth/resource_role_permissons_index-5f2fbdad91f13946bd25d5da3a5c35ec
Table: roles
Paths:
/var/lib/cassandra/data/system_auth/roles-5bc52802de2535edaeab188eecebb090
Table: role_members
Paths:
/var/lib/cassandra/data/system_auth/role_members-0ecdaa87f8fb3e6088d174fb36fe5c0d
기본적으로 모든 키스페이스와 테이블이 나열되지만, keyspace와 keyspace.table 인자 목록을 주어 특정 데이터 경로만 조회할 수 있어요. --format 옵션을 사용하면 출력을 YAML이나 JSON으로 서식화할 수 있습니다.