1
头图

前言

提及日志收集搜索框架,最常看到的解决方案就是 ELK。虽然现在有 Docker、k8s 帮我们简化了部署流程,但 ELK 对硬件的要求却很高。光是 Elasticsearch 官网就提及到需要 8 GB 内存以上的机器部署,可见占据的资源之多。为了能降本增效(穷~~~),在网上看到了 Grafana 团队的日志框架: Loki。为此进行了深入的了解并应用在了一些项目上。

Loki 介绍

Loki 是 Grafana 团队开源的一款高可用、高拓展、多租户的日志聚合系统,和 ELK 的组件功能一样,Loki 有负责日志存储查询的主服务,有在客户端负责收集日志并推送的代理服务,还有 Grafana 最拿手的可视化面板展示。

不同的是,Loki 不再根据日志内容去建立大量的索引,而是借鉴了 Prometheus 核心的思想,使用标签去对日志进行特征标记,然后归集统计。这样的话,能避免大量的内存资源占用,转向廉价的硬盘存储。当然 Loki 会对日志进行分块存储并压缩,保留少量的元数据索引,兼顾硬盘的查询效率。

除此之外,Loki 还有以下特性:

  • 一个 Loki 实例允许面向多个租户,不同租户的数据完全与其他租户隔离。
  • LogQL:Loki 自己的日志查询语言,很容易上手使用的。
  • 高拓展性,Loki 的所有组件可以跑在同一个程序里,也可以按微服务的方式去部署它们。
  • 支持市面上许多流行的日志客户端插件,能较好的集合在一起。

说白了,Loki 吸引人的地方就在于拥有和 Prometheus 类似机制的时序数据库以及方便拓展的硬盘资源。

Loki 架构

下面,我们来认识下 Loki 的总体架构。就像前面提及到的,Loki 主要分为了三部分:

  • agent client:日志代理客户端,负责收集日志发送到主服务 Loki,目前官方有自己的 client: Promtail,也支持主流的组件,如 Fluentd、Logstash、Fluent Bit 等。
  • loki:日志主服务,负责存储收集到的日志以及对日志查询解析。
  • grafana:日志数据展示面板。

Loki 总体架构

可以看到,核心的组件其实是 Loki 这个主服务,关于它的内部组成,其实还可以细分为几部分:

  • Distributor:负责处理客户端发送过来的日志数据,检验正确性后将其分发给后续组件。
  • Ingester:负责将日志按块存储。
  • Query frontend:可选服务,对外提供查询 API,负责一些查询调整和整合。

Loki 组成

Loki 的简单使用

Loki 的安装

关于 Loki 的安装非常的简单,大伙可以看官网的连接:Install Grafana Loki with Docker or Docker Compose。本人实践了一下,使用了下面的 yaml 文件,以 docker-compose 方式进行了部署:

version: "3"

services:
    loki:
        image: grafana/loki:2.4.0
        ports:
          - "3100:3100"
        command: -config.file=/etc/loki/config.yaml
        volumes:
            - ./config/loki:/etc/loki
            - loki-vm:/loki
    grafana:
        image: grafana/grafana:7.3.0
        ports:
          - "3000:3000"
        volumes:
            - grafana-vm:/var/lib/grafana
        environment:
            GF_SECURITY_ADMIN_PASSWORD: 123456
            GF_SERVER_HTTP_PORT: 3000
    promtail:
        image: grafana/promtail:2.4.0
        volumes:
          - /var/log:/var/log
        command: -config.file=/etc/config.yml
        network_mode: "host"
        volumes:
            - "./config/promtail/etc:/etc"
            - "./my-service/log:/var/log"
            - "./my-service/log-position:/var/log-position"
volumes:
  grafana-vm:
  loki-vm:

其中,关于 Loki 的配置文件,在本机的 ./config/loki 目录下需要有个 config.yaml,配置如下:

auth_enabled: false

server:
  http_listen_port: 3100
  log_level: debug

ingester:
  lifecycler:
    address: 127.0.0.1
    ring:
      kvstore:
        store: inmemory
      replication_factor: 1
    final_sleep: 0s
  chunk_idle_period: 5m
  chunk_retain_period: 30s
  wal:
    dir: /loki/wal

compactor:
  working_directory: /loki/persistent      # 压缩目录,一般也作为持久化目录
  compaction_interval: 10m                 # 压缩间隔
  retention_enabled: true                  # 持久化开启
  retention_delete_delay: 5m               # 过期后多久删除
  retention_delete_worker_count: 150       # 过期删除协程数目
schema_config:
    configs:
      - from: "2020-07-31"
        index:
            period: 24h
            prefix: loki_index_
        object_store: filesystem          # 持久化方式:本地文件
        schema: v11
        store: boltdb-shipper
storage_config:
    boltdb_shipper:
        active_index_directory: /loki/boltdb-index    # index 目录
        cache_location: /loki/boltdb-cache            # cache 目录
    filesystem:
        directory: /loki/chunks                       # chunks 目录
limits_config:
  retention_period: 240h                              # 多久过期

关于 promtail 的配置文件,在本机的 ./config/promtail/etc 目录下需要有个 config.yaml,配置如下:

server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /var/log-position/positions.yaml # 日志上传位置

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

scrape_configs:
- job_name: my-service
  static_configs:
  - targets:
      - localhost
    labels:
      job: my-service
      __path__: /var/log/*.log

其中,在 promtail 的配置文件里有 __path__ 路径,这个就是我们想要上传的日志文件路径了,它支持正则表达式。这样的话,只要我们的服务有新的日志文件产生,那么它就会被推送到 Loki 了。

Grafana 的使用

上面将会把日志数据推送到 Loki ,接下来我们就可以使用 Grafana 里的数据展示面板来查询我们的日志了。在使用之前,我们还得配置下 Grafana,在 http://服务器地址:3000 里输入配置的账号密码后,按以下步骤配置:

Data Sources 配置:

Grafana

Grafana

Grafana

Grafana

Manage 的配置:

Grafana

Grafana

Grafana

Grafana

Grafana

最后一张图的输入框就是我们想要查找日志关键字的地方了!

日志的标签

除了有 String Match 的输入外,我们还看到了 App 的选择。而这个 App 的选择就是我们提及 Loki 的重点:标签。此标签是我们在 promtail 配置文件里 scrape_configs 下的 label 里的。只要我们在这里配置一些标签,那么就可以对收集的日志进行标记然后在此过滤了,比如服务名、命名空间等。此外,它还支持 json 等格式的标签解析。

日志查询语言: LogQL

为了能满足各式各样的查询,比如包含、不包含、正则等查询,Loki 开发了属于自己的日志查询语言:LogQL。它就像 Prometheus 的 PromQL 一样,具有丰富的查询语义,例如我们可以点击如下的查询按钮:

Grafana

就会跳转到如下界面:

Grafana

如果我们想要查找日志不包含某些关键字的,那么可以这么输入:

{job="my-service"} != "内容"

LogQL 的使用非常简单,这里罗列一些常用的语法:

|=: 包含
!=: 不包含
|~: 正则匹配
!~: 不在正则匹配里的

总体上来讲,LogQL 的过滤分为了三种过滤,分别如下:

  • 标签匹配(Label matchers):例如 {job="my-service"},一般至少需要一个标签匹配,否则将检索所有数据了。
  • 行过滤器(Line filters):例如 != "内容",是对日志内容进行匹配过滤的。
  • 标签过滤器(Label filters):需要对标签进行转换计算,效率较低。

在 Loki 的官网里,有关于日志查询的一些最佳实践,下面总结罗列一下,方便大家部署时注意:

  • 尽量使用静态标签,不使用动态标签,以免产生大量的小块文件
  • 在配置文件里尽量使用缓存,能加快查询速度,配置支持 in-memory、memcached 和 redis。
  • Loki 的过滤效果是按标签匹配(Label matchers)、行过滤器(Line filters)、 标签过滤器(Label filters)逐级递减的,过滤条件越到后面匹配,将会越慢。尽量在前面就进行条件过滤。

遇到的问题

过期配置

在使用本地模式收集日志时,希望日志的存储能在一定时间后清除,以免无限增加。当时看了官网的 Table ManagerCompactor。尝试了多种配置后,一直不生效,后面才发现,需要在 limits_config 里也配置。

查询超时

当前使用 Loki 的时候,发现查询日期较远,查询较复杂时,会出现 time out 情况,并且会莫名重启。后面发现原来是 2.4.0 的版本有 bug,会不定时的出现 AllByUserID 的空指针访问。后面更新到最新的 2.4.2 版本就可以了。

总结

Loki 在使用的过程中,确实比较方便简单,特别是集合了 Grafana 的查询面板以及它的类 Prometheus 的标签机制,让我们的日志解决方案更加轻量。使用 Loki 期间也确实遇到了很多问题,大伙如果有兴趣的话,可以尝试上手,后续一起交流探讨。


感兴趣的朋友可以搜一搜公众号「 阅新技术 」,关注更多的推送文章。
可以的话,就顺便点个赞、留个言、分享下,感谢各位支持!
阅新技术,阅读更多的新知识。
阅新技术


lincoln
57 声望12 粉丝

分享有深度、有启示的技术文章;


引用和评论

0 条评论