Z.S.K.'s Records

Grafana学习(Loki日志系统初试)

基于kubernetes为容器平台的业种中, 对于日志的收集,使用最多的是FEK, 不过有时候,FEK在架构上会略显重, ES的查询及全文检索功能其实使用的不是很多.LoKi做为日志架构的新面孔, 由grafana开源, 使用了与Prometheus同样的label理念, 同时摒弃了全文检索的能力, 因此比较轻便, 非常具有潜力

like Prometheus, but for logs

Loki是 Grafana Labs 团队最新的开源项目,是一个水平可扩展,高可用性,多租户的日志聚合系统。它的设计非常经济高效且易于操作,因为它不会为日志内容编制索引,而是为每个日志流编制一组标签。项目受 Prometheus 启发,官方的介绍就是:Like Prometheus, but for logs,类似于 Prometheus 的日志系统

与其他日志聚合系统相比,Loki具有下面的一些特性:

  • 不对日志进行全文索引。通过存储压缩非结构化日志和仅索引元数据,Loki 操作起来会更简单,更省成本。
  • 通过使用与 Prometheus 相同的标签记录流对日志进行索引和分组,这使得日志的扩展和操作效率更高。
  • 特别适合储存 Kubernetes Pod 日志; 诸如 Pod 标签之类的元数据会被自动删除和编入索引。
  • 受 Grafana 原生支持。

Loki 由以下3个部分组成:

  • loki是主服务器,负责存储日志和处理查询。
  • promtail是代理,负责收集日志并将其发送给 loki,当然也支持其它的收集端如fluentd等
  • Grafana用于 UI 展示

同时Loki也提示了command line工具,通过这个工具可以使用http的方式与loki进行交互,这个后面说

架构

安装

官方提供了多种的部署方式, 这里选择使用helm, 如果只是想试用的话则非常简单, 直接参考helm即可run起来,这里就不做搬运工了

1
2
3
helm repo add loki https://grafana.github.io/loki/charts
helm repo update
helm upgrade --install loki loki/loki-stack

配置

对于loki来说,loki端的配置相对来说会比较简单, 采集端由于可以使用pipeline, 因此会稍复杂点,但是如果接触过prometheus,那其它会觉得还是挺情切.

先来看服务端loki的配置

loki.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
auth_enabled: false
chunk_store_config:
max_look_back_period: 0s
ingester:
chunk_block_size: 262144
chunk_idle_period: 3m
chunk_retain_period: 1m
lifecycler:
ring:
kvstore:
store: inmemory
replication_factor: 1
max_transfer_retries: 0
limits_config:
enforce_metric_name: false
reject_old_samples: true
reject_old_samples_max_age: 168h
schema_config:
configs:
- from: "2018-04-15"
index:
period: 168h
prefix: index_
object_store: filesystem
schema: v9
store: boltdb
server:
http_listen_port: 3100
storage_config:
boltdb:
directory: /data/loki/index
filesystem:
directory: /data/loki/chunks
table_manager:
retention_deletes_enabled: false
retention_period: 0s

loki服务端主要定义了数据到达控制面之后的一些策略, 比如ingester size大小, 存储路径等的信息,最好使用SSD.

再看看采集端配置

promtail

prometail同时充当服务端及客户端

server
1
2
server:
http_listen_port: 3101

promtail做为服务端, 可同时提供http及grpc能力,而需要进行数据发送到loki时,promtail则为客户端

client
1
2
3
4
5
6
7
8
9
10
client:
url: http://loki:3100/loki/api/v1/push
backoff_config:
max_period: 5s
max_retries: 20
min_period: 100ms
batchsize: 102400
batchwait: 1s
external_labels: {}
timeout: 10s

当做为client时, promtail做为日志的收集端,然后发送到loki实例

backoff_config 参数指定了当发送日志到loki实例失败时采取的重试策略

external_labels则可以在所有的日志发送到loki实例前加入k-v的labels.

1
2
3
4
5
# WARNING: If one of the remote Loki servers fails to respond or responds
# with any error which is retryable, this will impact sending logs to any
# other configured remote Loki servers. Sending is done on a single thread!
# It is generally recommended to run multiple promtail clients in parallel
# if you want to send to multiple remote Loki instances.

target_config

控制从发现的日志文件中读取行为,比如多久读取一次

1
2
target_config:
sync_period: 10s

scrape_configs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
scrape_configs:
- job_name: kubernetes-pods-name
pipeline_stages:
- docker: {}
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels:
- __meta_kubernetes_pod_label_name
target_label: __service__
- source_labels:
- __meta_kubernetes_pod_node_name
target_label: __host__
- action: drop
regex: ''
source_labels:
- __service__
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- action: replace
replacement: $1
separator: /
source_labels:
- __meta_kubernetes_namespace
- __service__
target_label: job
- action: replace
source_labels:
- __meta_kubernetes_namespace
target_label: namespace
- action: replace
source_labels:
- __meta_kubernetes_pod_name
target_label: pod
- action: replace
source_labels:
- __meta_kubernetes_pod_container_name
target_label: container
- replacement: /var/log/pods/*$1/*.log
separator: /
source_labels:
- __meta_kubernetes_pod_uid
- __meta_kubernetes_pod_container_name
target_label: __path__

上面是最重要的一个配置, 会发现跟prometheus的配置文件很像, 这里不对上述配置语法进行细说, 感兴趣的可以参考prometheus文档, 这里使用了跟prometheus相同的服务发现机制, 同时也是基于lable进行一系列的增删改的操作, 最终实现一条日志上存在多个label,我们可以基于这些label来查询日志

这个是直接使用官方提供的example, 可以根据实际情况进行修改.

pipeline

可以看到上面的配置中出现一个pipeline的选项,这个是用于指定采集到日志后可以进行的操作, 以stage为单位, 目前支持4种stage.

  1. 解析阶段:解析当前日志行并从中提取数据。然后,提取的数据可供其他阶段使用。
  2. 转换阶段:转换从先前阶段提取的数据。
  3. 行动阶段:从先前阶段中提取数据并对其进行处理。在日志行中添加或修改现有标签 更改日志行的时间戳 更改日志行的内容 根据提取的数据创建指标等
  4. 筛选阶段:可以根据某些条件选择应用阶段的子集或丢弃条目

同时每个stage又有一些预设的可直接供使用的操作.

比如上面指定的docker,就属于解析阶段, 它的作用是通过使用标准Docker格式解析日志行来提取数据

这对于直接将应用日志输出到console,然后通过docker的格式打印出来的情况下非常方便. 这也是最常见场景

官方的说明

使用

  1. 选择数据源

  1. 填写URL

  1. 切换到Explore --> 选择Loki

Log labels下拉框中可以下拉选择通过上述服务发现生成的的日志labels, 中间则可以使用label语法进行筛选

1
{app="ingress-nginx", pod="nginx-ingress-controller-fm24n"} |="error"

前半部分很好理解, 后面的|="error"则是在前半部分筛选出来的结果中再次grep出存在error的日志

这里使用的是LogQL语法, 见下文

  1. 添加dashboard

LogQL

Loki 使用一种称为 LogQL 的语法来进行日志检索,语法类似 PromQL

Log Stream Selector

也是使用大括号进行条件的筛选, 同时支持正则

1
{app="mysql",name=~"mysql-backup.+"}
  • =: exactly equal.
  • !=: not equal.
  • =~: regex matches.
  • !~: regex does not match.

Filter Expression

1
{instance=~"kafka-[23]",name="kafka"} != "kafka.server:type=ReplicaManager"
  • |=: Log line contains string.
  • !=: Log line does not contain string.
  • |~: Log line matches regular expression.
  • !~: Log line does not match regular expression.

Metric Queries

这个其实就跟prometheus中的很想像了.

1
rate({job="mysql"} |= "error" != "timeout" [5m])
  • rate: calculates the number of entries per second
  • count_over_time: counts the entries for each log stream within the given range.
  • bytes_rate: calculates the number of bytes per second for each stream.
  • bytes_over_time: counts the amount of bytes used by each log stream for a given range.

Aggregation operators

当然还支持一些聚合操作,比如

1
avg(rate(({job="nginx"} |= "GET")[10s])) by (region)
  • sum: Calculate sum over labels
  • min: Select minimum over labels
  • max: Select maximum over labels
  • avg: Calculate the average over labels
  • stddev: Calculate the population standard deviation over labels
  • stdvar: Calculate the population standard variance over labels
  • count: Count number of elements in the vector
  • bottomk: Select smallest k elements by sample value
  • topk: Select largest k elements by sample value

还有很多比如’and, or’的操作都是支持, 就不一一搬运了

logcli

logcli做为一个命令行工具, 可以直接与loki进行交互, 目前grafana是不支持对loki进行告警, 可以通过logcli写脚本的方式进行,也是种办法

性能

要知道es产生的索引可能跟日志本身一样大, loki最大的特点就是同一类型的日志带有相同的label,这样的话产生的索引就会压缩几个数量级,这就不需要像es查询一样将索引放入内存中, 从而可以使内存加载更大的日志量, 另一方面, loki实现了类型于分布式的grep,会将查询分解成较小的shard并行处理, 因为不需要全文检索,因此速度上会更快.

关于性能方面也局限于官方的说法, 还没有做过性能测试,目前还没有在生产上使用loki, 但是在QA/DEV环境中使用,体验还是不错的, 不用在grafana/kibana来回切换了.

参考文章:

转载请注明出处https://izsk.me

Z.S.K. wechat
Scan Me To Read on Phone
I know you won't do this,but what if you did?