TT Lab
开始
学习 学习路径 课程

Loki — 不索引日志的日志库

补回了两小时的日志,界面上却什么都没有

在 TT Lab 中继续学习

目标

在 Pod 里的真正的 Loki 上重现“用过去的时间戳放进去的行被接收了却看不到”的现象,在服务器上亲自确认决定那条界线的设置,然后用 flush 让它重新可见。

为什么重要

Loki 的写入和读取走的是不同的路。进来的行堆积在 ingester 打开着的数据块里,数据块关闭之后才会上传到存储。查询会问存储,如果是最近的区间,也会问 ingester,而这个“最近”的范围就是 query_ingesters_within(默认 3 小时)。所以为了恢复而事后推进去的过去数据,会掉进两条路之间的缝隙——存储里还没有,ingester 里有,却没有人去问。不了解这个结构,就会得出“push 在撒谎”的结论,去修错地方。

步骤

  1. 在 /root/lk-chunks 中启动 Loki,把 date +%s 写入 /root/lk-chunks/anchor.txt,然后用 python3 /opt/lab/d5/gen.py chunks "$(cat anchor.txt)" 放入数据。这份数据在距基准时刻 30 分钟以内。用一小时区间查询 {app="fresh"} 并数出行数,同时数一数存储目录 /tmp/lokidata/chunks 下的文件数,以 lines=<정수> 和 chunk_files=<정수>(占位符为整数)两行写入 /root/lk-chunks/01-boot.txt。
  2. 用 python3 /opt/lab/d5/gen.py chunks-old "$(cat anchor.txt)" 放入基准时刻五小时前的数据。然后用该时刻前后一小时的区间查询 {app="aged"} 并数出行数,写成两行存入 /root/lk-chunks/02-aged.txt——push_code=<HTTP 상태 코드> 和 lines=<정수>(占位符依次为 HTTP 状态码、整数)。
  3. 往四个新的流里各放一行,确认能不能看到——分别是距基准时刻 1、2、4、5 小时前,标签是 {"app":"b1h"}、b2h、b4h、b5h。把结果写入 /root/lk-chunks/boundary.tsv,不要表头,共四行,每行是用制表符分隔的两列 <시간><탭><yes|no>(占位符依次为小时数、制表符、yes 或 no)(小时数为 1、2、4、5)。然后在服务器的 /config 里找到决定这条界线的设置,以 param=<설정 이름> 和 value=<기본값 그대로>(占位符依次为设置名称、原样的默认值)两行写入 /root/lk-chunks/03-param.txt。
  4. 把 flush 前后记录到同一个文件里。先测出 {app="aged"} 的行数和 /tmp/lokidata/chunks 的文件数,调用 curl -XPOST http://localhost:3100/flush 之后,再测一遍同样的两个数字。写成四行存入 /root/lk-chunks/04-flush.txt——aged_before=、chunks_before=、aged_after=、chunks_after=。
  5. 在服务器的 /config 里找到决定打开着的数据块何时关闭的三个设置,写入 /root/lk-chunks/chunkparams.tsv,不要表头,共三行,每行是用制表符分隔的两列 <설정이름><탭><값>(占位符依次为设置名称、制表符、值)。顺序是 chunk_idle_period、chunk_target_size、max_chunk_age,值要原样照服务器印出来的写。
  6. 确认 flush 结束的现在,索引里有哪些流,用 series API 查看,写成两行存入 /root/lk-chunks/06-series.txt——streams=<정수> 和 apps=<app 라벨 값들을 쉼표로, 사전순>(占位符依次为整数、按字典序用逗号连接的 app 标签值)。查询区间给出从基准时刻往前七小时。第 8 步要做的 revive 流不计入(这一步里它还不存在)。
  7. 在 /root/lk-chunks/runbook.txt 中写四行。每行以 1. 到 4. 开头,每行里要有一条真正可以敲的确认命令,或者要确认的值。主题是收到“过去区间的日志看起来是空的”这条反馈时的检查顺序。四行合计去掉空格后要有 120 个字以上。
  8. 把一条正文里含有 revive-check 这个词的行,以标签 {"app":"revive"}、基准时刻六小时前放进去,用查询让它变得可见,然后把这一行的正文以一行写入 /root/lk-chunks/08-revive.txt。正文的其余内容不限。

参考

最近的数据一放进去就能看到

在 /root/lk-chunks 中启动 Loki,把 date +%s 写入 /root/lk-chunks/anchor.txt,然后用 python3 /opt/lab/d5/gen.py chunks "$(cat anchor.txt)" 放入数据。这份数据在距基准时刻 30 分钟以内。用一小时区间查询 {app="fresh"} 并数出行数,同时数一数存储目录 /tmp/lokidata/chunks 下的文件数,以 lines=<정수> 和 chunk_files=<정수>(占位符为整数)两行写入 /root/lk-chunks/01-boot.txt。

设置文件中的 path_prefix 和 storage_config.filesystem.directory 决定存储的位置。文件数用 find /tmp/lokidata/chunks -type f | wc -l 来数。刚放进去,那个目录却是空的,如果觉得奇怪,那正是本实验的出发点。

五小时前的数据收到了 204,却看不到

用 python3 /opt/lab/d5/gen.py chunks-old "$(cat anchor.txt)" 放入基准时刻五小时前的数据。然后用该时刻前后一小时的区间查询 {app="aged"} 并数出行数,写成两行存入 /root/lk-chunks/02-aged.txt——push_code=<HTTP 상태 코드> 和 lines=<정수>(占位符依次为 HTTP 状态码、整数)。

生成器失败时会以非 0 的值结束。想亲眼看状态码的话,用 curl -o /dev/null -w '%{http_code}' 手工放入一行试试。查询区间必须把五小时前放在中间——如果问的是最近一小时,当然是 0。

实测界线在哪里,并在设置里确认

往四个新的流里各放一行,确认能不能看到——分别是距基准时刻 1、2、4、5 小时前,标签是 {"app":"b1h"}、b2h、b4h、b5h。把结果写入 /root/lk-chunks/boundary.tsv,不要表头,共四行,每行是用制表符分隔的两列 <시간><탭><yes|no>(占位符依次为小时数、制表符、yes 或 no)(小时数为 1、2、4、5)。然后在服务器的 /config 里找到决定这条界线的设置,以 param=<설정 이름> 和 value=<기본값 그대로>(占位符依次为设置名称、原样的默认值)两行写入 /root/lk-chunks/03-param.txt。

curl -s localhost:3100/config 会把现在运行的设置整个给出来。看一看 querier: 块。值要原样写下服务器印出来的字符串(例如 1h0m0s 这样的形态)。查询每一行时,要在该时刻前后给足够宽的区间。

强制 flush 之后,同一个查询就能回答了

把 flush 前后记录到同一个文件里。先测出 {app="aged"} 的行数和 /tmp/lokidata/chunks 的文件数,调用 curl -XPOST http://localhost:3100/flush 之后,再测一遍同样的两个数字。写成四行存入 /root/lk-chunks/04-flush.txt——aged_before=、chunks_before=、aged_after=、chunks_after=。

flush 是异步的。文件真正出现要花几秒钟,所以不要用固定的 sleep,要用一个短暂循环,等到文件数增加为止(别忘了设上限)。查询区间要与第 2 步相同,才能比较这两个数字。

数据块什么时候关闭——找出三个旋钮

在服务器的 /config 里找到决定打开着的数据块何时关闭的三个设置,写入 /root/lk-chunks/chunkparams.tsv,不要表头,共三行,每行是用制表符分隔的两列 <설정이름><탭><값>(占位符依次为设置名称、制表符、值)。顺序是 chunk_idle_period、chunk_target_size、max_chunk_age,值要原样照服务器印出来的写。

它们在 ingester: 块里。如果 /config 的输出很长,先用 grep -n 找出行号,再用 sed -n 只看那附近。同样的名称也可能出现在其他块里,所以要确认是哪个块的值。

索引里留下了什么

确认 flush 结束的现在,索引里有哪些流,用 series API 查看,写成两行存入 /root/lk-chunks/06-series.txt——streams=<정수> 和 apps=<app 라벨 값들을 쉼표로, 사전순>(占位符依次为整数、按字典序用逗号连接的 app 标签值)。查询区间给出从基准时刻往前七小时。第 8 步要做的 revive 流不计入(这一步里它还不存在)。

给 /loki/api/v1/series 传入 match[]={app=~".+"} 和 start、end。如果不给区间,默认值是最近几个小时,过去的流就会被漏掉——这本身就和本实验所说的陷阱是同一类。

应用 ① ——收到同样反馈时的检查顺序

在 /root/lk-chunks/runbook.txt 中写四行。每行以 1. 到 4. 开头,每行里要有一条真正可以敲的确认命令,或者要确认的值。主题是收到“过去区间的日志看起来是空的”这条反馈时的检查顺序。四行合计去掉空格后要有 120 个字以上。

按顺序回想本实验里实际用过的东西就行——有没有被接收、哪条路径在回答、有没有落到存储、设置是怎样的。要把命令原样写下来,让别人在凌晨读着也能照着做。

应用 ② ——让一条六小时前的行变得可见

把一条正文里含有 revive-check 这个词的行,以标签 {"app":"revive"}、基准时刻六小时前放进去,用查询让它变得可见,然后把这一行的正文以一行写入 /root/lk-chunks/08-revive.txt。正文的其余内容不限。

把前面步骤做过的事按顺序再做一遍就行——放进去、落到存储、用把那个时刻放在中间的区间去问。如果查询给出空结果,说明还差一步。