LabHub
学习 学习路径 课程

Loki — 不索引日志的日志库

我们把故障开始时间报晚了四十分钟

在 LabHub 中继续学习

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

목표

Loki 의 질의 한도를 직접 넘어 보며 조용히 잘리는 경우와 400 으로 거절되는 경우를 가르고, 한도 안에서 넓은 구간을 빠짐없이 훑는 방법을 만듭니다.

왜 중요한가

로그 질의의 결과 수는 세 손잡이가 정한다. 요청의 limit 은 조용히 자르고, 서버의 max_entries_limit_per_querymax_query_length 는 400 으로 거절한다. 거절은 바로 보이지만 조용히 잘린 답은 '이게 전부' 처럼 보인다. 게다가 direction무엇이 잘려 나갈지를 정해서, 기본값인 backward 로 사고의 시작을 찾으면 정확히 찾고 싶은 것이 잘려 나간다. 넓은 구간을 훑어야 할 때의 답은 한도를 올리는 것이 아니라 구간을 잘라 여러 번 묻고 합치는 것이다 — 각 조각이 한도보다 작다는 것이 합계를 믿을 수 있게 만든다.

단계

  1. /root/lk-query-limits 에서 Loki 를 띄우고 date +%s/root/lk-query-limits/anchor.txt 에 적은 뒤 python3 /opt/lab/d5/gen.py querylimits "$(cat anchor.txt)" 로 자료를 넣으세요. 그리고 {app="gateway"} 를 기준 시각에서 과거 두 시간 구간으로 로그 질의해 전체 줄 수를 /root/lk-query-limits/01-total.txttotal=<정수> 한 줄로 적으세요. limit5000 으로 주고, 돌려받은 수가 그 값보다 작은지 반드시 확인하세요.
  2. 같은 두 시간 구간을 limit=100, direction=backward 로 로그 질의해 돌려받은 줄 수와 그중 가장 이른 줄의 나노초 타임스탬프/root/lk-query-limits/02-cut.txt 에 두 줄로 적으세요 — returned=<정수>oldest_ts=<나노초>. 응답 어디에도 '잘렸다' 는 표시가 없다는 것을 직접 확인하세요.
  3. 같은 질의를 limit=6000 으로 던져 보세요. 응답의 상태 코드와 본문에 적힌 한도값, 그리고 서버 /config 에서 읽은 그 설정의 값을 /root/lk-query-limits/03-entries.txt 에 세 줄로 적으세요 — code=<정수>, limit_in_body=<정수>, limit_in_config=<정수>.
  4. 같은 질의를 60일 구간으로 던져 보세요. 상태 코드와 서버 /config 의 구간 길이 한도를 /root/lk-query-limits/04-length.txt 에 세 줄로 적습니다 — code=<정수>, param=<설정 이름>, value=<서버가 찍은 값 그대로>.
  5. 같은 질의를 두 시간 구간과 30분 구간으로 각각 던져 응답 통계의 splits 를 재고, 서버의 조각 간격 설정도 읽어 /root/lk-query-limits/05-splits.txt 에 세 줄로 적으세요 — splits_2h=<정수>, splits_30m=<정수>, interval=<서버가 찍은 값 그대로>.
  6. limit50·500·5000 세 번 주어 같은 질의를 던지고, 결과를 /root/lk-query-limits/detect.tsv 에 머리글 없이 세 줄, 탭으로 나눈 세 칸 <limit><탭><returned><탭><truncated> 로 적으세요. truncatedyes 또는 no 이고, 판정 기준은 1단계에서 구한 진짜 총계입니다.
  7. /root/lk-query-limits/scan.sh 를 만들어 두 시간 구간을 30분씩 네 조각으로 나눠 각각 질의하고 합계를 내세요. 각 조각은 limit=5000 으로 던지고, 조각의 결과 수가 limit 과 같으면 INCOMPLETE 를 함께 출력해야 합니다. 스크립트를 돌린 결과를 /root/lk-query-limits/07-scan.txtsum=<정수>chunks=4 두 줄로 적습니다. 합계는 1단계의 총계와 같아야 합니다.
  8. 두 시간 구간에서 status=500 인 줄 중 가장 최근 50건을 가져오는 질의를 설계해 /root/lk-query-limits/08-latest.txt 에 세 줄로 적으세요 — returned=<정수>, newest_ts=<나노초>, oldest_ts=<나노초>. 50건보다 적게 있다면 있는 만큼만 나오면 됩니다.

참고

두 시간치를 넣고 진짜 총계를 구한다

/root/lk-query-limits 에서 Loki 를 띄우고 date +%s/root/lk-query-limits/anchor.txt 에 적은 뒤 python3 /opt/lab/d5/gen.py querylimits "$(cat anchor.txt)" 로 자료를 넣으세요. 그리고 {app="gateway"} 를 기준 시각에서 과거 두 시간 구간으로 로그 질의해 전체 줄 수를 /root/lk-query-limits/01-total.txttotal=<정수> 한 줄로 적으세요. limit5000 으로 주고, 돌려받은 수가 그 값보다 작은지 반드시 확인하세요.

돌려받은 수가 limit 과 같으면 잘렸다는 뜻이라 총계로 쓸 수 없습니다. 작으면 그 구간을 다 받은 것입니다. 이 숫자가 뒤 단계 내내 "잘렸는가" 를 판정하는 기준이 됩니다. 지표 질의(sum(count_over_time(...[2h])))로도 셀 수 있지만 범위 집계는 구간의 왼쪽 끝을 포함하지 않아 한 줄쯤 다르게 나올 수 있습니다.

limit 은 아무 말 없이 자른다

같은 두 시간 구간을 limit=100, direction=backward 로 로그 질의해 돌려받은 줄 수와 그중 가장 이른 줄의 나노초 타임스탬프/root/lk-query-limits/02-cut.txt 에 두 줄로 적으세요 — returned=<정수>oldest_ts=<나노초>. 응답 어디에도 '잘렸다' 는 표시가 없다는 것을 직접 확인하세요.

backward 는 최근부터 채웁니다. 그래서 돌려받은 100줄의 가장 이른 시각은 구간의 시작이 아니라 훨씬 뒤입니다. 이 값을 사고 시작 시각으로 보고하면 어떻게 되는지 생각해 보세요.

서버 한도는 대놓고 거절한다

같은 질의를 limit=6000 으로 던져 보세요. 응답의 상태 코드와 본문에 적힌 한도값, 그리고 서버 /config 에서 읽은 그 설정의 값을 /root/lk-query-limits/03-entries.txt 에 세 줄로 적으세요 — code=<정수>, limit_in_body=<정수>, limit_in_config=<정수>.

400 의 본문은 친절합니다 — 어떤 한도를 얼마나 넘겼는지 숫자까지 적혀 있습니다. /configlimits_config 에서 같은 이름을 찾아 두 값이 같은지 확인하세요. 자동화에서 이 본문을 버리고 상태 코드만 남기면 나중에 원인을 못 찾습니다.

구간이 너무 길어도 거절한다

같은 질의를 60일 구간으로 던져 보세요. 상태 코드와 서버 /config 의 구간 길이 한도를 /root/lk-query-limits/04-length.txt 에 세 줄로 적습니다 — code=<정수>, param=<설정 이름>, value=<서버가 찍은 값 그대로>.

start 를 60일 전으로 주면 됩니다. 본문에 질의 길이와 한도가 나란히 적혀 나옵니다. /configlimits_config 에서 같은 이름을 찾으세요 — 값의 표기가 본문과 다를 수 있습니다.

질의는 시간 조각으로 쪼개져 돈다

같은 질의를 두 시간 구간과 30분 구간으로 각각 던져 응답 통계의 splits 를 재고, 서버의 조각 간격 설정도 읽어 /root/lk-query-limits/05-splits.txt 에 세 줄로 적으세요 — splits_2h=<정수>, splits_30m=<정수>, interval=<서버가 찍은 값 그대로>.

splitsdata.stats.summary 에 있습니다. 조각 수가 구간 길이와 설정값에서 어떻게 나오는지 계산해 보세요 — 짧은 구간에서 0 이 나오는 것도 뜻이 있습니다.

잘렸는지 알아채는 법

limit50·500·5000 세 번 주어 같은 질의를 던지고, 결과를 /root/lk-query-limits/detect.tsv 에 머리글 없이 세 줄, 탭으로 나눈 세 칸 <limit><탭><returned><탭><truncated> 로 적으세요. truncatedyes 또는 no 이고, 판정 기준은 1단계에서 구한 진짜 총계입니다.

돌려받은 줄 수가 limit 과 같으면 거의 확실히 잘린 것이고, 총계보다 작으면 확실히 잘린 것입니다. 두 기준이 어긋나는 경우가 있는지도 생각해 보세요 — 총계와 같은 수를 받았다면 limit 과 같더라도 안 잘린 것입니다.

응용 ① — 구간을 쪼개 빠짐없이 센다

/root/lk-query-limits/scan.sh 를 만들어 두 시간 구간을 30분씩 네 조각으로 나눠 각각 질의하고 합계를 내세요. 각 조각은 limit=5000 으로 던지고, 조각의 결과 수가 limit 과 같으면 INCOMPLETE 를 함께 출력해야 합니다. 스크립트를 돌린 결과를 /root/lk-query-limits/07-scan.txtsum=<정수>chunks=4 두 줄로 적습니다. 합계는 1단계의 총계와 같아야 합니다.

각 조각의 시작과 끝을 겹치지 않게 잡는 것이 핵심입니다 — 경계 한 초를 두 조각이 함께 세면 합계가 커지고, 빠뜨리면 작아집니다. 구간의 왼쪽 끝은 포함, 오른쪽 끝은 제외로 맞추면 깔끔합니다.

응용 ② — 가장 최근 오류 50건을 정확히 가져온다

두 시간 구간에서 status=500 인 줄 중 가장 최근 50건을 가져오는 질의를 설계해 /root/lk-query-limits/08-latest.txt 에 세 줄로 적으세요 — returned=<정수>, newest_ts=<나노초>, oldest_ts=<나노초>. 50건보다 적게 있다면 있는 만큼만 나오면 됩니다.

방향과 limit 을 함께 정해야 합니다. '가장 최근' 을 원할 때의 방향과, 2단계에서 사고 시작을 찾을 때 필요했던 방향이 서로 반대라는 점이 이 실습의 요점입니다. 돌려받은 수가 limit 과 같은지도 함께 확인하세요.