轻量化日志中心 Grafana Loki
需要集中的日志系统的原因
目前现状,每个服务生产上有三台,定位生产问题,需要连上一台机器,然后使用 cd / tail / less / grep / sed / awk 等 linux命令去日志里查找故障原因。如果在这台机器没搜索到线索,就去另外两台机器上查日志。
但在分布式系统中,众多服务分散部署在数十台甚至上百台不同的服务器上,想要快速方便的实现查找、分析和归档等功能,使用Linux命令等传统的方式查询到想要的日志就费事费力,更不要说对日志进行分析与归纳了。
为解决大量日志归档,文件搜索慢,如何多维度查询就得需要集中化日志管理,将所有服务器上的日志收集汇总,常见的解决思路就是建立集中式日志收集系统。
LPG
Loki + Promtail + GRafana
- Loki:聚合并存储日志数据,可以作为Grafana的数据源,为Grafana提供可视化数据
- Promtail:日志收集器,有点像Filebeat,可以手机日志文件中的日志,并把收集到的数据推送到Loki。
- Grafana:从Loki中获取日志信息,进行可视化展示
Loki是 Grafana Labs 团队最新的开源项目,是一个水平可扩展,高可用,多租户的日志聚合系统。它的设计非常经济高效且易于操作,因为它不会为日志内容编制索引,而是为每个日志流编制一组标签,专门为 Prometheus和Kubernetes用户做了相关优化。
该项目受Prometheus启发,官方的介绍就是:Like Prometheus,But For Logs。类似Prometheus的日志系统。
项目地址:
https://github.com/grafana/loki/ |
与其他日志聚合系统相比,Loki具有以下特性:
- 不对日志进行全文索引。通过存储压缩非结构化日志和仅索引元数据,Loki操作起来会更简单,更省成本
- 通过使用与Prometheus相同的标签记录流对日志进行索引和分组,这使得日志的扩展和操作效率更高,能对接 alertmanager
- 特别适合存储Kubernetes Pod日志;诸如Pod标签之类的元数据会被自动删除和编入索引
- 受Grafana原生支持,避免Kibana和grafana来回切换
日志收集流程图
架构说明
部署
安装 docker
安装依赖 |
安装grafana
拉取镜像 |
安装Promtail
拉取镜像 |
安装Loki
拉取镜像 |
使用
Grafana配置Loki数据源
如下图:
源地址配置 http://10.0.0.74:3100 即可 保存
保存之后,切换到grafana左侧区域的Explore,即可进入到Loki页面
然后点击Log browser 就可以把当前系统采集的日志标签显示出来,再根据这些标签进行日志的过滤查询即可,比如这里选择 /var/log/message,10.0.0.74,就会把该文件下面的日志过滤展示出来
这里展示的是Promtail容器里面的 /var/log 目录中的日志
Promtail容器 /etc/promtail/config.yml
server: |
这里的 job 就是varlog,文件路径就是 /var/log/*log
只索引标签:之前多次看到Loki和ES最大的不同是Loki只对标签进行索引而不对内容索引。
静态标签匹配模式
以简单的Promtail配置举例
scrape_configs: |
解读:
- 上面这段配置代表启动一个日志采集任务
- 这个任务有一个固定标签 job: message
- 采集日志路径为 /var/log/messages,会以一个名为filename的固定标签
- 在Promtail的web页面上可以看到类似Promtail的target信息页面
可以和使用Prometheus一样的标签匹配语句进行查询 {job=”message”}
scrape_configs: |
如果我们配置了两个job,则可以使用 {job=~”message|varlogs”} 进行多job匹配;同时也支持正则匹配
标签匹配模式特点
- 和Prometheus一致,相同标签对应的是一个流Prometheus处理series的模式
- Prometheus中标签一致对应的同一个hash值和refid(正整数递增的id),也就是同一个series
- 时序数据不断的append追加到这个memseries中
- 当有人以标签发生变化时会产生新的hash值和refid,对应新的series
Loki处理日志的模式和Prometheus一致,loki一组标签值会生成一个stream。日志随着时间的递增会追加到这个stream中,最后压缩为chunk。当有人以标签发生变化时会产生新的hash值,对应新的stream
查询过程:
- loki现根据标签算出hash值在倒排索引中找到对应的chunk
- 然后再根据查询语句中的关键词等进行过滤,这样可以提速
- 因为这种根据标签算哈希在倒排中查找id,对应找到存储的块在Prometheus中已经被验证过了
- 属于第开销 速度快
动态标签和高基数
动态标签:标签的value不固定
高基数标签:标签的value可能性太多了,达到10万,100万甚至更多
比如Apache的access日志
11.11.11.11 - frank [25/Jan/2000:14:00:01 -0500] "GET /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6" |
在Promtail中使用regex想要匹配action和status_code两个标签:
scrape_configs: |
那么对应action=get/post 和 status_code=200/400 则对应4个流:
11.11.11.11 - frank [25/Jan/2000:14:00:01 -0500] "GET /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6" |
那四个日志行将变成4个单独的流,并开始填充4个单独的块,如果出现另一个独特的标签组合(如 status_code=500),则会创建另一个新流。
高基数问题:就像上面,如果给ip设置一个标签,来自用户的每个不同的ip请求不仅成为唯一的流。可以快速生成成千上万的流,这是高基数,这样可以杀死Loki
如果字段没有被当做标签被索引,会不会查询很慢,Loki的能力是将查询分解为小块并行分发,以便可以在短时间内查询大量日志数据
全文索引问题
大索引既复杂又昂贵。通常日志数据的全文索引的大小等于或大于日志数据本身的大小。
要查询日志数据,需要加载此索引,并且为了提高性能,它可能在内存中。这很难扩展,并随着日志增多,索引会迅速变大。
Loki的索引通常比摄取的日志量小一个数量级,索引的增长非常缓慢。
加速查询没标签字段:以👆提到的ip字段为例,使用过滤器表达式查询
{job="apache"}|="11.11.11.11" |
loki查询时的分片(按时间范围分段 grep)
- Loki把查询分解成较小的分片,并且与标签匹配的流打开每个区块,并开始寻找IP地址
- 这些分片的大小和并行化的数量是可以配置的,并取决于提供的资源
- 如果需要,可以将分片间隔配置文件5min,部署20个查询器,并在几秒钟内处理千兆字节的日志
- 或者,可以设置200个查询器并处理TB的日志
两种索引模式对比
- es的大索引,不管你查不查询,它都必须时刻存在。比如长时间占用过多的内存
- loki的逻辑是查询时在启动多个分段并行查询
日志量少时少加标签
- 因为每多加载一个chunk就有额外的开销
- 举例,如果查询是 {app=“loki”,level!=“bug”}
- 在没加level标签的情况下只需要加载一个chunk 即app=“loki”的标签
- 如果加了level的情况,则需要把level=info,warn,error,critical 5个chunk都加载再查询
需要标签是再去添加
- 当chunk_target_size=1M时 以1M的压缩大小来切割块
- 对应原始日志大小在5M—10M,如果日志在max_chunk_age时间内能达到10M,考虑添加标签
日志应当按时间递增
- 这个问题和tsdb中处理旧数据是一样的道理
- 目前loki为了性能考虑直接拒绝掉旧数据
对接Prometheus监控
修改 prometheus.yml
scrape_configs: |
然后加载Prometheus即可
Grafana dashboard
安装插件
grafana-cli plugins install grafana-piechart-panel |
dashboard效果图
import Dashboard Json
{ |