⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud ��目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 www.cnblogs.com/you-men/p/14900249.html 「常见-youmen」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

前言

在对公司容器云的应用中,Elasticsearch 的搜索功能,Elasticsearch 的多种搜索功能都用不上,最终选择了Grafana开源的Loki日志系统。

下面来介绍下 Loki 的基本概念和,当然 EFK 作为众多业内人士的一些日志,我们聚合解决方案需要有和掌握的。

简介

Loki Grafana Labs 的开源项目,是一个团队的开源项目,可扩展性高,是一个多级别的开源系统。

它的设计非常经济且易于操作,因为它不会为日志编制内容索引,而是为每个流编组标签,为我们和Kubernetes用户制作]相关的优化标签。

该项目受 Prometheus 的启发,官方的介绍就是:Like Prometheus,But For Logs。类似于 Prometheus 的日志系统。

项目地址:

https://github.com/grafana/loki/

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

  • 通过存储非日志记录和非索引元数据,Loki操作起来更简单,更省索引。
  • 通过使用与 Promethe 相同的标签进行索引和团队记录,这对记录日志对我们的记录者的扩展和操作日志有更大的影响,能够更好地响应警报人。
  • 特别适合索引存储 Kubernetes Pod 日志;诸如 Pod 标签之类的数据元会被自动删除和进入。
  • 受 Grafana 枣,避免 kibana 和 grafana 来回切换。

架构说明

组件说明

说明如下:

  • Promtail 采集器,类比文件节拍
  • Loki 相当于服务端,类比 es

Loki进程包含四个角色:

  • 查询器 查询器
  • 内政声明
  • 查询前端分类查询器
  • 分销商写入分发器

可以通过 Loki 路由器的 -target 参数指定运行角色。

读取路径

如下:

  • 接受器接受 HTTP/1 数据查询请求
  • 查询器将查询传递给所有摄取者请求内存中的数据
  • 接收器接受读取的请求,并返回与查询匹配的数据(如果有)
  • 如果接受返回数据时,会从备存储中延迟加载数据,然后执行查询者并没有执行查询
  • 设备将通过所有接收到的数据并进行重复数据删除,重新通过HTTP/1连接查询返回最终数据集

写入路径

如上图:

  • 分发服务器收到一个 HTTP/1 请求,以存储流数据
  • 流都使用散列环散列
  • 程序将每个和发送到适当的释放因子(基于配置的复制因子)
  • 实体流动中的所有实体都是其集中的个体,将创建一个和一个或多个现有标签的唯一的数据集
  • 分发服务器通过 HTTP/1 链接以成功代码作为响应

部署

本地化模式安装

下载 Promtail 和 Loki:

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

安装提示:

$ mkdir /opt/app/{promtail,loki} -pv

# promtail配置文件
$ cat <<EOF> /opt/app/promtail/promtail.yaml
server:
http_listen_port: 9080
grpc_listen_port: 0

positions:
filename: /var/log/positions.yaml # This location needs to be writeable by promtail.

client:
url: http://localhost:3100/loki/api/v1/push

scrape_configs:
- job_name: system
pipeline_stages:
static_configs:
- targets:
- localhost
labels:
job: varlogs
host: yourhost
__path__: /var/log/*.log
EOF

# 解压安装包
unzip promtail-linux-amd64.zip
mv promtail-linux-amd64 /opt/app/promtail/promtail

# service文件
$ cat <<EOF >/etc/systemd/system/promtail.service
[Unit]
Description=promtail server
Wants=network-online.target
After=network-online.target

[Service]
ExecStart=/opt/app/promtail/promtail -config.file=/opt/app/promtail/promtail.yaml
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=promtail
[Install]
WantedBy=default.target
EOF

systemctl daemon-reload
systemctl restart promtail
systemctl status promtail

安装 Loki:

$ mkdir /opt/app/{promtail,loki} -pv

# promtail配置文件
$ cat <<EOF> /opt/app/loki/loki.yaml
auth_enabled: false

server:
http_listen_port: 3100
grpc_listen_port: 9096

ingester:
wal:
enabled: true
dir: /opt/app/loki/wal
lifecycler:
address: 127.0.0.1
ring:
kvstore:
store: inmemory
replication_factor: 1
final_sleep: 0s
chunk_idle_period: 1h # Any chunk not receiving new logs in this time will be flushed
max_chunk_age: 1h # All chunks will be flushed when they hit this age, default is 1h
chunk_target_size: 1048576 # Loki will attempt to build chunks up to 1.5MB, flushing first if chunk_idle_period or max_chunk_age is reached first
chunk_retain_period: 30s # Must be greater than index read cache TTL if using an index cache (Default index read cache TTL is 5m)
max_transfer_retries: 0 # Chunk transfers disabled

schema_config:
configs:
- from: 2020-10-24
store: boltdb-shipper
object_store: filesystem
schema: v11
index:
prefix: index_
period: 24h

storage_config:
boltdb_shipper:
active_index_directory: /opt/app/loki/boltdb-shipper-active
cache_location: /opt/app/loki/boltdb-shipper-cache
cache_ttl: 24h # Can be increased for faster performance over longer query periods, uses more disk space
shared_store: filesystem
filesystem:
directory: /opt/app/loki/chunks

compactor:
working_directory: /opt/app/loki/boltdb-shipper-compactor
shared_store: filesystem

limits_config:
reject_old_samples: true
reject_old_samples_max_age: 168h

chunk_store_config:
max_look_back_period: 0s

table_manager:
retention_deletes_enabled: false
retention_period: 0s


ruler:
storage:
type: local
local:
directory: /opt/app/loki/rules
rule_path: /opt/app/loki/rules-temp
alertmanager_url: http://localhost:9093
ring:
kvstore:
store: inmemory
enable_api: true
EOF

# 解压包
unzip loki-linux-amd64.zip
mv loki-linux-amd64 /opt/app/loki/loki

# service文件

$ cat <<EOF >/etc/systemd/system/loki.service
[Unit]
Description=loki server
Wants=network-online.target
After=network-online.target

[Service]
ExecStart=/opt/app/loki/loki -config.file=/opt/app/loki/loki.yaml
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=loki
[Install]
WantedBy=default.target
EOF

systemctl daemon-reload
systemctl restart loki
systemctl status loki

使用

grafana 上配置 loki 数据源

如下图:

grafana-loki-dashsource

在数据源列表中选择 Loki,配置 Loki 源地址:

grafana-loki-dashsource-config

源地址配置 http://loki:3100 智能,保存。

保存完成后,切换到grafana到左侧区域的探索,会进入Loki的页面:

格拉法纳洛基

然后我们点击系统采集日志的标签就可以把日志标签显示出来,可以根据这些标签进行的过滤查询:

grafana-loki-日志标签

在这里选择 /var/log/messages,只要把该文件下面的日志过滤展示出来,不过,可能需要设置下一段时间才能看到数据:

grafana-loki-日志

这里展示的是promtail Container里面/var/log目录中的日志。

promtail 容器 /etc/promtail/config.yml:

server:
http_listen_port: 9080
grpc_listen_port: 0

positions:
filename: /tmp/positions.yaml

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

scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: varlogs
__path__: /var/log/*log

这里的工作就是varlog,文件路径就是/var/log/*log。

在 grafana explore 上配置查看日志

查看日志 rate({job="message"} |="kubelet"

算 qps rate({job=”message”} |=”kubelet” [1m])

仅索引标签

只是之前的索引内容是不同的索引 loki 和 es 是最大的索引 loki 对标签进行而不是对下面的索引。我们举个例子看下。

静态标签匹配模式

以简单的promtail配置举例:

scrape_configs:
- job_name: system
pipeline_stages:
static_configs:
- targets:
- localhost
labels:
job: message
__path__: /var/log/messages

配置解读:

  • 手势录音启动一个任务
  • 这个任务有1个固定标签 job=”syslog”
  • 记录路径为/var/log/messages,会以一个文件名的固定标签
  • 在promtail的网页上可以看到类似prometheus的目标信息页面

可以和使用 Prometheus 一样的匹配标签语句进行查询。

{job="系统日志"}:

scrape_configs:
- job_name: system
pipeline_stages:
static_configs:
- targets:
- localhost
labels:
job: syslog
__path__: /var/log/syslog
- job_name: system
pipeline_stages:
static_configs:
- targets:
- localhost
labels:
job: apache
__path__: /var/log/apache.log

  • 如果我们配置了两个作业,则可以使用{job=~”apache|syslog”} 进行多个作业匹配
  • 也支持正则和正则非匹配

标签匹配模式的特点

原理如下:
  • 和 prometheus 一致,相同的标签是一个流 prometheus 处理系列的模式
  • prometheus 中标签一致的同一个 hash 值和 refid(正好递增就是同一个 id),也有一个系列
  • 将数据不断的追加到这个我的系列中
  • 当有任意标签发生变化时会产生新的哈希值和 refid,新的系列

loki 处理模式和 prometheus 一致,loki 等一系列日志的产生到会生成一个日志流。随着时间的增长会产生一个哈希值流中,最后压缩为块。有任意的标签变化时会新发生,188金宝搏下流。

查询过程
  • 所以 loki 先根据标签算出哈希值在倒排索引中找到的块?
  • 然后再根据语句中的等关键词进行过滤,这样可以更大的提速
  • 因为这种根据标签算哈希在倒排中查找id,找到存储的块在prometheus中已经被验证过了
  • 属于类别低
  • 速度快

动态标签和高基数

所以上面有知识,那么就得聊聊标签的问题了。

两个概念:

  • 何为动态标签:说白了就是标签的价值不固定
  • 何为高基数标签:说白了标签的值更多就是,达到10万,100万甚至更多

apache的访问日志:

11.11.11.11 - frank [25/Jan/2000:14:00:01 -0500] "GET /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"

在 Promtail 中使用 regex 想要匹配 action 和 status_code 两个标签:

scrape_configs:
- job_name: system
pipeline_stages:
static_configs:
- targets:
- localhost
labels:
job: syslog
__path__: /var/log/syslog
- job_name: system
pipeline_stages:
static_configs:
- targets:
- localhost
labels:
job: apache
__path__: /var/log/apache.log

- job_name: system
pipeline_stages:
- regex:
expression: "^(?P<ip>\\S+) (?P<identd>\\S+) (?P<user>\\S+) \\[(?P<timestamp>[\\w:/]+\\s[+\\-]\\d{4})\\] \"(?P<action>\\S+)\\s?(?P<path>\\S+)?\\s?(?P<protocol>\\S+)?\" (?P<status_code>\\d{3}|-) (?P<size>\\d+|-)\\s?\"?(?P<referer>[^\"]*)\"?\\s?\"?(?P<useragent>[^\"]*)?\"?$"
- labels:
action:
status_code:
static_configs:
- targets:
- localhost
labels:
job: apache
env: dev
__path__: /var/log/apache.log

action=get/post 和 status_code=200/400 则满足 4 个流:

11.11.11.11 - frank [25/Jan/2000:14:00:01 -0500] "GET /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
11.11.11.12 - frank [25/Jan/2000:14:00:02 -0500] "POST /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
11.11.11.13 - frank [25/Jan/2000:14:00:03 -0500] "GET /1986.js HTTP/1.1" 400 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
11.11.11.14 - frank [25/Jan/2000:14:00:04 -0500] "POST /1986.js HTTP/1.1" 400 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"

四个日志行将变成四个单独的流动,并开始填充四个单独的块。

如果出现另一个特殊的代码组合(例如“500”),创建另一个新流。

高基数问题

就像上面,如果给 ip 标签,给了一个预览的标签。高基数,这可以杀死Loki。

现场没有被标记,不会很容易被查询日志,你可以查询命令查询会为小块并当分发,以便在查询大量查询。

全文索引问题

大索引既复杂又完整。通常,日志的索引的大小或日志大于数据本身的大小。

要日志加载此索引,并且为了提高性能,它可能应该在内存扩展中,随着查询中的更多数据变化,这个索引需要更大的日志,然后索引会。

Loki 的索引量通常比简单的日志小一个,索引量的增长非常缓慢。

加速没有字段:上面提到的ip字段查询标签-使用过滤器表达式。

{job="apache"} |= "11.11.11.11"

loki 时的分片(按时间范围分段查询grep):

  • Loki将把分割成该片段与该分片的匹配,并标签的每个区块,并开始寻找IP地址。
  • 这些片子的大小和并行化的数量,并列出您可以提供的资源
  • 需要,如果部署间隔配置为20个5m,就可以在几个内查询,并且您可以在需要处理的分片日志
  • 或者,您可以发疯并设置 200 个查询器并处理 TB 的日志!

索引模式对比:

  • es 的大索引,不管你查不查询,他都必须时刻存在。比如长时间占用过多的内存
  • loki 逻辑是查询时再启动多个并行查询
日志量少时少加标签:
  • 因为每一个额外的额外的一个块
  • 例子,如果该查询是 {app=”loki”,level!=”debug”}
  • 在没加level标签的情况下只加载一个chunk 即app=“loki”的标签
  • 如果加了level的情况,则需要把level=info,warn,error,critical 5个chunk 都加载再查询
需要标签时再去添加:
  • 当 chunk_target_size=1MB 时代表以 1MB 的压缩大小来切割块
  • 原来的日志大小在5MB,如果日志max_chunk_age在10MB,可以达到10MB,可以考虑添加标签
应该按时间递增:
  • 这个和 tsdb 中处理旧数据是一样的道理
  • 目前 loki 为了性能考虑直接拒绝掉旧数据
文章目录
  1. 1. 前言
  2. 2. 简介
  3. 3. 架构说明
  4. 4. 组件说明
    1. 4.0.0.1. 读取路径
    2. 4.0.0.2. 写入路径
  • 5. 部署
    1. 5.0.0.1. 本地化模式安装
      1. 5.0.0.1.1. 安装提示:
  • 6. 使用
    1. 6.0.0.1. grafana 上配置 loki 数据源
    2. 6.0.0.2. 在 grafana explore 上配置查看日志
    3. 6.0.0.3. 仅索引标签
      1. 6.0.0.3.1. 原理如下:
      2. 6.0.0.3.2. 查询过程
    4. 6.0.0.4. 动态标签和高基数
    5. 6.0.0.5. 高基数问题
    6. 6.0.0.6. 全文索引问题
    7. 6.0.0.7. 加速没有字段:上面提到的ip字段查询标签-使用过滤器表达式。
    8. 6.0.0.8. loki 时的分片(按时间范围分段查询grep):
    9. 6.0.0.9. 索引模式对比:
      1. 6.0.0.9.1. 日志量少时少加标签:
      2. 6.0.0.9.2. 需要标签时再去添加:
      3. 6.0.0.9.3. 应该按时间递增: