왜 RBD 지연이 문제가 되는가

Ceph RBD는 여러 OSD에 객체를 분산 저장하기 때문에, 단일 쓰기 요청도 프라이머리 OSD와 레플리카 OSD들의 응답을 모두 기다려야 완료된다. 이 구조에서 평균 IOPS는 정상인데 p99 지연이 튀는 현상이 흔하다. 원인은 대개 한두 개의 느린 OSD(slow OSD), fsync 병목, 혹은 저널/WAL 위치 문제다. 평균값만 보면 절대 안 잡히고, 꼬리 지연(tail latency)을 봐야 한다.

먼저 계층별로 지연을 분리한다

튜닝 전에 "어디서 느린가"를 반드시 나눠야 한다. 클라이언트(QEMU/krbd) → 네트워크 → 프라이머리 OSD → 레플리카 순으로 계층이 있고, 각 계층의 관측 지점이 다르다. 클러스터 관점에서는 OSD별 op 지연을, 클라이언트 관점에서는 실제 블록 지연을 측정한다.

# OSD별 요청 지연 히스토그램 (프라이머리 관점)
ceph daemon osd.3 perf dump | jq '.osd | {
  op_latency: .op_latency,
  op_w_latency: .op_w_latency,
  subop_latency: .subop_latency
}'

# 느린 요청이 있는지 즉시 확인
ceph daemon osd.3 dump_historic_ops | jq '.ops[] | {duration, description}' | sort -rn | head

# 클러스터 전체에서 blocked ops 감시
ceph health detail | grep -i slow

op_w_latency가 높은데 subop_latency가 낮으면 로컬 디스크(BlueStore) 문제이고, subop_latency가 높으면 레플리카나 네트워크가 범인이다. 이 한 줄 분기가 진단 시간을 크게 줄인다.

클라이언트 측 실측: fio로 재현하기

운영 워크로드를 그대로 재현하려면 큐 깊이와 블록 크기를 실제와 맞춰야 한다. 특히 iodepth=1 동기 쓰기는 순수 왕복 지연을, 높은 iodepth는 처리량 한계를 드러낸다.

# 최악의 지연 시나리오: 4K 동기 랜덤 쓰기, 큐깊이 1
fio --name=rbd-lat --ioengine=rbd --pool=rbd --rbdname=testvol \
    --rw=randwrite --bs=4k --iodepth=1 --numjobs=1 \
    --direct=1 --runtime=60 --time_based \
    --percentile_list=50:95:99:99.9

# 결과 해석: clat p99.9가 p50의 10배 이상이면 tail latency 문제

BlueStore와 WAL/DB 배치 튜닝

가장 효과가 큰 튜닝은 block.db와 block.wal을 고속 장치(NVMe)로 분리하는 것이다. HDD OSD의 메타데이터와 WAL이 같은 스핀들에 있으면 랜덤 쓰기가 순차 처리량을 잡아먹는다. 아래는 배치에 따른 특성이다.

구성4K 랜덤쓰기 지연비용/복잡도
HDD 단독 (WAL/DB 동거)매우 높음, 편차 큼낮음
HDD + NVMe WAL/DB중간, 안정적중간
All-NVMe OSD낮음, 예측 가능높음

DB 크기는 데이터 용량의 약 1~4%를 확보한다. 너무 작으면 spillover가 나서 메타데이터가 다시 느린 장치로 흘러 지연이 튄다. ceph daemon osd.N perf dump | jq '.bluefs.slow_used_bytes'가 0이 아니면 spillover가 발생 중이다.

OSD 스케줄러와 mClock 조정

최근 버전은 mClock 스케줄러가 기본이다. 복구(recovery) 트래픽이 클라이언트 IO 지연을 밀어낼 때, 프로파일을 조정해 클라이언트를 보호한다.

# 클라이언트 IO 우선 보호
ceph config set osd osd_mclock_profile high_client_ops

# 스크럽으로 인한 지연 스파이크 완화
ceph config set osd osd_scrub_sleep 0.1
ceph config set osd osd_max_scrubs 1
ceph config set osd osd_scrub_begin_hour 1
ceph config set osd osd_scrub_end_hour 6

클라이언트 캐시와 krbd 옵션

QEMU 기반 VM은 rbd cache를 켜면 순차 쓰기 병합으로 지연이 개선되지만, writeback 모드는 flush 보장이 필요한 워크로드에서 데이터 정합성 위험이 있다. DB처럼 fsync가 잦은 워크로드는 캐시 이득이 적으므로 writethrough나 캐시 비활성이 더 예측 가능하다. krbd(커널 매핑)는 유저스페이스 librbd보다 CPU 오버헤드가 낮아 고IOPS 베어메탈에서 유리하다.

주의점

튜닝은 반드시 한 번에 하나씩, 실측 지표와 함께 바꾼다. 특히 osd_scrub_sleep을 과하게 키우면 스크럽이 밀려 데이터 무결성 검증 주기가 위험할 만큼 길어진다. mClock 프로파일 변경은 복구 속도와 트레이드오프이므로, 장애 상황에서 복구가 느려져 축소된 리던던시 상태가 길어질 수 있다는 점을 감안해야 한다. 그리고 단 하나의 느린 디스크가 전체 p99를 지배하는 경우가 많으니, 튜닝보다 먼저 dump_historic_ops로 특정 OSD를 격리·교체하는 편이 빠른 해결책일 때가 많다.