PLG= Promtail+Loki+Grafana

Promtail: 代理,负责收集日志并将其发送给 loki

Loki: 日志记录引擎,负责存储日志和处理查询

Grafana: UI 界面

PLG 的官方介绍可参考:https://grafana.com/docs/loki/latest/overview/

Loki 和常用的 EFK(Elasticsearch + Filebeat + Kibana)日志采集方案类似,基本架构都是在应用节点有代理进程(Promtail)收集日志,传输到集中化的服务(Loki)存储和索引,最后通过图形化界面(Grafana)统一查询。

Loki 与 EFK 的区别

参考链接1官方

参考链接2私人博主

ELK 存在的问题

使用 ELK 会导致运维同学在使用时,通过监控报警查询日志,需要频繁的在监控平台和 kibana 之间切换,影响用户体验。所以 loki 的第一目的就是最小化度量和日志的切换成本,有助于减少异常事件的响应时间和提高用户的体验。

优点是功能丰富,允许复杂的操作。但是,这些方案往往规模复杂,资源占用高,操作苦难。很多功能往往用不上,大多数查询只关注一定时间范围和一些简单的参数(如host、service等),使用这些解决方案就有点杀鸡用牛刀的感觉了。因此,Loki的第二个目的是,在查询语言的易操作性和复杂性之间可以达到一个权衡。

还有一点是关于检索的方案,ES 索引的切分成本较高,Loki 的第三个目的是为了提高更具成本效益的解决方案。

  1. Loki不会对原始的日志数据进行全文索引,而是采用了 Prometheus 的标签思想,只对标签索引
  2. 日志数据本身也会被压缩,并以chunks(块)的形式存储在对象存储或者本地文件系统
  3. Loki能够以微服务模式运行,也就是把自身的各个模块分解出单个进程运行。比如,通过横向扩展多个查询器(Querier)模块可提高查询性能。

这几点区别使Loki更加轻量和灵活,特别适合云原生环境。

运行模式

Loki 有一组组件(distributor,ingester,querier,query-frontend),它们在内部被称为模块。每个组件为内部流量生成一个 gRPC 服务器(用于组件之间调用),为外部 API 请求生成一个 HTTP/1 服务器。所有组件都带有一个 HTTP/1 服务器,但大多数只公开就绪、健康和指标端点。

Loki 运行哪个组件取决于命令行中的 -target 标志或 Loki 配置文件中的 target: <string> 部分。当 target 的值为 all 时,Loki 将在单个进程中运行其所有组件。这被称为“单进程”、“单二进制”或单片模式。当使用 Helm 安装 Loki 时,单体模式是 Loki 的默认部署。

target 未设置为 all(即被设置为 querieringesterquery-frontenddistributor)时,Loki 被称为以“水平可扩展”或微服务模式运行。

Loki 的每个组件,例如ingesterdistributor,都使用 Loki 配置中定义的 gRPC 侦听端口,通过 gRPC 相互通信。当以单体模式运行组件时,这仍然是正确的:每个组件虽然运行在同一进程中,但将通过本地网络相互连接以进行组件间通信。

单进程模式非常适合本地开发、小工作负载和评估目的。单片模式可以通过多个进程进行扩展,但有以下限制:

当运行具有多个副本的单体模式时,当前无法使用本地索引和本地存储,因为每个副本必须能够访问相同的存储后端,并且本地存储对于并发访问是不安全的。
单个组件无法独立扩展,因此读取组件不可能多于写入组件。

Loki 整体架构

本文仅仅简单介绍每个组件的主要工作,想要了解深入的组件工作方式请参考:

Loki 的模块:distributor,ingester,querier,query-frontend

Distributor

distributor 服务负责处理客户端写入的日志,它本质上是日志数据写入路径中的第一站,一旦 distributor 收到日志数据,会将其拆分为多个批次,然后并行发送给多个 ingester

distributor 通过 gRPC 与 ingester 通信,它们都是无状态的,可以根据需要扩大或缩小规模。

Igester

ingester 服务负责将日志数据写入长期存储后端(DynamoDB、S3、Cassandra 等)。此外 ingester 会验证摄取的日志行是按照时间戳递增的顺序接收的(即每条日志的时间戳都比前面的日志晚一些),当 ingester 收到不符合这个顺序的日志时,该日志行会被拒绝并返回一个错误。

query-frontend

查询前端是一个可选的服务,提供 querier 的 API 端点,可以用来加速读取路径。当查询前端就位时,应将传入的查询请求定向到查询前端,而不是 querier, 为了执行实际的查询,群集中仍需要 querier 服务。

Querier

Querier 查询器服务使用 LogQL 查询语言处理查询,从 ingesters 和长期存储中获取日志。

查询器查询所有 ingesters 的内存数据,然后再到后端存储运行相同的查询。由于复制因子,查询器有可能会收到重复的数据。为了解决这个问题,查询器在内部对具有相同纳秒时间戳、标签集和日志信息的数据进行重复数据删除。

1、promtail收集并将日志发送给loki的 Distributor 组件

2、Distributor会对接收到的日志流进行正确性校验,并将验证后的日志分批并行发送到Ingester(存储)

3、Ingester 接受日志流并构建数据块,压缩后存放到所连接的存储后端

4、Querier(查询器) 收到HTTP查询请求,并将请求发送至Ingester 用以获取内存数据 ,Ingester 收到请求后返回符合条件的数据 ;

5、如果 Ingester 没有返回数据,Querier 会从后端存储加载数据并遍历去重执行查询 ,通过HTTP返回查询结果

PLG部署

本文只做二进制部署的方式,以后需要其他方式再写新文章,部署之前请确认,每台服务器时区与时间是否一致

部署方式在官网有说明

下载链接,在链接中下载 loki-linux-amd64.zippromtail-linux-amd64.zip 的二进制文件

Host SoftWare OS
192.168.1.10 Promtail、Loki、Grafana CentOS 7.5
192.168.1.12 Promtail、nginx、mysql CentOS 7.5

Loki

下载二进制包

wget https://github.com/grafana/loki/releases/download/v2.3.0/loki-linux-amd64.zip -O /tmp/loki.zip

准备安装目录

mkdir -p /usr/local/loki && cd $_

解压二进制包

unzip /tmp/loki.zip -d /usr/local/loki
ln -s /usr/local/loki/loki-linux-amd64 /usr/bin/loki

下载配置文件

wget https://raw.githubusercontent.com/grafana/loki/master/cmd/loki/loki-local-config.yaml

启动命令:/usr/bin/loki -config.file /usr/local/loki/loki-local-config.yaml,该命令执行为前台运行,打断即停止服务。

这里不使用命令启动,会写脚本交给 systemctl 来管理

# 创建服务用户
useradd --system loki
# 创建loki.service文件
cat << EOF >> /etc/systemd/system/loki.service
[Unit]
Description=Loki service
After=network.target

[Service]
Type=simple
User=loki
ExecStart=/usr/bin/loki \
          -config.file /usr/local/loki/loki-local-config.yaml

[Install]
WantedBy=multi-user.target
EOF

使用 systemctl 启动服务

systemctl --now enable loki

使用命令 systemctl status loki,查看到服务没起来,查看 /var/log/messages 日志,报错信息为以下内容

Sep  7 17:19:56 localhost loki: failed parsing config: /usr/local/loki/loki-local-config.yaml: yaml: unmarshal errors:
Sep  7 17:19:56 localhost loki: line 50: field unordered_writes not found in type validation.plain

配置文件 /usr/local/loki/loki-local-config.yaml 第50行内容删除,重新启动即可

访问 http://192.168.1.10:3100/metrics,记得放行防火墙端口

Promtail

下载二进制包

wget https://github.com/grafana/loki/releases/download/v2.3.0/promtail-linux-amd64.zip -O /tmp/promtail.zip

准备安装目录

mkdir -p /usr/local/promtail && cd $_

解压二进制包

unzip /tmp/promtail.zip -d /usr/local/promtail/
ln -s /usr/local/promtail/promtail-linux-amd64 /usr/bin/promtail

下载配置文件

wget https://raw.githubusercontent.com/grafana/loki/main/clients/cmd/promtail/promtail-local-config.yaml

配置文件修改

PS:Pormtail 推送的日志目录,必须具有读取权限

$ vim /usr/local/promtail/promtail-local-config.yaml
server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml

clients:
  # 这里要修改为loki的ip以及对应端口
  - url: http://localhost:3100/loki/api/v1/push

scrape_configs:
- job_name: system
  static_configs:
  - targets:
      - localhost  # 代表收集promtail本机的日志目录
    labels:
      # 将会作为索引查询,除了"__path__"外,其他的"key: value"可以自定义
      app: "1.10-varlog"
      # 收集日志的目录
      __path__: /var/log/*log

日志授权

# 目录授权755
chmod 755 /var/log/
# 文件授权644
chmod 644 /var/log/*log
$ vim /usr/local/promtail/promtail-local-config.yaml
server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml

clients:
  - url: http://192.168.1.10:3100/loki/api/v1/push

scrape_configs:
- job_name: nginx
  static_configs:
  - targets:
      - localhost
    labels:
      job: "1.12-nginx"
      __path__: /var/log/nginx/*log

- job_name: db
  static_configs:
  - targets:
      - localhost
    labels:
      job: "1.12-mysql"
      __path__: /var/log/mysqld.log

日志授权

# 目录授权755
chmod 755 /var/log/nginx/ /var/log/
# 文件授权644
chmod 644 /var/log/nginx/*log /var/log/mysqld.log

启动命令:/usr/bin/promtail -config.file /usr/local/promtail/promtail-local-config.yaml

这里也不使用命令启动,同样交给 systemctl 来管理

# 创建promtail服务用户
useradd --system promtail
# 创建promtail.service文件
cat << EOF >> /etc/systemd/system/promtail.service
[Unit]
Description=Promtail service
After=network.target

[Service]
Type=simple
User=promtail
ExecStart=/usr/bin/promtail \
          -config.file /usr/local/promtail/promtail-local-config.yaml

[Install]
WantedBy=multi-user.target
EOF

使用 systemctl 启动服务

systemctl --now enable promtail

访问 http://192.168.1.12:9080http://192.168.1.10:9080

可以通过查看 /tmp/positions.yaml 文件来验证是否收集到需要的日志。

Grafana

配置 grafana 的 yum 源

cat << EOF >> /etc/yum.repos.d/grafana.repo
[grafana]
name=grafana
baseurl=https://packages.grafana.com/oss/rpm
repo_gpgcheck=1
enabled=1
gpgcheck=1
gpgkey=https://packages.grafana.com/gpg.key
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
EOF

安装 Grafana

yum -y install grafana

启动服务

systemctl --now enable grafana-server

Grafana 与 Loki 结合

访问 http://192.168.1.10:3000,默认用户密码为admin,登录后进行如下操作

添加数据源

loki-datasource

选择数据源为 loki

loki-loki

在URL处填写 Loki 的访问地址,点击下方 save & test

loki-loki-uri

查看日志

如果没有日志,稍微等几分钟,日志有一个推送的时间间隔

loki-export

loki_select

查询条件可以在下图的位置找到,不需要自己写,红框中的 app ,就是在 promtail 中定义的字段

loki_log_browser

示例:查看 nginx 日志,根据 app 的索引找到对应的 filename ,点击 show logs

loki_nginx_log

loki_nginx_log_result

报错解决

watcher closed

无法获取到日志文件,原因是权限问题,这个问题找了我好久,因为没有直接报权限的错误,需要给到日志所在目录 755 权限

msg="filetarget: watcher closed, tailer stopped, positions saved" path=/var/log/nginx/*log
msg="filetarget: watcher closed, tailer stopped, positions saved" path=/var/log/mariadb/mariadb.log

解决

chmod 755 /var/log/nginx
chmod 755 /var/log/mariadb

重启服务即可

permission denied

如果直接报这个权限问题,给日志文件644权限即可

level=debug ts=2019-11-25T10:28:54.257209775Z caller=filetarget.go:245 msg="watching new directory" directory=/var/log
level=error ts=2019-11-25T10:28:54.257677719Z caller=filetarget.go:247 msg="error adding directory to watcher" error="permission denied"

解决

chmod -R 644 [日志路径]

重启服务即可

推送日志到loki失败

服务没有报错的情况下,loki中也没有显示日志,确认当天是否有日志写入,在我的使用经验中发现,开始收集日志当天如果没有日志写入,loki中是不会显示的,即使你的日志文件能够看到之前的日志,但也是不会被收集的。具体可以查看 promtail 所在服务器的 positions ,默认路径是 /tmp/positions.yaml ,如下,尾部数字为 0 则不会在 grafana 界面显示

positions:
  /var/log/mysqld.log: "3368"
  /var/log/nginx/access.log: "187"
  /var/log/nginx/error.log: "0"

日志量大推送错误

当你搭建完成 promtail,并且启动发送日志到 loki 的时候很有可能会碰到这个错误,因为你要收集的日志太多了,超过了 loki 的限制,所以会报429。

level=warn ts=2021-09-13T07:00:13.558415458Z caller=client.go:344 component=client host=10.101.249.246:5654 msg="error sending batch, will retry" status=429 error="server returned HTTP status 429 Too Many Requests (429): Ingestion rate limit exceeded (limit: 4194304 bytes/sec) while attempting to ingest '10793' lines totaling '1048548' bytes, reduce log volume or contact your Loki administrator to see if the limit can be increased"

loki 配置文件添加 ingestion_rate_mb: 15,旧版添加 ingestion_rate: 25000

limits_config:
  reject_old_samples: true
  reject_old_samples_max_age: 168h
  # 每秒允许promtail传输32MB,默认为4
  ingestion_rate_mb: 32
  ingestion_burst_size_mb: 64

Loki API 查看日志

# 'query={job=""}': job后的引号内填写Pormtail配置文件中指定的job值
curl -G -s  "http://localhost:3100/loki/api/v1/query_range" --data-urlencode 'query={job=""}' | jq

评论




正在载入...
PoweredHexo
HostedAliyun
DNSAliyun
ThemeVolantis
UV
PV
BY-NC-SA 4.0