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

Loki — 不索引日志的日志库

同样结果的两条查询,一条四分钟,一条两秒

在 TT Lab 中继续学习

目标

读取 Loki 响应附带的 stats.summary,测量查询实际读了多少行、多少字节,亲自确认什么能减少这些数字,什么不能。

为什么重要

Loki 的索引里只有标签组合和数据块的时间范围。正文不被索引。所以查询总是按同一个顺序运行——选择器选出要打开的数据块,时间区间只留下其中重叠的,把剩下的全部读出来应用过滤器。只有前两步决定读取量,后面是丢弃已经读进来的东西。不了解这个顺序,就会一边把行过滤器放前面、一边把 limit 调小,等着查询变快。在成本按字节计的存储里,这个差别就是账单。

步骤

  1. 在 /root/lk-filters 中启动 Loki,把 date +%s 写入 /root/lk-filters/anchor.txt,然后用 python3 /opt/lab/d5/gen.py filters "$(cat anchor.txt)" 放入数据。接着对 {app=~"edge|cart|ship|batch"},以从基准时刻往前一小时的区间发出查询,把响应 stats.summary 中读取的行数和字节数,以 processed=<정수> 和 bytes=<정수>(占位符为整数)两行写入 /root/lk-filters/01-base.txt。
  2. 在同一个一小时区间里,把以四个流整体为对象、查找正文含有 SETTLE-LATE 的行的查询写入 /root/lk-filters/02-marker.logql,并把结果行数和读取行数,以 lines=<정수> 和 processed=<정수>(占位符为整数)两行写入 /root/lk-filters/02-marker.txt。
  3. 在给出同样答案(同样的行)的前提下,只缩小流选择器,把这个查询写入 /root/lk-filters/03-stream.logql,并把结果行数和读取行数,以 lines=<정수>、processed=<정수>(占位符为整数)写入 /root/lk-filters/03-stream.txt。再在 /root/lk-filters/03-ratio.txt 中以 ratio=<소수 둘째 자리>(占位符为保留到小数点后第二位的数)一行,写下读取行数相对于第 2 步的比率。
  4. 用与第 3 步相同的查询,只把区间改为 30 分钟(从基准时刻往前 1800 秒)发出。把结果行数和读取行数,以 lines=<정수>、processed=<정수>(占位符为整数)写入 /root/lk-filters/04-window.txt,并在 /root/lk-filters/04-note.txt 中写一个以 tradeoff= 开头的句子(去掉空格后至少 40 个字),用自己的话写出缩小区间时得到什么、失去什么。
  5. 在四个流整体、一小时区间里发出两个查询,比较读取的行数。一个是完全没有过滤器的 {app=~"edge|cart|ship|batch"},另一个是在其上再加两个行过滤器的查询。把结果写成四行存入 /root/lk-filters/05-linefilter.txt——plain_processed=、plain_lines=、filtered_processed=、filtered_lines=。
  6. 对四个流整体、一小时区间,发出接上了 | logfmt | status="500" 的查询,把三个数字写入 /root/lk-filters/06-parser.txt——processed=<읽은 줄 수>、post_filter=<필터를 통과해 남은 줄 수>、lines=<결과 줄 수>(占位符依次为读取的行数、通过过滤器后剩下的行数、结果行数)。把这三个数字与第 1 步的基准线比较,看看什么相同、什么变了。
  7. 把到目前为止测得的内容整理成 /root/lk-filters/cost.tsv。不要表头,共四行,每行是用制表符分隔的三列 <방법><탭><읽은줄수><탭><결과줄수>(占位符依次为方法、制表符、读取行数、制表符、结果行数)。方法名称依次为 all(第 2 步)、stream(第 3 步)、window(第 4 步)、parser(第 6 步)。
  8. 在 /root/lk-filters/08-budget.logql 中写一个查询。条件有三个——(1)以从基准时刻往前一小时的区间发出时,返回与第 2 步完全相同的行;(2)读取的行数在第 1 步基准线的三分之一以下;(3)不要依赖 limit。再在 /root/lk-filters/08-budget.txt 中以 processed=<정수>(占位符为整数)一行写下该查询读取的行数。

参考

放入四个流,测量基准线

在 /root/lk-filters 中启动 Loki,把 date +%s 写入 /root/lk-filters/anchor.txt,然后用 python3 /opt/lab/d5/gen.py filters "$(cat anchor.txt)" 放入数据。接着对 {app=~"edge|cart|ship|batch"},以从基准时刻往前一小时的区间发出查询,把响应 stats.summary 中读取的行数和字节数,以 processed=<정수> 和 bytes=<정수>(占位符为整数)两行写入 /root/lk-filters/01-base.txt。

统计在 query_range 响应的 data.stats.summary 里——用 jq '.data.stats.summary' 整个看一遍。是 totalLinesProcessed 和 totalBytesProcessed 这两项。这个数字就是本实验自始至终要比较的基准线。

为了找五行,读了多少行

在同一个一小时区间里,把以四个流整体为对象、查找正文含有 SETTLE-LATE 的行的查询写入 /root/lk-filters/02-marker.logql,并把结果行数和读取行数,以 lines=<정수> 和 processed=<정수>(占位符为整数)两行写入 /root/lk-filters/02-marker.txt。

一个行过滤器就够了。重要的不是答案,而是为得到答案读取的量——把两个数字并排放着看。也要确认读取的行数是否与第 1 步的基准线相同。

缩小选择器,读取量就会减少

在给出同样答案(同样的行)的前提下,只缩小流选择器,把这个查询写入 /root/lk-filters/03-stream.logql,并把结果行数和读取行数,以 lines=<정수>、processed=<정수>(占位符为整数)写入 /root/lk-filters/03-stream.txt。再在 /root/lk-filters/03-ratio.txt 中以 ratio=<소수 둘째 자리>(占位符为保留到小数点后第二位的数)一行,写下读取行数相对于第 2 步的比率。

标记出自哪个服务,看第 2 步结果的 stream 标签就知道。把选择器缩小成那一个。结果行数必须保持不变——不改变答案,只降低成本,这就是这一步的要点。比率是用第 3 步读取的行数除以第 2 步的值。

缩小区间,读取量会减少,答案也会减少

用与第 3 步相同的查询,只把区间改为 30 分钟(从基准时刻往前 1800 秒)发出。把结果行数和读取行数,以 lines=<정수>、processed=<정수>(占位符为整数)写入 /root/lk-filters/04-window.txt,并在 /root/lk-filters/04-note.txt 中写一个以 tradeoff= 开头的句子(去掉空格后至少 40 个字),用自己的话写出缩小区间时得到什么、失去什么。

查询语句保持不变,只改 start。读取的行数会减少一半左右,结果行数也一起减少——区间之外的答案根本看不到。想一想,在不知道事故时刻的情况下就先缩小区间,会有什么危险。

加上行过滤器,读取量也不变

在四个流整体、一小时区间里发出两个查询,比较读取的行数。一个是完全没有过滤器的 {app=~"edge|cart|ship|batch"},另一个是在其上再加两个行过滤器的查询。把结果写成四行存入 /root/lk-filters/05-linefilter.txt——plain_processed=、plain_lines=、filtered_processed=、filtered_lines=。

行过滤器用什么都行(例如 |= "level=error" 和 != "route=/a")。要看的是四个数字之间的关系——哪一对相同,哪一对不同。相同的一边是“读取量”,不同的一边是“剩下的量”。

接上解析器,读取量也不变

对四个流整体、一小时区间,发出接上了 | logfmt | status="500" 的查询,把三个数字写入 /root/lk-filters/06-parser.txt——processed=<읽은 줄 수>、post_filter=<필터를 통과해 남은 줄 수>、lines=<결과 줄 수>(占位符依次为读取的行数、通过过滤器后剩下的行数、结果行数)。把这三个数字与第 1 步的基准线比较,看看什么相同、什么变了。

totalPostFilterLines 是统计的第三项。cost.sh 不输出这一项,所以直接用 curl ... | jq '.data.stats.summary' 来看,或者修改辅助工具来用。解析器做的事比行过滤器更贵,但在读取量这个标准上,两者处于同一个位置。

应用 ① ——四种方法的成本表

把到目前为止测得的内容整理成 /root/lk-filters/cost.tsv。不要表头,共四行,每行是用制表符分隔的三列 <방법><탭><읽은줄수><탭><결과줄수>(占位符依次为方法、制表符、读取行数、制表符、结果行数)。方法名称依次为 all(第 2 步)、stream(第 3 步)、window(第 4 步)、parser(第 6 步)。

从前面步骤里做出的文件中取出值汇总即可。表做出来之后一眼就能看出来——读取行数真正减少的行有几个。

应用 ② ——在预算内给出同样答案的查询

在 /root/lk-filters/08-budget.logql 中写一个查询。条件有三个——(1)以从基准时刻往前一小时的区间发出时,返回与第 2 步完全相同的行;(2)读取的行数在第 1 步基准线的三分之一以下;(3)不要依赖 limit。再在 /root/lk-filters/08-budget.txt 中以 processed=<정수>(占位符为整数)一行写下该查询读取的行数。

减少读取量的旋钮只有两个。这一步不能改区间,所以要用剩下的那一个来解决。第 2 步结果的 stream 标签会告诉你答案。改完查询之后,一定要重新测一下结果行数是否保持不变——变便宜了,答案却变了,那就不是调优,而是事故。