⭐⭐⭐ 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. 应该按时间递增: