LabHub
배우기 러닝패스 코스

Loki — 로그를 색인하지 않는 로그 저장소 · 넣는 쪽의 한도 · 이론

400 은 고치고 429 는 기다린다

LabHub 에서 이어서 보기

한 줄 요약

넣는 쪽의 거절은 두 종류다. 400 은 고쳐야 하고 429 는 기다려야 한다. 이 둘을 같은 코드로 처리하는 수집기는 둘 다 잘못 다룬다.

왜 이게 필요했나

새 서비스를 붙인 날 수집기 로그에 거절이 쏟아졌다. 담당자는 재시도 로직을 켜고 퇴근했다. 다음 날 아침, 거절은 그대로였고 대신 수집기의 버퍼가 가득 차 다른 서비스의 로그까지 밀리고 있었다.

거절은 400 이었다. 라벨 이름에 하이픈이 들어 있었고, 그 줄은 몇 번을 다시 보내도 영원히 거절된다. 재시도는 상황을 고치지 못하고 큐만 채웠다. 반대로 같은 주에 다른 서비스에서 난 429 는 재시도가 정답이었는데, 그쪽은 재시도 없이 그냥 버리고 있었다.

어떻게 동작하나

Loki 가 들어오는 요청을 거절하는 이유는 크게 네 가지다.

| 상황 | 코드 | 대처 |
| --- | --- | --- |
| 라벨 이름이 문법에 안 맞음 | 400 | 보내는 쪽을 고친다 |
| 라벨 개수가 상한을 넘음 (max_label_names_per_series) | 400 | 라벨을 줄인다 |
| 줄이 너무 김 (max_line_size) | 400 | 자르거나 나눈다 |
| 스트림당 속도 초과 (per_stream_rate_limit) | 429 | 백오프 후 재시도한다 |

라벨 이름은 프로메테우스와 같은 규칙이다 — 문자나 밑줄로 시작하고 문자·숫자·밑줄만 쓴다. 하이픈은 안 되고 숫자로 시작할 수도 없다. 쿠버네티스 라벨을 그대로 옮기려다 이 벽에 부딪히는 경우가 많아서, 수집기 쪽에서 이름을 바꿔 주는 설정을 미리 넣어 두는 편이 낫다.

속도 제한은 스트림 단위다. 그래서 같은 서비스라도 라벨 조합이 여러 개면 각 조합이 따로 한도를 받는다. 반대로 라벨을 줄여 스트림을 합치면 한 스트림에 트래픽이 몰려 429 가 난다. 카디널리티를 낮추는 일과 속도 제한을 피하는 일이 서로 반대 방향으로 당긴다 — 이 긴장을 모르면 한쪽만 고치다 다른 쪽을 터뜨린다.

버스트가 이 그림에 한 겹 더한다. per_stream_rate_limit_burst 는 순간적으로 한도를 넘겨도 되는 양이다. 그래서 잠잠하다 몰아치는 트래픽은 처음 얼마간은 통과하고 그 뒤부터 429 를 받는다. "처음엔 되다가 갑자기 안 된다" 는 증상의 정체가 대개 이것이다.

429 를 받았을 때의 올바른 클라이언트는 셋을 갖춘다 — 지수 백오프, 지터, 재시도 상한. 지터가 없으면 여러 수집기가 같은 박자로 다시 몰려와 같은 벽을 함께 친다. 상한이 없으면 400 을 429 로 착각했을 때 영원히 재시도한다.

현장에서 만나는 모습

가장 흔한 사고는 위의 "400 에 재시도" 다. 수집기 설정에서 재시도 조건을 상태 코드로 명시하고, 400 대는 격리 큐로 보내 사람이 보게 만드는 것이 해법이다.

두 번째는 긴 줄이다. 스택 트레이스 하나가 상한을 넘으면 그 요청이 통째로 거절되어 같은 배치의 멀쩡한 줄까지 함께 떨어진다. 그래서 수집기에서 먼저 자르거나, 배치를 작게 잡아 피해 범위를 줄인다.

세 번째는 라벨 개수다. 쿠버네티스 메타데이터를 전부 라벨로 옮기면 상한을 쉽게 넘는다. 필요한 대여섯 개만 남기고 나머지는 본문에 두면 거절도 사라지고 스트림 수도 줄어든다.

다음 실습에서 할 것

서버가 들고 있는 한도들을 /config 에서 직접 읽어 표로 만들고, 잘못된 라벨과 너무 긴 줄을 실제로 보내 400 과 그 본문을 받아 본다. 그 다음 낮은 속도 한도를 건 두 번째 Loki 를 띄워 진짜 429 를 받고, 버스트 때문에 처음 몇 번이 통과한 이유를 숫자로 설명한다. 마지막에는 백오프 재시도를 붙여 한 줄도 잃지 않고 전부 저장하는 데까지 간다.