点击上方“Java基基”,选择“设为星标”
做积极的人,而不是积极废人!
每天 14:00 更新文章,每天掉亿点点头发...
源码精品专栏
前言
在对公司容器云的应用中,Elasticsearch 的搜索功能,Elasticsearch 的多种搜索功能都用不上,最终选择了Grafana开源的Loki日志系统。
下面来介绍下 Loki 的基本概念和,当然 EFK 作为众多业内人士的一些日志,我们聚合解决方案需要有和掌握的。
基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能。
项目地址:https://github.com/YunaiV/ruoyi-vue-pro
简介
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 来回切换。
基于微服务的思想,构建在 B2C 电商场景下的项目实战。核心技术栈,是 Spring Boot + Dubbo 。未来,会重构成 Spring Cloud Alibaba 。
项目地址:https://github.com/YunaiV/onemall
架构说明
组件说明
说明如下:
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=~”apachesyslog”进行多个作业匹配
也支持正则和正则非匹配
标签匹配模式的特点
原理如下:
和 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 为了性能考虑直接拒绝掉旧数据
欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:
已在知识星球更新源码解析如下:
最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。
提供近 3W 行代码的 SpringBoot 示例,以及超 6W 行代码的电商微服务项目。
获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)