What to index and what to leave in the body
한국어 원문으로 표시합니다.
목표
로그 저장소가 느려지거나 비싸지는 이유는 거의 언제나 무엇을 색인할지 잘못 골랐기 때문입니다. 그 결정은 데이터가 쌓인 뒤에 되돌리기가 아주 어렵습니다.
여기서는 실제 로그를 세어 보고 숫자로 정합니다.
재료
/opt/lab/logidx/events.jsonl 로그 2만 줄 (약 4MB)
mkdir -p /root/logidx && cp /opt/lab/logidx/* /root/logidx/ && cd /root/logidx
head -1 events.jsonl | python3 -m json.tool
남길 것
01-cardinality.txt 필드마다 값이 몇 가지인가
02-labels.txt 라벨과 본문을 가른 결과
03-explode.txt 라벨 하나를 더하면 스트림이 몇 개가 되나
04-shards.txt 샤드 수
05-tiers.txt 보관 단계와 기간
06-cost.txt 색인과 검색의 비용
07-notes.md 왜 그런지
먼저 세어 본다
각 필드(service level env pod route request_id user_id)가 서로 다른 값을 몇 가지 갖는지 세어 01-cardinality.txt 에 적고, 높은 것과 낮은 것을 갈라 표시하세요.
python3 - <<'PY'
import json
rows = [json.loads(l) for l in open('events.jsonl')]
for k in ('service','level','env','pod','route','request_id','user_id'):
print(k, len({r[k] for r in rows}))
PY
두 자리 이하와 만 단위가 섞여 있을 겁니다. 그 차이가 그대로 비용의 차이가 됩니다.
라벨과 본문을 가른다
라벨로 둘 것과 본문에 둘 것을 갈라 02-labels.txt 에 적으세요. 라벨로 고른 것들의 조합 수도 함께 계산합니다.
라벨은 곧 스트림(또는 시계열)입니다. 조합 수가 그대로 개수가 됩니다.
service · level · env 셋이면 5 × 3 × 2 이지만, 실제로 나타나는 조합만 세면 그보다 작을 수도 있습니다. 실제 데이터로 세어 보세요.
높은 기수 필드는 본문에 둡니다. 그러면 라벨로 먼저 좁힌 뒤 그 안에서 찾게 되고, 그것이 이런 저장소의 설계 의도입니다.
하나만 더해 본다
라벨 셋에 pod · route · request_id · user_id 를 각각 하나씩 더했을 때 조합 수가 얼마가 되는지 03-explode.txt 에 적고, pod 하나로 몇 배가 되는지 적으세요.
네 번 계산해서 견줍니다. pod 는 서비스마다 여섯이니 곱해집니다.
"이 라벨 하나만 있으면 편한데" 가 사고의 시작입니다. 편의는 한 사람의 것이고 비용은 클러스터 전체의 것입니다.
샤드를 몇 개로 나눌 것인가
이 로그가 초당 500줄 들어온다고 보고 하루치 저장량과 샤드 수를 04-shards.txt 에 계산하세요. 목표 샤드 크기를 정하고, 하루치가 그보다 작으면 어떻게 할지도 적습니다.
한 줄의 크기는 파일 크기 ÷ 줄 수로 구합니다.
샤드 하나에 10~50GB 를 목표로 잡습니다. 작은 샤드가 수천 개면 메모리와 파일 핸들을 그만큼 먹고 클러스터가 느려집니다.
하루치가 목표보다 작으면 날짜별 대신 주별로 만들거나 롤오버 조건(크기 기준)에 맡깁니다.
언제 무엇을 버릴 것인가
hot · warm · cold · delete 네 단계의 기간을 정하고, 각 단계에 얼마가 쌓이는지 05-tiers.txt 에 계산하세요. warm 이나 cold 에서 무엇이 달라지는지도 적습니다.
hot 은 쓰기와 검색이 모두 일어나고, warm 은 읽기 전용이라 세그먼트를 합치고 복제본을 줄일 수 있습니다. cold 는 느린 저장소나 객체 스토리지로 옮깁니다.
정하지 않으면 어느 날 디스크가 차고, 그때는 급하게 지우느라 필요한 것까지 지웁니다.
비용은 어디서 나는가
색인 쪽 비용과 검색 쪽 비용을 갈라 06-cost.txt 에 적고, 색인 비용을 줄이는 방법과 검색하지 않는 필드를 어떻게 다룰지를 함께 쓰세요.
초당 문서 수가 곧 CPU 입니다. 디버그 수준 로그를 운영에서 그대로 보내면 그 비용을 매일 냅니다.
검색은 안 하고 보기만 하는 필드는 index: false 로 두면 색인 비용과 저장 공간이 줍니다. 반대로 집계만 하는 숫자는 doc_values 만 있으면 됩니다.
정상 요청은 추적으로 대신하고 로그는 이상한 경우에만 남기는 쪽으로 옮기는 것도 방법입니다.
다음에 읽을 사람에게
여기서 본 것 중 넷 이상을 골라 07-notes.md 에 정리하세요. 무엇을 했는지가 아니라 왜 그런지를 적습니다.
새 필드를 라벨에 넣을지 고민하는 자신이 읽는다고 생각하세요. "카디널리티를 셌다" 는 도움이 안 되고, "pod 를 라벨에 넣으면 스트림이 여섯 배가 된다 — 편의는 한 사람의 것이고 비용은 클러스터 전체의 것이다" 는 도움이 됩니다.