来自Grafana Labs的云原生日志解决方案之 Loki
Loki是一个开源的日志聚合系统,其提供对日志信息的收集、存储、以及查询等功能,和其它日志存储(如ElasticSearch)不同的是,Loki主要将日志数据以标签(labels)分流,按时间分块保存在对象存储而非本地硬盘中,并且,Loki只会对日志信息的元数据(即由标签所组合的日志流及其时间区间)进行索引,而非对全文进行索引。
这是一种非常聪明的设计,因为日志数据有两个非常重要的特点:
- 日志数据本质上和指标数据类似,是一种时序数据——数据按时间顺序排列,我们查询时,总是在对某个特定时间区间内的信息进行检索
- 日志数据是不可变的,只会追加新的数据而不会对旧数据进行修改 这两个特点使得Loki可以相对于主要面向全文检索场景的ElasticSearch,对日志场景做出更深入更激进的优化,比如能够建立更少的索引,以及建立更有效的缓存等。
Loki是如何工作的
Loki的架构和之前所介绍的Cortex项目非常相似,都是由distributor、ingester、querier等组件构成,其行为也基本一样,实际上后面准备介绍的分布式追踪项目Tempo也是使用的这种设计,毕竟这些项目所解决的问题高度相似,都是对时序的遥测数据进行收集、处理、存储和查询。
日志数据首先被发送给distributor, distributor对数据进行检查和校验后,将数据分批并行地发送到多个ingester,ingester会将日志数据上传到所配置的对象存储中,并且在保存缓存在本地。
查询时,需要使用Loki专用的查询语言——LogQL——进行查询,querier组件负责LogQL查询语句的执行,同时从ingester以及后端对象存储中拉取数据进行查询。
另外,一个可选的query frontend组件可以用来建立一个额外的查询层面,其可以将查询命令按时间分片放入查询队列按调度交由多个queriers并行执行,这样一方面提高了查询的效率,另一方面也避免由于某些比较高成本的查询命令导致内存不足等。
此外,ruler组件可以像Prometheus一样,配置规则从日志流中生成指标数据和报警信息,报警信息可以直接发到alertmanager进行管理和通知。
对于日志数据,Loki将其按日志上的标签信息进行分流,然后按其时间进行分块保存成文件在对象存储中,比如这么一条日志:
labels: {cluster="prod",app="meetingsvc", pod="...", namespace="...", ...}
message: "Order 123 processed"
timestamp: 1644926567933944082
Loki会将其完整的标签信息{cluster="prod",app="meetingsvc", pod="...", namespace="...", ...}
进行哈希,得到其所属的日志流id为fc98wz37
,这条日志会连同这个日志流其它同时间区间内的日志被打包成一个文件上传到对象存储,并对其标签建立索引。
查询时,需要使用这样的LogQL语句:
{app="meetingsvc", cluster="prod" } |= "Order 123"
语句前半部分{app="meetingsvc", cluster="prod"}
为标签过滤条件,后半部分|= "Order 123"
是对文本进行检索,查询时,Loki首先根据查询语句中的标签条件通过索引找到对应的日志流id,并将此日志流在指定时间内的所有文件都拉取到本地,然后遍历所有文件的内容,根据条件进行检索。
可以看到,在这种工作方式下,日志的标签需要谨慎地设计,因为标签值的每一种组合都会产生额外的一个独立日志流,因此要避免以诸如OrderId
等数据作为标签之一。
这种“把大块数据拉到本地然后进行遍历查找”的做法,乍一看可能很危险,但是回顾最开始我们说的日志数据的两个特点,就会发现,在正常的使用场景中,日志的查询只会触及特定流的特定时间区间,所以只会下载和遍历有限大小的文件块,而且当一个时间区间的所有日志都被打包上传后,这个文件块就不会再被更新了,因此所有对此文件块所建立的缓存都不会失效(Loki目前对于日志查询的缓存还在积极开发中,只有部分实现)。
Loki的主要优势
- 得益于Loki专门面向日志数据的设计,它大大降低了对数据的索引,其存储成本和使用成本都能够显著降低
- Loki将日志数据存储在对象存储中,可以利用上云服务中对象存储的可扩展性和可靠性
- 部署维护都相对较为简单
- 可以横向扩展,包括对其各个组件单独进行伸缩
- 相对于一些商用日志产品,Loki是面向云原生的,利用公共云或者私有云或者混合云上的基本的块存储和对象存储服务,就可以轻松地完整建设出一整套供应商中立的日志系统
- 内建多租户支持
- 由于是Grafana自家项目,Grafana里有着原生的Loki组件和面板
PLG技术栈
与由ElasticSearch、Fluentd、Kibana组成的EFK技术栈类似,Loki也有由Promtail、Loki、Grafana组成的PLG技术栈,其中Promtail是一个类似Fluentd的对日志进行采集、处理和转发的代理,与Fluentd不同的是,Promtail是为Kubernetes和Loki专门设计的,其只能对Kubernetes中的容器日志文件进行采集,并且自动关联相关Pod的labels作为日志消息的标签。
不过Promtail并不是Loki的唯一选择,Loki也支持Fluentd、Logstash等其它转发器。
在Grafana dashboard中,内置有原生的Loki组件,添加Loki作为数据源后,即可在Explore页面进行自定义查询:
也可以创建特定的面板来根据配置的LogQL展示日志信息:
最后
总体来说,Loki的设计和行为都和Cortex高度一致,其对待日志数据的方式也和Prometheus相似,正如其介绍中的那样:“Like prometheus, but for logs”,原因上面也说过了,日志数据和其它遥测数据一样,都是时序性的,正是基于这样的设计和架构,在不丢失功能和性能的前提下,得以将日志数据保存在更低成本更高可扩展性更易于管理的对象存储中。
就我目前使用Loki的体验来说,其整体上已经基本成熟完备了,只是在某些较为边缘的功能上还有所缺乏,偶尔也会出一些小问题,不过得益于其积极的开发者们和活跃的开源社区都得到了较好的解决,加上其相对较低的维护难度和使用条件以及成本,和其可扩展性,无论场景规模大小,都可以说是一个非常优秀的云原生日志解决方案。