对于一个系统来说,日志具有非常重要的作用,当我们遇到某个问题,可以直接登录到机器上面,看看日志,grep 下关键信息,在辅助其他一些手段,多数就能快速定位问题了。但是,对于分布式系统来说,因为日志散落在很多的机器上面,我们不可能人工的登录到不同的机器查看,而且也没法对多台机器上面的日志进行汇总聚合分析,所以,这里,我们一定需要一个统一的 Log 管理工具,它不光能帮我们自动的收集所有机器上面的 Log,同时也能让我们方便的使用各种条件来查询特定的信息。
在 TiDB 里面,我们使用的是 fluentbit + Elasticsearch,两者结合,很好的帮我们解决了上面的需求。不过这里我要说的,是另一套解决方案 Loki,虽然它现在还不成熟,但因为是 Grafana 团队开发的, 所以没准会成为 K8s 下面的一套标准。
Loki
根据官网的介绍,Loki 是一个可水平扩展的,高可靠的,支持多租户的 Log 聚合系统,有点类似于 Prometheus,不过是针对 Log 的。网上已经有很多针对 Loki 的介绍,这里不重点说明了,我觉得 Loki 有两点吸引我的地方:
- 非常类似 Prometheus,如果大家熟悉了 Prometheus,用 Loki 会非常的习惯,毕竟 Label 这些概念都是一致的。而且 Loki 里面还可以支持将 Log entry 提取成一个 metrics。
- 跟 Grafana 完美结合,不过这需要 Grafana 6.0 及以上版本的支持。
除了 Loki 自身,我们有时候还需要使用另外两个组件:
- Promtail : 用来将不同机器上面的 Log 收集并且发给 Loki
- Logcli:Loki 的 cli 客户端,如果没有 Grafana,就可以用这个来操作
其实对于 Promtail,大家也可以使用其他的 Log 收集器,譬如著名的 fluentd,fluentbit 这些,然后写个插件能将 Log 发给 Loki 就成,毕竟 Loki 的 API 足够简单,很容易对接。
我是直接从源码来安装 Loki 的,参考的这里,没什么难度,唯一想吐槽的就是现在都什么年代了,Loki 竟然还是使用的 dep + vendor 的方式来管理项目的依赖(貌似最新的已经换成 go mod 方式了)。
运行
首先,我们启动 Loki,这里,因为我只是在本机验证,所以直接使用的是 Loki 里面自带的配置文件:
./loki --config.file=./cmd/loki/loki-local-config.yaml
默认的配置里面,Loki 是监听 3100 端口。
然后就是启动 Promtail 了,这里要在配置文件里面配置如何让 Promtail 去抓取 TiDB 集群的日志:
scrape_configs:
- job_name: tikv
pipeline_stages:
- regex:
expression: '\[(?P<time>\d{4}\/\d{2}\/\d{2}.\d{2}:\d{2}:\d{2}.\d{3}.\+\d{2}:\d{2})\].\[(?P<level>\w*)\].\[(?P<source>\w.*):(?P<line>\d*)\].(?P<message>.*$)'
- labels:
level:
- timestamp:
format: 2006/01/02 15:04:05.000 -07:00
source: time
static_configs:
- targets:
- localhost
labels:
job: tikv
__path__: /var/tikv*.log
上面的例子是 Prometheus 抓取 TiKV 日志的配置,job 的名字就是 “tikv”,因为整个 TiDB 的日志格式跟 Loki 默认能处理的不一样,我们需要自己解析出来,这个就是在 regex 的 expression 定义的正则,用来匹配类似如下的 Log 格式:
[2019/07/21 17:26:36.484 +08:00] [INFO] [peer.rs:142] ["create peer"] [peer_id=31] [region_id=30]
具体格式定义,大家可以参考这里。
然后我们在额外定义了一个 label level,也就是 Loki 到时候会按照 Log level 对 log 进行分组聚合。
再就是 timestamp 的处理,因为我们的日志里面包含了时间,所以需要显示的告诉 Promtail 用我们日志里面的时间,不然 Promtail 就会用它自己的当前时间作为日志的时间,这个其实就不对了。
TiDB 其他组件也会按照同样的方式来配置, 当然最后,我们还要启动整个 TiDB 集群,参考这里。
Grafana
当整个都启动起来之后,我们就可以打开 Grafana,参考这里,将 Loki 加入到 Grafana 中,然后就可以做查询操作了,譬如下面,我按照 job 来简单的查询,得到如下的输出:
看起来还是挺不错的,不过唯一让我有点不爽的就是 timestamp 有点冗余,Grafana 显示了两次时间,这个主要原因在于 Promtail 在处理的时候,仍然会把原始 message 发给 Loki。我没找到比较好的办法来解决,没准用 template 能搞定。
于是我尝试了另一种方法,自己写了一个 tidb-to-loki,将 TiDB 的日志发给 Loki,毕竟我们只需要使用 Loki 的 Push API 就可以了,而且它还支持 JSON 格式,都不用去折腾 Protobuf 的,然后 Grafana 展示如下:
界面清爽了很多,但现在 tidb-to-loki 还只是一个玩具,不可能用于生产,后面还不如增强 Promtail 或者用 fluentbit 这些来搞定吧。
总结
总的来说,受益于 Grafana,我对于 Loki 的未来还是蛮期待的,写到这里,不由的现编了一个段子:
曾经,有一位程序员新手跑到一位大师面前,问道:『大师,我写的服务器程序出现了问题,请告诉我如何快速找到问题?』
大师:『日志』。