在前面章节已经介绍了使用Grafana生态搭建链路跟踪系统,这一节开始将会向大家介绍围绕Loki搭建日志平台,同样的日志的查询也是在Grafana上进行,Grafana内置了Loki类型的数据源。
Loki
Loki是Grafana Labs开源的一个可水平扩展、高可用的多租户日志系统。其设计非常简洁高效,简洁的最大原因是与传统的EFK(ELK)日志系统最大的差别在于对日志内容的处理上。
EFK(ELK)是将日志内容存储在ElasticSeach里,ElasticSeach会对日志内容进行编排索引。
而Loki是为每个日志处理成一组键值对,这一组键值对类似Promethues采集的指标中的Labels。这样日志内容就可以像通过Label查询Metrcis一样进行查找。类似Prometheus的查询PromQL规则一样,Loki提供了LogQL语句查询。
官方对Loki的介绍就是 Like Prometheus,but for logs。
Loki的数据流如下,由三部分组成:
Agent:在集群内部采集各应用服务日志的客户端,例如Promtail、grafana Agent。Grafana Agent除了可以收集日志,在链路跟踪Grafana Tempo的介绍和部署 章节用来收集Trace数据。后面也会介绍Grafana Agent对Metrics的采集。
Loki:日志系统的主服务,存储日志和提供日志查询的处理
Grafana:提供日志查询的前端页面,供用户使用日志查询功能。同时Loki提供了工具LogCLI进行命令式的查询。

Loki组件

Distributor
接收来自客户端的数据,是日志数据流到达服务端的第一站。在这里Distributor会对数据流进行校验其正确性,会分析日志数据是否是太旧了还是否需要采集,同时判断是否满足配置的Limit限制(各租户的)。在确保数据合法之后会将日志流数据拆分成若干个小的批处理并发的发送至Ingester进行下一步处理。
拆分成若干个小的批处理的过程,可以很容易的想到这块的处理是任务的分发FAN-OUT模式:

在Distributor中有个replication_factor配置,通常配置为3。其表示向Ingester写数据的因子,至少向(replication_factor/2)+1个Ingester写入某个批处理才看做这个批处理写入成功。否则认为写失败,会向其他的Ingester副本进行重试写入。这样尽可能地保障了数据不会丢失。
Ingester
Ingester
Ingester负责将日志数据写入持久化存储,Loki支持S3对象存储,单副本模式也支持文件存储(不推荐)。Ingester同时也为查询提供数据缓存。
在Ingester的Hash ring中维护了各个Ingester实例的状态,Ingester一个有以下五种状态:
PENDING:表示正在等其他LEVING状态的Ingester向其传送数据。
JOINING:表示该实例正在插入Hash ring并且初始化当前实例。
ACTIVE:当完成初始化后,状态转化为ACTIVE,此时该实例正常提供读写功能。
LEVING:表示实例正在关闭,仅提供在缓存中的数据进行查询,将未持久化的数据发送给其他伙伴进行处理。
UNHEALTHY:表示异常状态,未能正确上报心跳。
Distributor会向多个Ingester发送同一份数据进行冗余写操作,和LEVING状态的副本将数据发送给其他的伙伴这两个过程尽可能的降低了日志丢失的风险。
Ingester对拆分的chunk会根据租户信息、labels、日志内容进行hash后决定写入的位置,对于同一份数据hash的结果是一样的,所以不用担心数据会被存储多份。
Loki是默认开启accept out-of-order writes配置的,如果关闭这个配置,Ingester只会将日志流按照日期排序,且之后接收按照预期排序的数据,对于久远的数据将会拒绝接收,同时返回异常错误给用户。
Query frontend
query frontend是一个可选的服务,用来优化对querier的查询。query frontend会将大的查询拆分成若干个小的查询并发的供querier正在的执行查询。
拆分后的小的查询或者用户的请求将会放入query frontend内部维护的队列,所以在Querier的配置中需要配置query frontend访问地址(-querier.frontend-address ),这样Querier可以读取到队列中的请求。
同时query frontend会对查询的数据进行缓存,供后续相同的查询重复利用。
Querier
真正执行LogQL查询的组件,从Ingester或者持久化存储中查询数据。
在上面我们有介绍Distributor会向多个Ingester发送同一份数据,那么Querier就可能从多个Ingester实例中查询到重复数据,Querier会通过删除具有相同纳秒时间戳、标签集和日志消息的重复数据来解决这个问题。
在本节对Loki各组件进行了介绍,了解了Loki如何处理日志的写入和查询。下一节将会带领大家使用Loki搭建完整的日志平台。
往期回顾:
Grafana全家桶(四)链路跟踪Demo-Go代码集成opentelemetry SDK
Grafana全家桶(三)使用Grafana Agent与Tempo实现链路追踪完整demo
Grafana全家桶(二)链路跟踪Grafana Tempo的介绍和部署




