LabHub
배우기 러닝패스 코스

Loki — ログを索引しないログストア

要求した途端に画面から消えたのに、保存容量は一か月そのままだった

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

보존을 켜고 스트림마다 다른 기간을 거는 설정을 직접 써서 검증하고, 그 설정으로 두 번째 Loki 를 띄운 뒤 삭제 요청을 넣어 접수와 실제 삭제 사이의 시간 간격을 숫자로 확인합니다.

왜 중요한가

Loki 는 보존을 꺼 둔 채로 출발한다. 아무도 켜지 않으면 넣은 로그는 영원히 남고, 청구서가 네 배가 된 뒤에야 그 사실을 알게 된다. 삭제 요청도 마찬가지로 두 겹이다 — 기본 방식에서는 요청이 접수되는 즉시 질의가 그 줄을 걸러 주지만, 저장된 객체에서 실제로 지워지는 것은 취소 대기 기간이 지난 뒤 컴팩터의 몫이다. '안 보인다' 를 '지워졌다' 로 읽으면 규제 대응 보고서가 틀리게 되고 용량 계획도 어긋난다. 보존 기간을 정하는 일은 추정이 아니라 실측에서 출발해야 한다 — 질의 응답에 실려 오는 바이트 수가 그 출발점이다.

단계

  1. /root/lk-retention 에서 Loki 를 띄우고 date +%s/root/lk-retention/anchor.txt 에 적은 뒤 python3 /opt/lab/d5/gen.py retention "$(cat anchor.txt)" 로 자료를 넣으세요. 그리고 auditdebug 두 스트림을 한 시간 구간으로 각각 질의해 응답 통계의 읽은 바이트를 /root/lk-retention/01-bytes.txtaudit_bytes=<정수>debug_bytes=<정수> 두 줄로 적으세요.
  2. 1단계의 한 시간치 바이트에서 스트림별 저장량을 계산해 /root/lk-retention/budget.tsv 를 만드세요. 머리글 없이 두 줄이고 각 줄은 탭으로 나눈 네 칸 <스트림><탭><한시간바이트><탭><보존일수><탭><보존기간총바이트> 입니다. 스트림은 순서대로 audit, debug 이고 보존 일수는 각각 3651 로 잡습니다. 총바이트는 한시간바이트 × 24 × 보존일수 입니다.
  3. /root/lk-retention/loki-ret.yaml 을 쓰세요. 지금 쓰는 loki.yaml 을 바탕으로 하되 다음을 더합니다 — server.http_listen_port3200, server.grpc_listen_port9096, 저장 경로는 /tmp/lokiret 아래, compactor.retention_enabledtrue, compactor.delete_request_storefilesystem, compactor.working_directory 지정, limits_config.retention_period720h. 그리고 loki -config.file=/root/lk-retention/loki-ret.yaml -verify-config 가 아무 오류 없이 끝나야 합니다.
  4. /root/lk-retention/loki-ret.yamllimits_configretention_stream 목록을 더해 {app="debug"}24h, {app="audit"}8760h 로 보존되게 하세요. 우선순위는 각각 12 로 명시합니다. 그리고 /root/lk-retention/04-rules.txt 에 두 줄을 적으세요 — rules=<규칙 개수>verify=ok(-verify-config 가 통과했을 때).
  5. /root/lk-retention/loki-ret.yaml 로 두 번째 Loki 를 띄우고 http://localhost:3200/readyready 를 돌려줄 때까지 기다리세요. 그리고 그 서버의 /config 에서 세 값을 읽어 /root/lk-retention/05-run.txt 에 적습니다 — retention_enabled=<값>, retention_period=<값>, compaction_interval=<값>.
  6. 3200 포트의 Loki 에 줄을 몇 개 넣고, 그중 한 스트림의 한 구간을 지워 달라고 요청하세요. 요청은 POST /loki/api/v1/deletequery·start·end 를 줍니다. 그리고 /root/lk-retention/06-delete.txt 에 세 줄을 적으세요 — post_code=<HTTP 상태 코드>, requests=<목록에 있는 요청 수>, status=<그 요청의 status 값>.
  7. 삭제를 요청한 그 구간을 다시 질의해 지금 몇 줄이 나오는지 세고, 실제 삭제가 언제 일어나는지를 서버 설정에서 찾아 확인하세요. /root/lk-retention/07-async.txt 에 네 줄을 적습니다 — still_visible=<정수>, mode=<deletion_mode 값>, param=<실제 삭제까지 기다리는 시간을 정하는 설정 이름>, value=<서버가 찍은 값 그대로>.
  8. /root/lk-retention/policy.txt 에 다섯 줄을 적으세요 — audit_period=, debug_period=(둘 다 설정에 쓴 값 그대로), audit_bytes_total=, debug_bytes_total=(2단계 표의 마지막 칸), note=(공백 뺀 60자 이상, 왜 두 기간을 다르게 잡았는지와 삭제 요청이 즉시 반영되지 않는다는 사실을 함께 적습니다).

참고

두 종류의 로그를 넣고 실제 바이트를 잰다

/root/lk-retention 에서 Loki 를 띄우고 date +%s/root/lk-retention/anchor.txt 에 적은 뒤 python3 /opt/lab/d5/gen.py retention "$(cat anchor.txt)" 로 자료를 넣으세요. 그리고 auditdebug 두 스트림을 한 시간 구간으로 각각 질의해 응답 통계의 읽은 바이트를 /root/lk-retention/01-bytes.txtaudit_bytes=<정수>debug_bytes=<정수> 두 줄로 적으세요.

통계는 query_range 응답의 data.stats.summary.totalBytesProcessed 입니다. 두 스트림의 성격이 다릅니다 — 하나는 드물게 쌓이는 감사 기록, 하나는 초당 여러 줄씩 쏟아지는 디버그 로그입니다. 용량 계획은 이 차이에서 시작합니다.

실측에서 보존 예산을 계산한다

1단계의 한 시간치 바이트에서 스트림별 저장량을 계산해 /root/lk-retention/budget.tsv 를 만드세요. 머리글 없이 두 줄이고 각 줄은 탭으로 나눈 네 칸 <스트림><탭><한시간바이트><탭><보존일수><탭><보존기간총바이트> 입니다. 스트림은 순서대로 audit, debug 이고 보존 일수는 각각 3651 로 잡습니다. 총바이트는 한시간바이트 × 24 × 보존일수 입니다.

이 계산의 요점은 두 줄의 마지막 칸을 나란히 놓고 보는 것입니다. 줄 수가 열 배 많은 쪽이 보존 기간이 짧으면 총량이 뒤집힐 수 있습니다 — 그 역전이 보존 정책을 스트림별로 가르는 이유입니다.

보존을 켜는 설정을 쓰고 검증한다

/root/lk-retention/loki-ret.yaml 을 쓰세요. 지금 쓰는 loki.yaml 을 바탕으로 하되 다음을 더합니다 — server.http_listen_port3200, server.grpc_listen_port9096, 저장 경로는 /tmp/lokiret 아래, compactor.retention_enabledtrue, compactor.delete_request_storefilesystem, compactor.working_directory 지정, limits_config.retention_period720h. 그리고 loki -config.file=/root/lk-retention/loki-ret.yaml -verify-config 가 아무 오류 없이 끝나야 합니다.

-verify-config 는 문법뿐 아니라 설정 조합이 말이 되는지도 봅니다 — 통과하면 출력이 없습니다. 포트를 둘 다 바꾸는 이유는 다음 단계에서 드러납니다. 저장 경로를 안 바꾸면 지금 도는 Loki 와 같은 디렉터리를 두 프로세스가 쓰게 됩니다.

스트림마다 다른 보존 기간

/root/lk-retention/loki-ret.yamllimits_configretention_stream 목록을 더해 {app="debug"}24h, {app="audit"}8760h 로 보존되게 하세요. 우선순위는 각각 12 로 명시합니다. 그리고 /root/lk-retention/04-rules.txt 에 두 줄을 적으세요 — rules=<규칙 개수>verify=ok(-verify-config 가 통과했을 때).

retention_streamselector·priority·period 세 칸을 가진 항목의 목록입니다. 선택자는 LogQL 스트림 선택자 문법 그대로이고 따옴표 안에 넣습니다. 우선순위를 안 적으면 겹치는 규칙에서 어느 쪽이 이길지 예측하기 어려워집니다.

두 번째 Loki 를 띄운다 — 포트는 두 개다

/root/lk-retention/loki-ret.yaml 로 두 번째 Loki 를 띄우고 http://localhost:3200/readyready 를 돌려줄 때까지 기다리세요. 그리고 그 서버의 /config 에서 세 값을 읽어 /root/lk-retention/05-run.txt 에 적습니다 — retention_enabled=<값>, retention_period=<값>, compaction_interval=<값>.

로그는 파일로 남기세요(> ret.log 2>&1). 만약 바로 죽는다면 그 파일의 마지막 줄을 보세요 — 포트 하나만 바꿨을 때 나는 오류가 거기 그대로 적혀 있습니다. /ready 는 20초쯤 걸리니 고정 sleep 대신 조건을 보는 반복문을 쓰세요.

삭제 요청을 넣고 목록을 본다

3200 포트의 Loki 에 줄을 몇 개 넣고, 그중 한 스트림의 한 구간을 지워 달라고 요청하세요. 요청은 POST /loki/api/v1/deletequery·start·end 를 줍니다. 그리고 /root/lk-retention/06-delete.txt 에 세 줄을 적으세요 — post_code=<HTTP 상태 코드>, requests=<목록에 있는 요청 수>, status=<그 요청의 status 값>.

구간은 초 단위 정수로 줍니다(나노초가 아닙니다). 목록은 같은 경로에 GET 으로 묻습니다. 요청이 400 으로 거부되면 delete_request_store 가 설정돼 있는지, 구간이 거꾸로 되어 있지 않은지 보세요.

응용 ① — 안 보이는 것과 지워진 것은 다르다

삭제를 요청한 그 구간을 다시 질의해 지금 몇 줄이 나오는지 세고, 실제 삭제가 언제 일어나는지를 서버 설정에서 찾아 확인하세요. /root/lk-retention/07-async.txt 에 네 줄을 적습니다 — still_visible=<정수>, mode=<deletion_mode 값>, param=<실제 삭제까지 기다리는 시간을 정하는 설정 이름>, value=<서버가 찍은 값 그대로>.

조회 결과가 0 이라고 저장소에서 지워진 것은 아닙니다. /config 에서 삭제 방식을 뜻하는 설정과, compactor: 블록의 '요청을 취소할 수 있는 기간' 을 찾아 보세요. 두 값을 나란히 놓으면 '왜 용량이 안 줄어드는가' 의 답이 나옵니다.

응용 ② — 보존 정책을 문서로 못박는다

/root/lk-retention/policy.txt 에 다섯 줄을 적으세요 — audit_period=, debug_period=(둘 다 설정에 쓴 값 그대로), audit_bytes_total=, debug_bytes_total=(2단계 표의 마지막 칸), note=(공백 뺀 60자 이상, 왜 두 기간을 다르게 잡았는지와 삭제 요청이 즉시 반영되지 않는다는 사실을 함께 적습니다).

정책 문서의 값이 설정 파일과 어긋나면 그 문서는 없는 것보다 나쁩니다. 설정에서 그대로 가져오세요. 마지막 줄은 다음에 이 클러스터를 맡을 사람이 읽을 문장입니다 — 숫자의 근거와 시간 지연을 함께 적어 두면 같은 질문을 두 번 받지 않습니다.