Loki的原理及使用

  • Post author:
  • Post category:其他



为什么做监控


核心目标:保障站点可靠,从而保障业务稳定及保障业务迭代效率

什么决定了站点“可靠”:系统可用度

系统可用度取决于什么:多长时间坏一次;一旦坏了之后,多长时间可以恢复

监控,即是服务于“可观察性”

覆盖面:硬件/系统级监控、应用服务指标监控、程序运行日志监控、业务监控、链路监控


关于日志监控

核心目标:程序运行日志监控,关注程序运行状态

如何做:日志的采集 -> 转换 -> 存储 ->可视化

ELK Stack:

ELK系统通常包含较多需求场景:“日志”(程序的运行信息)的监控、接口调用的指标统计分析、离线数据保存、业务数据分析等

当数据量级上来,在每个需求场景下都很难达到满意

ELK系统的需求做分化,让各自的技术方案适配各自的场景需求

ES存储日志数据成本高:尽量避免使用昂贵的全文索引或列式存储引擎来存储大量低价值的日志信息通常情况下查看频率较低

ES集群部署、扩缩容的运维成本较高

日志告警功能不完善


Loki是什么

Loki一个可水平伸缩、高可用、支持多租户的日志聚合系统。

Loki的灵感来源于Prometheus,它的设计极具成本效益并且易于操作,可以认为是日志版的Prometheus。


Loki的特殊之处

Loki不会对日志数据建立全文索引,也不支持Multiline:

取而代之的是:对非结构化的日志数据进行压缩存储并且只对日志数据的metadata(包括:时间戳、 labels等)建立索引。


存储、查询成本较低

Loki可以跟Prometheus中的监控指标进行关联:Loki可以使用与Prometheus相同的label定义和设计。

Loki的查询语法LogQL简单:日志数据查询分析心智负担低,便于在此之上建立告警统计机制

Grafana原生支持Loki:Grafana中原生支持Loki作为数据源进行查询


Loki的功能组件

Promtail、Distributor、Ingester、Querier、Query Frontend、Overrides、TableManager、RuntimeConfig


Loki的功能组件的架构


Loki的功能组件-Promtail

日志数据:采集、提取、匹配、过滤、打Labels、批量Push To Loki

支持的采集方式:File Traget、Journal Traget、Syslog Traget、Stdin Traget


Loki的功能组件-Promtail-处理流程


Loki的功能组件-Promtail-处理结果


Loki的功能组件-Distributor

接收Promtail push过来的日志数据,并把日志数据分发给Ingester

Distributor从Etcd/Consul上获取Ingester注册的服务信息

Distributor与Ingester之间以RPC的方式进行通信

Distributor以Consistent Hash的方式,决定日志数据分发到哪一个Ingester上

Distributor以日志数据的TenantID、Lables作为Hash Key


Loki的功能组件-Ingester

接收Distributor发送过来的日志数据,存储日志数据的索引数据以及日志内容数据

Instance Stages、Organize Data In Memory、Build Chunk Index


Loki的功能组件-Ingester-Instance Stages

PENDING:

Ingester启动后的初始状态,在PENDING状态下,Ingester会等待是否有LEAVING状态的Ingester进行Hand-Over

如果在auto-join定时(ingester.join-after)的超时时间内,没有Hand-Over发生,则Ingester会以一组新的随机Tokens加入Hash Ring,进入JOINING状态

JOINING:

Ingester会有两种情况进入JOINING状态

1)auto-join定时超时后,Ingester会自动进入JOINING状态

在此场景下,Ingester会生成新的Tokens,并把Tokens信息存入Hash Ring

此时可选择observe Hash Ring上的Token是否存在冲突存储失败的情况,直到Token存储正常再进入ACTIVE状态,或者直接进入ACTIVE状态

2)如果Ingester与LEAVING状态的Ingester进行Hand-Over,则在Hand-Over正常结束时,Ingester会继续使用LEAVING状态的Ingester的Tokens,然后进入ACTIVE状态

如果Hand-Over失败,则Ingester重新回到PENDING状态,重新开启auto-join定时等待Hand-Over

ACTIVE:

Ingester在ACTIVE状态下,表明已经完成初始化,可以开始处理Write/Read请求

LEAVING:

当Ingester被正常结束运行时,会进入LEAVING状态,LEAVING状态下Ingester不再处理Write请求,但是内存中的日志数据依旧可以提供Read请求

在LEAVING状态时,Ingester会寻找处于PENDING状态的Ingester,然后开始Hand-Over,把自己的状态以及内存中的日志数据转交给其中一个PENDING状态的Ingester

LEAVING状态下的Ingester会在尝试ingester.max_transfer_retries次寻找之后,如果还没有寻找到PENDING状态的Ingester,则把内存中的日志数据flush到store中

UNHEALTHY:

如果Ingester与Hash Ring Store之间心跳超时,则Distributor认为Ingester为UNHEALTHY状态,此时不再有Write/Read请求路由至UNHEALTHY状态的Ingester上


Loki的功能组件-Ingester-Instance Stages



Loki的功能组件-Ingester-Organize Data In Memory


Loki的功能组件-Ingester-Build Chunk Index

SeriesID:计算chunk的labels的SHA256 Hash值

Shard:seriesID % rowShards

Bucket:描述了tableName和hashKey的一个时间段信息

From:起始时间点(Unix ms)

Through:时间段(单位:ms)

TableName:prefix+时间段分区

HashKey:tenantID:d+天数

MetricName:固定为”logs”

ChunkID:chunk.orgID/chunk.fingerprint:chunk.from:chunk.through:chunk.checksum




Loki的功能组件-Querier

接收日志数据查询、聚合统计请求

从Ingester以及Index/Chunks Store中读取索引数据以及日志文本内容

合并各个Ingester以及Index/Chunks Store中读取到的结果,返回给查询Client


Loki与Grafana

LogQL、Grafana DataSource

LogQL是Loki的一套查询语言

Label的操作符

= exactly equal

!= not equal

=~ regex-match

!~ do not regex-match

示例:{app=”mysql”,name=~”mysql-backup”}

Log文本内容的操作符

|= exactly equal

!= not equal

|~ regex-match

!~ do not regex-match

示例:{app=”mysql”,name=~”mysql-backup”} |~ “relog“

{app=”mysql”,name=~”mysql-backup”} |~ “relog” !~ “slow”

Log Metric的操作

rate  计算每秒的log entry数量

count_over_time   计算目标时间段内的每一个聚合条件下的log entry数量



https://grafana.com/docs/grafana/latest/features/datasources/loki/

可以通过Grafana中的Explore组件查询、聚合统计日志数据;Grafana Version >= V7.0.3

在Grafana中添加DataSource

在Explore中选择目标DataSource

查询日志数据(Logs)

Live Tail日志数据

聚合统计日志数据(Metrics)


Loki与Prometheus

Promtail指标数据的采集:Go App Stats、Process Info、采集任务处理性能(处理的LogEntry数量/字节数、单条LogEntry的处理时长等)

Loki-Server指标数据的采集:Go App Stats、Process Info、接口调用性能(Push/Query)、Store

Loki可以与Prometheus结合进行异常日志告警功能的支持


Loki的部署使用

Loki的部署方案-日志数据标签定义

Loki的部署使用-Single部署

Loki的部署使用-集群部署-I

Loki的部署方案-集群部署-II


Loki的容错机制

Loki的容错机制-Promtail:

Loki-Promtail断点续传:记录采集文件offset

Loki-Promtail重复采集:唯一标识:目标采集文件的全路径

Loki的容错机制-Loki-Server:

Loki-Server集群的扩容:直接启动新增的Loki实例;在Query路由至此Loki实例时,此Loki实例需要download其他Loki实例的Index数据,可能会造成不同程度的Query延时

Loki-Server集群的缩容:直接正常结束掉需要下线的Loki实例即可

Loki-Server集群的实例替换:先启动一个新的Loki实例,在JoinAfter时间内,结束掉要下线的Loki实例

单个Loki-Server节点异常挂掉:在此Loki节点在Etcd/Consul上的节点信息过期之前,会引起短暂的Push、Query失败;此时Push失败,Promtail会丢弃部分日志数据;保留在Loki-Server实例内存中尚未Flush的chunk数据全部丢失

整个Loki-Server集群挂掉:Loki-Server集群恢复之后,可以通过清除Promtail的position.yaml文件,对日志文件重新处理;重复写入的日志数据(时间戳、Labels相同)Index/Chunk数据均会被覆盖


Loki的容错机制-端到端成功率

Promtail Push To Loki-Server的成功率

Query Client To Loki-Server的成功率



版权声明:本文为shiyuezhong原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。