### 介绍

Loki 是 Grafana Lab开发的一套日志系统，使用Go语言实现。根据官方的介绍， Loki，高可用性，多租户的日志聚合系统，受到Prometheus的启发。它的设计非常经济高效且易于操作，因为它不会为日志内容编制索引，而是为每个日志流编制一组标签。如果用一句话介绍的话，就是 `Like Prometheus, but for logs`

#### Loki 能做什么

- 日志采集。loki-stack中提供promtail，专为loki定制的日志采集组件
- 日志压缩存储
- 使用和prometheus相同的标签。根据日志元数据和标签对日志进行分组和索引。
- 使用Grafana展示Loki中的日志，也可以使用API和CLI来查询日志。

#### Loki 和 ELK 对比

- 轻量。loki 使用go实现，并且除存储（也是可选的）外不依赖其他的中间件
- 存储成本低。由于loki只对元数据和标签进行索引，对日志文本进行压缩存储，存储成本是远低于ES
- 检索能力低于ES。loki 不会对文本日志进行分词和倒排索引，所以只能使用标签去匹配查询日志块，然后可以对搜索的日志块在内存进行grep
- 日志分析能力。loki 可以提供兼容promethues的范围向量查询，如对查询的日志进行计数，kibana 则可以对任意文本进行查询分析。

#### 与其他日志聚合系统相比，Loki

- 
不对日志进行全文本索引。通过存储压缩的，非结构化的日志以及仅索引元数据，Loki更加易于操作且运行成本更低。

- 
使用与Prometheus相同的标签对日志流进行索引和分组，从而使您能够使用与Prometheus相同的标签在指标和日志之间无缝切换。

- 
特别适合存储Kubernetes Pod日志。诸如Pod标签之类的元数据会自动被抓取并建立索引。

- 
在Grafana中原生支持（需要Grafana v6.0及以上）。


#### 基于Loki的日志记录堆栈包含3个组件

- promtail是代理，负责收集日志并将其发送给Loki。
- loki是主服务器，负责存储日志和处理查询。
- Grafana用于查询和显示日志。

#### 架构说明

- 地址 [https://grafana.com/docs/loki/latest/architecture/](https://grafana.com/docs/loki/latest/architecture/)

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202204170051701.png#alt=)

### 组件说明

**loki相当于服务端，类比es**

#### promtail 作为采集器，类比filebeat

> loki 进程包含 四种角色


- querier 查询器
- ingester 日志存储器
- query-frontend 前置查询器
- distributor 写入分发器

> 可以通过loki二进制的 -target参数指定运行角色


#### read path

- 查询器接收HTTP / 1数据请求。
- 查询器将查询传递给所有ingesters 请求内存中的数据。
- 接收器接收读取的请求，并返回与查询匹配的数据（如果有）。
- 如果没有接收者返回数据，则查询器会从后备存储中延迟加载数据并对其执行查询。
- 查询器将迭代所有接收到的数据并进行重复数据删除，从而通过HTTP / 1连接返回最终数据集。

#### write path

- 分发服务器收到一个HTTP / 1请求，以存储流数据。
- 每个流都使用散列环散列。
- 分发程序将每个流发送到适当的inester和其副本（基于配置的复制因子）。
- 每个实例将为流的数据创建一个块或将其追加到现有块中。每个租户和每个标签集的块都是唯一的。
- 分发服务器通过HTTP / 1连接以成功代码作为响应。

### 使用本地化模式安装



#### 1.安装grafana

[Grafana: The open observability platform | Grafana Labs](https://grafana.com/)

```shell
[root@loki opt]# cd /opt && wget https://dl.grafana.com/enterprise/release/grafana-enterprise-8.4.5-1.x86_64.rpm

[root@loki opt]# yum -y install grafana-enterprise-8.4.5-1.x86_64.rpm

# 可以rpm -ivh，也可以yum安装；但是rpm需要解决依赖
```

#### 2.启动grafana(port:3000)

```shell
[root@loki opt]# sudo /bin/systemctl daemon-reload
[root@loki opt]# systemctl start grafana-server.service
[root@loki opt]# systemctl status grafana-server.service

[root@loki opt]# netstat -ntpl |grep 3000
tcp6       0      0 :::3000                 :::*                    LISTEN      1179/grafana-server 
```

#### 3.浏览器打开页面

输入ip:3000，打开如下图，默认账号密码是admin，登录后会要求改密码

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202204161929351.png#alt=)

**改密**

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202204161930323.png#alt=)

**进去之后的页面**

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202204161931419.png#alt=)



https://www.cnblogs.com/emma1325/p/13045425.html



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

#### 4.安装loki和promtail

```shell
cd /opt && wget https://github.com/grafana/loki/releases/download/v2.6.1/loki-linux-amd64.zip
cd /opt && wget https://github.com/grafana/loki/releases/download/v2.6.1/promtail-linux-amd64.zip
[root@loki opt]# yum -y install unzip
[root@loki opt]# unzip loki-linux-amd64.zip     
[root@loki opt]# unzip promtail-linux-amd64.zip 

# 查看会发现两个是二进制，没有配置文件需要我们自己写		
```

#### 5.做成系统命令

```shell
[root@loki opt]# cp promtail-linux-amd64 /usr/local/bin/promtail
[root@loki opt]# cp loki-linux-amd64 /usr/local/bin/loki
```

#### 6.修改配置文件

https://grafana.com/docs/loki/next/getting-started/，可以到官网查看怎么写或者去官方github上面找

```shell
[root@loki opt]# vim loki.yaml
# 添加如下内容
auth_enabled: false

server:
  http_listen_port: 3100
  grpc_listen_port: 9096

common:
  path_prefix: /opt/loki   # 路径设置
  storage:
    filesystem:
      chunks_directory: /opt/loki/chunks
      rules_directory: /opt/loki/rules
  replication_factor: 1
  ring:
    instance_addr: 127.0.0.1
    kvstore:
      store: inmemory

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

ruler:
  alertmanager_url: http://localhost:9093

# By default, Loki will send anonymous, but uniquely-identifiable usage and configuration
# # analytics to Grafana Labs. These statistics are sent to https://stats.grafana.org/
# #
# # Statistics help us better understand how Loki is used, and they show us performance
# # levels for most users. This helps us prioritize features and documentation.
# # For more information on what's sent, look at
# # https://github.com/grafana/loki/blob/main/pkg/usagestats/stats.go
# # Refer to the buildReport method to see what goes into a report.
# #
# # If you would like to disable reporting, uncomment the following lines:
# #analytics:
# #  reporting_enabled: false
```

```shell
[root@loki opt]# mkdir /opt/loki
```

#### 7.启动

```shell
[root@loki opt]# loki -config.file=/opt/loki.yaml

或者

[root@loki opt]# nohup loki -config.file=/opt/loki.yaml > /dev/null &
[1] 1445
```

```shell
[root@loki opt]# netstat -autlnp
# 检查有没有9096、3000、3100
```

#### 8.结合grafana

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202204162344182.png#alt=)

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202204162344909.png#alt=)

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202204162345099.png#alt=)

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202204162349221.png#alt=)

#### 9.设置promtail

```shell
[root@loki opt]# vim promtail.yaml
#添加以下内容
server:
  http_listen_port: 9080
  grpc_listen_port: 0

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

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

scrape_configs:
 - job_name: system
   pipeline_stages:
   static_configs:
   - targets:
      - localhost
     labels:
      job: varlogs  # A `job` label is fairly standard in prometheus and useful for linking metrics and logs.
      host: yourhost # A `host` label will help identify logs from this machine vs others
      __path__: /var/log/*.log  # The path matching uses a third party library: https://github.com/bmatcuk/doublestar
```

#### 10.启动promtail

```shell
[root@loki opt]# promtail -config.file=/opt/promtail.yaml

或者

[root@loki opt]# nohup promtail -config.file=/opt/promtail.yaml > /dev/null &

# 浏览器输入ip:9080，如下图，能看到promtail采集的日志
```

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202204170001792.png#alt=)

**使用grafana仓库模板(官网模板https://grafana.com/grafana/dashboards/?search=loki)，这里有常用的模板https://blog.csdn.net/yuezhilangniao/article/details/117687312；复制模板ID**

**导入，如下图**

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202204170014456.png#alt=)

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202204170015983.png#alt=)

**我后面换了模板，ID：10004**

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202204170018091.png#alt=)

#### 11.添加多个采集

```shell
[root@loki opt]# vim promtail.yaml
# 在scrape_configs添加需要采集的日志即可，根据前一个为模板来写
server:
  http_listen_port: 9080
  grpc_listen_port: 0

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

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

scrape_configs:
 - job_name: system
   pipeline_stages:
   static_configs:
   - targets:
      - localhost
     labels:
      job: varlogs  # A `job` label is fairly standard in prometheus and useful for linking metrics and logs.
      host: yourhost # A `host` label will help identify logs from this machine vs others
      __path__: /var/log/*.log  # The path matching uses a third party library: https://github.com/bmatcuk/doublestar
 - job_name: msg
   pipeline_stages:
   static_configs:
   - targets:
      - localhost
     labels:
      job: message
      __path__: /var/log/messages
      
      
# kill之前那个，重启一下promtail
```

#### 12.回到grafana

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202204170031503.png#alt=)

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202204170032317.png#alt=)

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202204170032103.png#alt=)

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202204170035095.png#alt=)

### 只索引标签

> 之前多次提到loki和es最大的不同是 loki只对标签进行索引而不对内容索引<br />
下面我们举例来看下


### 静态标签匹配模式

> 以简单的promtail配置举例


### 配置解读

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

- 上面这段配置代表启动一个日志采集任务
- 这个任务有1个固定标签`job="syslog"`
- 采集日志路径为 `/var/log/messages` ,会以一个名为filename的固定标签
- 在promtail的web页面上可以看到类似prometheus 的target信息页面

### 查询的时候可以使用和prometheus一样的标签匹配语句进行查询

- `{job="syslog"}`

```yaml
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，则可以使用`{job=~”apache|syslog”}` 进行多job匹配
- 同时也支持正则和正则非匹配

### 标签匹配模式的特点

#### 原理

- 和prometheus一致，相同标签对应的是一个流

> prometheus 处理series的模式


- prometheus中标签一致对应的同一个hash值和refid(正整数递增的id)，也就是同一个series

   - 时序数据不断的append追加到这个memseries中
   - 当有任意标签发生变化时会产生新的hash值和refid，对应新的series

> loki处理日志的模式


- 和prometheus一致，loki一组标签值会生成一个stream

   - 日志随着时间的递增会追加到这个stream中，最后压缩为chunk
   - 当有任意标签发生变化时会产生新的hash值，对应新的stream

#### 查询过程

- 所以loki先根据标签算出hash值在倒排索引中找到对应的chunk?
- 然后再根据查询语句中的关键词等进行过滤，这样能大大的提速
- 因为这种根据标签算哈希在倒排中查找id，对应找到存储的块在prometheus中已经被验证过了

   - 属于开销低
   - 速度快

### 动态标签和高基数

> 所以有了上述知识，那么就得谈谈动态标签的问题了


#### 两个概念

> 何为动态标签：说白了就是标签的value不固定


> 何为高基数标签：说白了就是标签的value可能性太多了，达到10万，100万甚至更多


### promtail支持在 pipline_stages中用正则匹配动态标签

- 比如apache的access日志

```shell
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`两个标签

```yaml
- 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个流

```shell
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"
```

- 那四个日志行将变成四个单独的流，并开始填充四个单独的块。
- 如果出现另一个独特的标签组合（例如status_code =“ 500”），则会创建另一个新流

### 高基数问题

- 就像上面，如果给ip设置一个标签，现在想象一下，如果您为设置了标签ip，来自用户的每个不同的ip请求不仅成为唯一的流
- 可以快速生成成千上万的流，这是高基数，这可以杀死Loki
- 所以为了避免高基数则应该避免使用这种取值分位太大的标签

### 如果字段没有被当做标签被索引，会不会导致查询很慢

> Loki的超级能力是将查询分解为小块并并行分发，以便您可以在短时间内查询大量日志数据


### 全文索引问题

- 大索引既复杂又昂贵。通常，日志数据的全文索引的大小等于或大于日志数据本身的大小
- 要查询日志数据，需要加载此索引，并且为了提高性能，它可能应该在内存中。这很难扩展，并且随着您摄入更多日志，索引会迅速变大。
- Loki的索引通常比摄取的日志量小一个数量级，索引的增长非常缓慢

### 那么如何加速查询没有标签的字段

> 以上边提到的ip字段为例


- 使用过滤器表达式查询

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

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

- Loki将把查询分解成较小的分片，并为与标签匹配的流打开每个区块，并开始寻找该IP地址。
- 这些分片的大小和并行化的数量是可配置的，并取决于您提供的资源
- 如果需要，您可以将分片间隔配置为5m，部署20个查询器，并在几秒钟内处理千兆字节的日志
- 或者，您可以发疯并设置200个查询器并处理TB的日志！

### 两种索引模式对比

- es的大索引，不管你查不查询，他都必须时刻存在。比如长时间占用过多的内存
- loki的逻辑是查询时再启动多个分段并行查询

### 在日志量少的时候少加标签

- 因为每多加载一个chunk就有额外的开销
- 举例 如果该查询是{app="loki",level!="debug"}
- 在没加level标签的情况下只需加载一个chunk 即app="loki"的标签
- 如果加了level的情况，则需要把level=info,warn,error,critical 5个chunk都加载再查询

### 在需要标签时再去添加

- 当chunk_target_size=1MB时代表 以1MB的压缩大小来切割块
- 对应的原始日志大小在5MB-10MB，如果日志在 max_chunk_age时间内能达到10MB，考虑添加标签

### 日志应当按时间递增

- 这个问题和tsdb中处理旧数据是一样的道理
- 目前loki为了性能考虑直接拒绝掉旧数据

### 总结下loki的优点

#### 1.低索引开销

- loki和es最大的不同是 loki只对标签进行索引而不对内容索引
- 这样做可以大幅降低索引资源开销(es无论你查不查，巨大的索引开销必须时刻承担)

#### 2.并发查询+使用cache

- 同时为了弥补没有全文索引带来的查询降速使用，Loki将把查询分解成较小的分片，可以理解为并发的grep
- 同时支持index、chunk和result缓存提速

#### 3.和prometheus采用相同的标签，对接alertmanager

- Loki和Prometheus之间的标签一致是Loki的超级能力之一

#### 4.使用grafana作为前端，避免在kibana和grafana来回切换
