LabHub
배우기 러닝패스 코스

Loki — 로그를 색인하지 않는 로그 저장소 · 한도와 잘린 답 · 이론

조용히 잘리는 답이 제일 위험하다

LabHub 에서 이어서 보기

한 줄 요약

limit 은 답을 조용히 자르고, 서버 한도는 질의를 400 으로 거절한다. 사고 조사를 망치는 쪽은 언제나 조용한 쪽이다.

왜 이게 필요했나

사고 원인을 찾던 사람이 {app="gateway"} |= "timeout" 을 두 시간 구간으로 던졌다. 결과는 1000줄이었고, 가장 이른 줄의 시각을 사고 시작으로 보고했다. 나중에 보니 실제 시작은 그보다 40분 앞이었다.

limit 의 기본값이 1000 이었고 방향이 backward 였다. 즉 가장 최근 1000줄만 돌아왔고, 그보다 앞의 줄은 화면에 나타나지 않았다. 응답 어디에도 "잘렸다" 는 표시가 없었다. 돌려받은 줄 수가 정확히 limit 과 같다는 것 하나가 유일한 단서였다.

어떻게 동작하나

로그 질의의 결과 수를 정하는 것은 세 가지다.

| 손잡이 | 성격 | 넘으면 |
| --- | --- | --- |
| 요청의 limit | 클라이언트가 고른다 | 조용히 잘린다 |
| limits_config.max_entries_limit_per_query | 서버가 정한 상한 | 400 으로 거절 |
| limits_config.max_query_length | 구간 길이 상한 | 400 으로 거절 |

direction무엇이 잘려 나가는지를 정한다. backward(기본)는 최근부터 채우므로 오래된 줄이 잘리고, forward 는 반대다. 사고의 시작을 찾을 때 기본값을 그대로 쓰면 정확히 찾고 싶은 것이 잘려 나간다.

limit 이 조용히 자르는 자리. direction=backward 는 최근 줄부터 채우므로 구간 앞쪽이 잘려 실제 사고 시작보다 40분 늦은 시각을 보고하게 되고, direction=forward 로 바꾸면 반대쪽부터 채워 사고의 시작이 결과 안에 들어온다

질의는 또 split_queries_by_interval 에 따라 시간 조각으로 쪼개져 병렬로 돈다. 응답 통계의 splits 가 그 조각 수다. 조각이 많으면 더 빨리 끝나지만 스케줄러와 쿼리어에 부하가 몰린다. 반대로 조각이 0 이면 한 조각으로 돈 것이다.

그래서 넓은 구간을 훑어야 할 때의 올바른 방법은 limit 을 키우는 것이 아니다. 구간을 잘라 여러 번 묻고 합치는 것이다. 각 조각의 결과 수가 limit 보다 작으면 그 조각은 완전하다는 것이 보장되고, 합계도 믿을 수 있다. 자동화 스크립트는 거의 항상 이 모양이어야 한다.

한도를 올리는 것이 답이 되는 경우는 드물다. max_entries_limit_per_query 를 키우면 쿼리어의 메모리가 커지고, 한 사람의 질의가 클러스터 전체를 흔들 수 있다. 한도는 사고를 막는 안전장치이지 방해물이 아니다.

현장에서 만나는 모습

첫째, "돌려받은 줄 수 == limit" 이면 무조건 의심한다. 자동화라면 이 조건을 명시적으로 검사해 경고를 내야 한다. 사람이 쓰는 대시보드라면 패널 제목에 limit 을 적어 두는 것만으로도 오해가 크게 줍니다.

둘째, 조사 시작 시각을 찾을 때는 direction=forward 를 쓴다. 이 한 글자가 보고서의 타임라인을 바꾼다.

셋째, 400 응답의 본문은 대개 친절하다 — 어떤 한도를 얼마나 넘겼는지 숫자까지 적어 준다. 자동화에서 그 본문을 버리고 상태 코드만 로그에 남기면, 나중에 원인을 찾느라 같은 질의를 손으로 다시 던지게 된다.

다음 실습에서 할 것

두 시간에 걸친 자료를 넣고, limit 을 작게 주었을 때 조용히 잘리는 것을 숫자로 확인한다. 서버 한도를 일부러 넘겨 400 과 그 본문을 직접 받아 보고, 구간 길이 한도도 같은 방법으로 확인한다. splits 가 구간에 따라 어떻게 달라지는지 재고, 마지막에는 한도 안에서 구간을 쪼개 두 시간치를 빠짐없이 세는 스크립트를 만든다.