云原生轻量级日志神器之Loki
一 背景
1.1 需求
随着云原生技术的发展,传统的日志解决方案面临着新的挑战。日志量剧增、数据结构复杂、实时分析需求等都对传统的日志服务提出了更高的要求。Loki作为一款新兴的云原生日志聚合系统,凭借其高可扩展性、低成本和易用性,越来越受到业界的关注。京东智联云,作为国内领先的云服务提供商,也正在将云翼的日志服务底层逐步从ES替换为Loki。 本文将基于京东智联云对Loki的使用和理解,从其产生的背景、解决的问题、采用的方案、系统架构、实现逻辑等方面进行剖析,希望对关注Loki的小伙伴们提供一些帮助。
1.2 loki简介
Loki 是一个受 Prometheus 启发的水平可伸缩的、高可用的、多租户的日志聚合系统。它的设计非常具有成本效益和易于操作。它不索引日志的内容,而是索引每个日志流的一组标签。
1.3 痛点
传统日志解决方案,如基于ES的日志服务,在面对云原生环境下的海量日志数据时,面临着以下问题:
- 成本高昂: ES作为一款功能强大的搜索引擎,在存储和查询日志数据时,需要大量的硬件资源,导致成本高昂。
- 可扩展性不足: ES的扩展性受限于集群规模和节点数量,难以满足快速增长的日志数据需求。
- 查询效率低: ES的查询效率会随着数据量和查询复杂度而下降,难以满足实时分析需求。
二 特点
2.1 Loki特点
Loki采用了一种独特的方法,只对元数据而不是日志行的全文进行索引:
Loki的最小索引方法意味着在Loki中存储相同的日志集所需的存储量远低于其他解决方案
- 非常容易上手,因为您可以使用广泛的客户机阵列,从任何来源以任何格式发送日志
- 构建度量标准并从日志行生成警报
- 对对象存储的100%持久化意味着您可以获得Pabyte规模、高吞吐量和经济高效的持久存储
- 没有摄取日志格式化要求,为您提供了更大的灵活性和在查询时格式化的选项
- 实时跟踪您的日志,以查看进入系统的日志,每隔一段时间更新日志,查看特定日期的日志,等等。
- 与Prometheus、Grafana和K8s原生集成,因此您可以在单个UI中无缝地在度量、日志和跟踪之间移动
2.2 Loki与其他系统对比
- 不会对日志进行全文索引。通过存储压缩的、非结构化的日志,只索引元数据,Loki 操作更简单,运行成本也更低。
- 索引和组日志流使用与 Prometheus 相同的标签,使您能够使用与 Prometheus 相同的标签在度量和日志之间无缝切换。
- 是一个特别适合存储库伯尼特斯 Pod 原木。像 Pod 标签这样的元数据会被自动刮取并编入索引。
- 在 Grafana 得到了本地支持(需要 Grafana v6.0)。
2.3 loki的组件
- Distributor(分发器)
Distributor负责处理客户端请求,也就是将日志数据写入到指定路径之前,先要经过Distributor。Distributor会验证客户端输入流的合法性和正确性,确保传入的用户是合法的租户。然后将每一个chunk(块)拆分成多个批次,并行发送到多个ingester(摄取器中)
- Ingester(摄取器)
Ingester摄取器负责将接收到的日志数据写入到 Storage Backend中(可以是S3、Cassandra或者本地文件系统中),并负责将日志数据读取到内存中供外部查询。
- [可选]Query fronted(查询前端)
查询前端是可选的组件,它提供了一个日志数据查询的API端口。如果Loki部署了Query fronted组件,那么客户端会将查询发送给Query fronted,而不发给Querier(查询器)。而查询前端还是要将查询交给Querier(查询器)执行查询的。
- Querier(查询器)
Querier组件用于接收LogQL语言进行日志数据查询,它会同时从Ingester组件以及后端存储中查询日志。
- Chunk Store(块存储)
Chunk Store是用于长期存储Loki日志的存储,并要求块存储能够支持交互式查询和持续写入。Loki支持的chunk store有:Amazon DynamoDB/Google BigTable/Apache Cassandra/Amazon S3/Google Cloud Storage
Chunk Store并不是单独的服务,而是以库的形式提供(在Ingester和Querier使用到)
2.4 原理
Loki 类似于 Prometheus,但是对于日志: 我们更喜欢使用基于多维标签的索引方法,并且希望使用单一二进制文件,操作起来很方便,没有依赖关系。洛基与普罗米修斯不同,他们更关注日志而不是度量,通过推送而不是拉送日志。
用Promtail拉入任何源日志:Promtail是专门为Loki构建的日志收集器。它使用与Prometheus相同的服务发现,并包括类似的特性,用于在将日志输入到Loki之前对日志进行标记、转换和过滤。
将日志存储在Loki中:Loki不对日志的文本进行索引。取而代之的是,条目被分组到流中,并用标签进行索引。这不仅降低了成本,还意味着日志行可以在Loki收到后的毫秒内查询。
使用LogQL来暴露:使用Loki强大的查询语言LogQL来查看日志。直接在Grafana中运行LogQL查询,以便将日志与其他数据源一起可视化,或者使用LogCLI来可视化,以便那些喜欢命令行体验的人使用。
日志上的警报:为Loki设置警报规则,以便对传入的日志数据进行评估。配置Loki将生成的警报发送到Prometheus Alertmanager,以便将它们路由到正确的团队。
2.5 Loki的架构与实现
Loki的系统架构主要由以下几个组件构成:
- Promtail: 负责从各种来源收集日志数据,并将其转发到Loki服务器。
- Loki服务器: 负责存储和索引日志数据,并提供查询接口。
- Grafana: 可视化工具,用于展示和分析Loki中的日志数据。
Loki的实现逻辑可以概括为以下几个步骤:
- 日志采集: Promtail从应用、容器等来源收集日志数据,并将数据以文本格式存储在本地磁盘。
- 数据传输: Promtail将收集的日志数据压缩并传输到Loki服务器。
- 数据存储: Loki服务器将日志数据存储在分布式存储系统中,并使用索引结构来提高查询效率。
- 日志查询: 用户可以通过PromQL查询语言,对Loki中的日志数据进行筛选、聚合、排序等操作。
- 可视化展示: Grafana可以将Loki中的日志数据以图表、表格等形式展现出来,方便用户分析和理解。
三 部署
3.1 安装Loki
3.1.1 利用helm安装loki
helm repo add loki https://grafana.github.io/loki/charts
helm repo update
# 通过存储类部署
[root@master ~]# helm upgrade --install loki --namespace=loki loki/loki-stack --set grafana.enabled=true,prometheus.enabled=true,prometheus.alertmanager.persistentVolume.enabled=false,prometheus.server.persistentVolume.enabled=false,loki.persistence.enabled=true,loki.persistence.storageClassName=rbd,loki.persistence.size=5Gi
Release "loki" does not exist. Installing it now.
NAME: loki
LAST DEPLOYED: Fri Dec 18 15:33:33 2020
NAMESPACE: loki
STATUS: DEPLOYED
RESOURCES:
==> v1/ClusterRole
NAME AGE
loki-grafana-clusterrole 2s
loki-prometheus-alertmanager 2s
loki-prometheus-pushgateway 2s
loki-prometheus-server 2s
loki-promtail-clusterrole 2s
==> v1/ClusterRoleBinding
NAME AGE
loki-grafana-clusterrolebinding 2s
loki-prometheus-alertmanager 2s
loki-prometheus-pushgateway 2s
loki-prometheus-server 2s
loki-promtail-clusterrolebinding 2s
==> v1/ConfigMap
NAME DATA AGE
loki-grafana 1 1s
loki-grafana-test 1 1s
loki-loki-stack 1 1s
loki-loki-stack-test 1 1s
loki-prometheus-alertmanager 1 1s
loki-prometheus-server 5 1s
loki-promtail 1 1s
==> v1/DaemonSet
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
loki-prometheus-node-exporter 4 4 0 4 0 <none> 1s
loki-promtail 4 4 0 4 0 <none> 1s
==> v1/Deployment
NAME READY UP-TO-DATE AVAILABLE AGE
loki-grafana 0/1 1 0 1s
loki-kube-state-metrics 0/1 1 0 1s
loki-prometheus-alertmanager 0/1 1 0 1s
loki-prometheus-pushgateway 0/1 1 0 1s
loki-prometheus-server 0/1 1 0 1s
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
loki-0 0/1 Pending 0 2s
loki-0 0/1 Pending 0 2s
loki-0 0/1 Pending 0 2s
loki-0 0/1 Pending 0 2s
loki-0 0/1 Pending 0 2s
loki-0 0/1 Pending 0 2s
loki-0 0/1 Pending 0 2s
loki-0 0/1 Pending 0 2s
==> v1/Role
NAME AGE
loki 2s
loki-grafana-test 2s
loki-promtail 2s
==> v1/RoleBinding
NAME AGE
loki 2s
loki-grafana-test 2s
loki-promtail 2s
==> v1/Secret
NAME TYPE DATA AGE
loki Opaque 1 1s
loki-grafana Opaque 3 1s
==> v1/Service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
loki ClusterIP 10.233.35.11 <none> 3100/TCP 1s
loki-grafana ClusterIP 10.233.55.139 <none> 80/TCP 1s
loki-headless ClusterIP None <none> 3100/TCP 1s
loki-kube-state-metrics ClusterIP 10.233.17.40 <none> 8080/TCP 1s
loki-prometheus-alertmanager ClusterIP 10.233.26.110 <none> 80/TCP 1s
loki-prometheus-node-exporter ClusterIP None <none> 9100/TCP 1s
loki-prometheus-pushgateway ClusterIP 10.233.25.28 <none> 9091/TCP 1s
loki-prometheus-server ClusterIP 10.233.46.145 <none> 80/TCP 1s
==> v1/ServiceAccount
NAME SECRETS AGE
loki 1 1s
loki-grafana 1 1s
loki-grafana-test 1 1s
loki-kube-state-metrics 1 1s
loki-prometheus-alertmanager 1 1s
loki-prometheus-node-exporter 1 1s
loki-prometheus-pushgateway 1 1s
loki-prometheus-server 1 1s
loki-promtail 1 1s
==> v1/StatefulSet
NAME READY AGE
loki 0/1 1s
==> v1beta1/ClusterRole
NAME AGE
loki-kube-state-metrics 2s
==> v1beta1/ClusterRoleBinding
NAME AGE
loki-kube-state-metrics 2s
==> v1beta1/PodSecurityPolicy
NAME PRIV CAPS SELINUX RUNASUSER FSGROUP SUPGROUP READONLYROOTFS VOLUMES
loki false RunAsAny MustRunAsNonRoot MustRunAs MustRunAs true configMap,emptyDir,persistentVolumeClaim,secret,projected,downwardAPI
loki-grafana false RunAsAny RunAsAny RunAsAny RunAsAny false configMap,emptyDir,projected,secret,downwardAPI,persistentVolumeClaim
loki-grafana-test false RunAsAny RunAsAny RunAsAny RunAsAny false configMap,downwardAPI,emptyDir,projected,secret
loki-promtail false RunAsAny RunAsAny RunAsAny RunAsAny true secret,configMap,hostPath,projected,downwardAPI,emptyDir
==> v1beta1/Role
NAME AGE
loki-grafana 2s
==> v1beta1/RoleBinding
NAME AGE
loki-grafana 2s
NOTES:
The Loki stack has been deployed to your cluster. Loki can now be added as a datasource in Grafana.
See http://docs.grafana.org/features/datasources/loki/ for more detail.
部署完成
xuel@kaliarchmacbookpro ~ master k get all -n loki
NAME READY STATUS RESTARTS AGE
pod/loki-0 1/1 Running 0 116m
pod/loki-grafana-9c55b4589-mkvrh 1/1 Running 0 116m
pod/loki-kube-state-metrics-7f9f667d7d-k9ctr 1/1 Running 0 116m
pod/loki-prometheus-alertmanager-9bb4c6f8f-t6vbk 2/2 Running 0 116m
pod/loki-prometheus-node-exporter-lcj2v 1/1 Running 0 116m
pod/loki-prometheus-pushgateway-664fd45795-5lz6f 1/1 Running 0 116m
pod/loki-prometheus-server-5d6f9d5c6c-25cfx 2/2 Running 0 116m
pod/loki-promtail-ndvzg 1/1 Running 0 116m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/loki ClusterIP 10.96.196.180 <none> 3100/TCP 116m
service/loki-grafana ClusterIP 10.96.106.18 <none> 80/TCP 116m
service/loki-headless ClusterIP None <none> 3100/TCP 116m
service/loki-kube-state-metrics ClusterIP 10.96.171.19 <none> 8080/TCP 116m
service/loki-prometheus-alertmanager ClusterIP 10.96.184.187 <none> 80/TCP 116m
service/loki-prometheus-node-exporter ClusterIP None <none> 9100/TCP 116m
service/loki-prometheus-pushgateway ClusterIP 10.96.128.101 <none> 9091/TCP 116m
service/loki-prometheus-server ClusterIP 10.96.41.33 <none> 80/TCP 116m
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/loki-prometheus-node-exporter 1 1 1 1 1 <none> 116m
daemonset.apps/loki-promtail 1 1 1 1 1 <none> 116m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/loki-grafana 1/1 1 1 116m
deployment.apps/loki-kube-state-metrics 1/1 1 1 116m
deployment.apps/loki-prometheus-alertmanager 1/1 1 1 116m
deployment.apps/loki-prometheus-pushgateway 1/1 1 1 116m
deployment.apps/loki-prometheus-server 1/1 1 1 116m
NAME DESIRED CURRENT READY AGE
replicaset.apps/loki-grafana-9c55b4589 1 1 1 116m
replicaset.apps/loki-kube-state-metrics-7f9f667d7d 1 1 1 116m
replicaset.apps/loki-prometheus-alertmanager-9bb4c6f8f 1 1 1 116m
replicaset.apps/loki-prometheus-pushgateway-664fd45795 1 1 1 116m
replicaset.apps/loki-prometheus-server-5d6f9d5c6c 1 1 1 116m
NAME READY AGE
statefulset.apps/loki 1/1 116m
查看服务
3.2 访问
由于在本地测试,临时使用port-forward,线上环境可改为Lb或Nodeport
k port-forward -n loki --address 0.0.0.0 svc/loki-grafana 80:80
查看登录密码
kubectl get secret --namespace loki loki-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
- 数据源已经添加好
四 使用
去重日志
实时查看
可以查看查询历史,或starred 历史,方便后期查询
五 配置日志采集
loki 日志采集使用的promtail,
k get cm -n loki loki-promtail -oyaml
其中对静态Pod/业务Pod/直接控制器Pod和非直接控制器Pod都有对应的日志收集配置。
六 日志选择与过滤
6.1、日志选择器
对于查询表达式的标签部分,将其用大括号括起来{},然后使用键值语法选择标签。多个标签表达式用逗号分隔:
{app="mysql",name="mysql-backup"}
当前支持以下标签匹配运算符:
- = 完全相等。
- != 不相等。
- =~ 正则表达式匹配。
- !~ 不进行正则表达式匹配。
例子:
{name=~"mysql.+"}
{name!~"mysql.+"}
6.2、日志过滤器
编写日志流选择器后,您可以通过编写搜索表达式来进一步过滤结果。搜索表达式可以只是文本或正则表达式。 查询示例:
{job="mysql"} |= "error"
{name="kafka"} |~ "tsdb-ops.*io:2003"
{instance=~"kafka-[23]",name="kafka"} != kafka.server:type=ReplicaManager
过滤器运算符可以被链接,并将顺序过滤表达式-结果日志行将满足每个过滤器。例如:
{job="mysql"} |= "error" != "timeout"
已实现以下过滤器类型:
- |= 行包含字符串。
- != 行不包含字符串。
- |~ 行匹配正则表达式。
- !~ 行与正则表达式不匹配。 regex表达式接受RE2语法。默认情况下,匹配项区分大小写,并且可以将regex切换为不区分大小写的前缀(?i)。
注意事项
- 数据格式: Loki 主要使用 Promtail 采集日志,并以 文本格式 进行存储。确保您的日志格式符合 Loki 的要求,可以使用 promtail-client 工具进行测试。
- 数据量: Loki 擅长处理大量日志数据,但仍需注意存储和查询性能。对于超大规模的日志,可以考虑使用数据压缩、数据切片等优化策略。
- 日志查询: Loki 使用 PromQL 语法进行日志查询,这与 Prometheus 的监控查询语言相同。熟悉 PromQL 是高效使用 Loki 的前提。
- 安全性: Loki 支持多种身份验证和授权机制,可以有效保护日志数据安全。注意配置相关安全策略,并定期进行安全审计。
- 日志保留策略: 设置合理的日志保留策略,确保日志数据既能满足您的需求,又不造成存储空间浪费。
- 日志可视化: Loki 提供丰富的可视化工具,可以帮助您直观地分析日志数据。选择合适的可视化工具,并根据您的需求进行配置。
- 与其他工具整合: Loki 可以与其他云原生工具,如 Prometheus、Grafana 等进行整合,实现更加强大的日志分析和监控功能。
总结
Loki 是一款强大的云原生日志聚合系统,可以帮助您高效地收集、存储、查询和分析日志数据。但在使用 Loki 时,需注意数据格式、数据量、日志查询、安全性、日志保留策略、日志可视化以及与其他工具的整合等方面,才能充分发挥 Loki 的优势。
参考链接
- 点赞
- 收藏
- 关注作者
评论(0)