Kudu 용량 산정 문서에 "minimum 128MB per hot replica" 같은 표현이 나온다. 여기서 hot replica 는 장애 상태나 특별한 역할을 가리키는 말이 아니라 지금 계속 쓰기를 받고 있는 tablet replica 를 뜻한다.
| 용어 | 뜻 |
|---|---|
| tablet | 테이블을 수평으로 나눈 조각 |
| replica | tablet 의 복제본. 복제 계수 3이면 tablet 하나에 replica 3개 |
| hot replica | 현재 insert · update · delete 가 계속 들어오는 replica |
| cold replica | 쓰기는 거의 없고 읽기 위주인 replica |
시계열 테이블처럼 시간 기준 range 파티션을 쓰는 경우 가장 최근 파티션의 replica 들만 hot 이고 과거 파티션은 cold 다. 전체 replica 수가 많아도 hot 은 그중 일부다.
hot replica 가 메모리를 요구하는 이유는 쓰기 경로에 두 개의 인메모리 저장소가 있기 때문이다.
MemRowSet 은 새로 insert 된 행이 디스크로 flush 되기 전까지 쌓이는 영역이다. 일정 크기에 이르면 디스크로 내려가고 새 MemRowSet 이 만들어진다.
DeltaMemStore 는 이미 디스크에 내려간 행에 대한 update · delete 변경분을 담는 영역이다. Kudu 의 base data 파일은 사실상 불변이라 기존 행을 고칠 수 없고, 변경분을 따로 모았다가 나중에 병합한다.
용량 산정에서 hot replica 당 128MB 를 잡으라는 것은 이 둘의 합에 대한 최소 기준이다. insert 가 update 보다 훨씬 많은 일반적인 워크로드에서는 대부분이 MemRowSet 몫이고 DeltaMemStore 는 아주 작다.
Tablet Server 한 대에 hot replica 200개 → 200 × 128MB ≈ 25.6GB
여기에 블록 캐시, WAL 버퍼, 스캔 버퍼 등이 따로 붙으므로 실제 --memory_limit_hard_bytes 는 이보다 넉넉해야 한다.
전체 replica 수로 계산하면 필요 메모리가 과도하게 나온다. 몇 년치 파티션이 쌓인 테이블이라면 replica 수천 개 중 hot 은 수십 개일 수 있다. 현재 쓰기가 들어오는 파티션에 걸린 replica 수를 세는 것이 맞다.
반대로 파티션 설계가 잘못되면 hot replica 가 한쪽에 몰린다. 시간 기준 range 파티션만 쓰고 hash 파티션을 두지 않으면 최신 파티션의 tablet 몇 개에 모든 쓰기가 집중되어, 그 tablet 을 가진 Tablet Server 만 메모리와 CPU 를 쓰고 나머지는 논다. 시계열 테이블에서는 range(시간) + hash(키) 를 함께 쓰는 것이 기본이다.
쓰기가 몰리는 tablet 을 찾으려면 Tablet Server 웹 UI 의 tablet 목록에서 MemRowSet 크기를 보거나 지표를 본다.
curl -s http://<tserver>:8050/metrics | \
python3 -c "import sys,json; [print(m['id'], [x for x in m['metrics'] if x['name'] in ('memrowset_size','on_disk_size')]) for m in json.load(sys.stdin) if m['type']=='tablet']" | head
클러스터 전체 상태와 tablet 분포는 ksck 로 본다.
kudu cluster ksck <master-addresses>
memory_limit_hard_bytes 등 메모리 관련 플래그.