vlambda博客
学习文章列表

京东到家Loki日志系统实践

  1. 背景

  2. Loki日志系统
    2.1 Loki架构
    2.2 Loki读写组件
    2.3 Loki查询语法

  3. 京东到家应用日志系统
    3.1 架构图
    3.2 日志接入
    3.3 实时日志
    3.4 历史日志
    3.5 技术难点
    3.6 配置文件

  4. 总结及规划


1、背景

随着业务的高速发展,目前基于ELK架构的日志系统无法满足京东到家的日志存储和查询需求。这是因为ELK架构中要用全文索引来支撑搜索服务,需要为日志的原文建立反向索引,这会导致最终存储数据相较原始内容成倍增长,产生较高的存储成本。不管数据将来是否会被搜索,都会在写入时因为索引操作而占用大量的计算资源,这对于日志这种写多读少的服务也是一种计算资源的浪费。另外日志采集无法自动化,新的日志需要运维手动加入。针对这些痛点,我们调研了当前流行的日志系统,最终选择了Loki这个新兴日志系统作为ELK架构日志系统的替代。

以下是根据ELKLoki优缺点进行对比


优点

缺点

ELK

1.可实现更复杂的查询;
 2.
适合现有环境,根据需求在kibana制作图表,更加可视化;
 3.
分片机制提供更好的分布性,将索引分割到不同容器或者分片中,可以存在单个节点或多个节点,在集群节点间平衡这些分片,为了更好地扩展索引和搜索负载;
 4.
分片高可用,一个分片可以设置多个复制,使得某台服务器宕机的情况下,集群仍旧可以照常运行,并会把由于服务器宕机丢失的复制恢复到其它可用节点上,复制每个分片提供数据备份,防止硬件问题导致数据丢失;

1.数据库字段太多,查询太慢,索引没有办法再做优化;
 2.
建立索引占用大量计算资源;
 3.
存储数据相较于原始内容成倍增长,增加存储成本
 4.
日志采集无法自动化

Loki

1.      不对日志进行全文索引,只索引与日志相关的元数据的标签,Loki通过标签对日志进行索引和分组,这使得日志的扩展和操作效率更高;
 2.
资源消耗少,轻便;
 3.
使用了类似Prometheus的方式进行日志的匹配过滤,查询速度快;
 4.
特别适合储存 Kubernetes Pod  日志。诸如 Pod 标签之类的元数据会被自动删除和编入索引;
 5.Grafana
原生支持;
 6.
后端存储选择Cassandra时,空间大约是原始日志的1/6
 7.api
支持websocket协议

 

 

1. 受制于该工具比较新,很多地方还待完善。如dashboardLoki的支持力度远远不够。

 

2、Loki日志系统

        LokiGrafana Labs 团队最新的开源项目,是一个水平可扩展,高可用性,多租户的日志聚合系统。设计经济高效且易于操作,它不会为日志内容编制索引,而是为每个日志流编制一组标签

Loki日志系统由以下3个部分组成:

       loki是主服务器,负责存储日志和处理查询。

      promtail是专为loki定制的客户端,负责收集日志并将其发送loki

      Grafana用于 UI展示(可以自己开发前端页面来替代)。

 

2.1 Loki架构

           

               

 

       Promtail开源客户端负责采集并上报日志;

       Distributor:日志写入入口,将数据转发到Ingester

•    Ingester:日志的写入服务,缓存并写入日志内容和索引到底层存储;

       Querier:日志读取服务,执行搜索请求;

 

 

Distributor

       promtail收集日志并将其发送给lokiDistributor就是第一个接收日志的组件。由于日志的写入量可能很大,所以不能在它们传入时就将它们写入存储中,需要批处理和压缩数据。Loki通过构建压缩数据块来实现这一点,方法是在日志进入时对其进行gzip操作,组件ingester是一个有状态的组件,负责构建和刷新chunck,当chunk达到一定的数量或者时间后,刷新到存储中去。每个流的日志对应一个ingester,当日志到达Distributor后,根据元数据和hash算法计算出应该到哪个ingester上面。

 

Ingester

       接收到日志并开始构建chunk,基本上就是将日志进行压缩并附加到chunk上面。一旦chunk“填满(数据达到一定数量或者过了一定期限),ingester将其刷新到数据库。对块和索引使用单独的数据库,因为它们存储的数据类型不同。 

刷新一个chunk之后,ingester然后创建一个新的空chunk并将新条目添加到该chunk
 

Querier

   读取就非常简单了,由Querier负责给定一个时间范围和标签选择器,Querier查看索引以确定哪些块匹配,并通过greps将结果显示出来。它还从Ingester获取尚未刷新的最新数据。

对于每个查询,一个查询器将为您显示所有相关日志。实现了查询并行化,提供分布式grep,使即使是大型查询也是足够的。

 

2.2 Loki读写组件

写数据

日志数据的写主要依托的是DistributorIngester两个组件,整体流程如下:

1.     Distributor收到 HTTP 请求,用于存储流数据

2.     通过 hash 环对数据流进行 hash

3.    Distributor将数据流发送到对应的Ingester及其副本上

4.     Ingester新建 Chunk 或将数据追加到已有Chunk

5.     Distributor通过 HTTP连接发送响应信息

 

读数据

1.  Querier收到 HTTP 请求(来自Granfana或者自己开发的前端)

2.      Querier将请求发送至Ingester用以获取内存数据

3.      Ingester收到请求后返回符合条件的数据

4.     如果没有Ingester返回数据,Querier从后端存储加载数据并执行查询

5.     Querier遍历所有数据并进行去重处理,通过HTTP连接返回最终结果

 

2.3 Loki查询语法

选择器

对于查询表达式的标签部分,将放在{}中,多个标签表达式用逗号分隔:

{app="mysql",name="mysql-backup"}

支持的符号有:

            = 完全相同。

            != 不平等。

            =~ 正则表达式匹配。

            !~ 不要正则表达式匹配

 

过滤表达式

编写日志流选择器后,您可以通过编写搜索表达式进一步过滤结果。搜索表达式可以文本或正则表达式。

如:

      {job=“mysql”} |= “error”

支持多个过滤

      {job=“mysql”} |= “error” !=“timeout”

目前支持的操作符:

      |= line包含字符串。

      != line不包含字符串。

      |~ line匹配正则表达式。

      !~ line与正则表达式不匹配 

 

3、京东到家应用日志系统

   到家运维部基于loki日志系统,开发出到家应用日志分析平台。具体的技术方案如下:

* 前端UI 官方是使用Grafana进行前端展示,我们使用python/flask开发前端页面,整合到运维管理平台中。

后端存储选择cassandra分布式存储系统,可以横向扩容。

*     研发在页面自定义要收集的日志文件,利用promtail文件发现机制自动进行日志收集。

* 支持实时展示日志内容,以及对历史日志文件进行自定义搜索。

 

3.1 架构图

京东到家Loki日志系统实践


3.2 日志接入

京东到家Loki日志系统实践

 

 

            选择应用、主机,输入自定义的日志文件。

            调用应用服务器上的saltstack管理客户端,将待采集日志文件路径写入主机promtail日志采集客户端对应文件中

            利用promtail文件自动发现机制,发现新加入的日志,将日志采集发送到Loki server

 

3.3 实时日志

京东到家Loki日志系统实践

 

            调用Loki api 通过websocket实时展示日志内容。

 

3.4 历史日志

京东到家Loki日志系统实践

 

选择应用,主机及日志,输入多个关键字进行内容过滤,多个关键字中间使用空格间隔


在实际生产环境中(148/256G内存/12*6T sata硬盘的存储型物理机)对10T数据进行多关键字、多日志文件进行查询,5s内返回查询结果。

3.5 技术难点

    日志路径采用文件监听技术,配置日志路径更加灵活,不需要重新启动客户端。

    采用分布式数据存储Cassandra,可以横向扩容。

    实时日志采用websocket技术实现。

    在所有服务器部署Promtail客户端工作量比较大,我们采用将客户端打包到操作系统镜像中,这样新的机器无需再安装客户端。

3.6 配置文件示例

下面是到家的Loki 相关配置文件,供大家参考。

LokiServer配置:auth_enabled: false #关闭认证,对数据来源客户端不做认证server:  http_listen_port: 3101  #loki http端口 ingester:  lifecycler:    address: 127.0.0.1   #ingester地址,默认为本机127.0.0.1,如果有多台server也可以写多个    ring: kvstore: store: inmemory #使用内存做为ingester存储 replication_factor: 1 final_sleep: 0s  chunk_idle_period: 5m #在没有更新之前chunk在内存中的时间  chunk_retain_period: 30s  #刷新后应在内存中保留多长时间  storage_config:#存储配置 cassandra:#使用cassandra addresses: x.x.x.x #cassandra的IP keyspace: lokiindex #cassandra的keyspace    auth: false    #关闭cassandra认证 schema_config: configs: - from: 2020-07-01 store: cassandra #数据存储方式为cassandra  object_store: cassandra schema: v11 index: prefix: index_ #index表的前缀 period: 168h #index每张表的时间范围7天 chunks: prefix: chunk_ #chunks表的前缀       period: 168h  #chunks每张表的时间范围7天 limits_config: ingestion_rate_mb: 50 #每个用户每秒的采样率限制 enforce_metric_name: false reject_old_samples: true  reject_old_samples_max_age:168h chunk_store_config: # 最大可查询历史日期 7天max_look_back_period: 168h # 表的保留期7天table_manager: retention_deletes_enabled: true #超过retention_period时间历史数据可以删除  retention_period: 168h  #Promtail客户端:   server: http_listen_port: 0 #http端口,为0表示端口随机  grpc_listen_port: 0 #grpc端口,为0表示端口随机  # Positionspositions:  filename:/export/servers/promtail/tmp/positions.yaml #记录采集的文件路径与日志采集位置 # Loki服务器的地址clients:  - url:http://xx.xx.xxx/loki/api/v1/push scrape_configs: - job_name: daojia #job_name 用于标识抓取配置 file_sd_configs:#用于文件发现 - files: -'/export/servers/promtail/logpath.yaml'#具体文件         refresh_interval: 10s #文件检测间隔,当有新日志加入会自动发现并自动采集日志,无须客户端重启 - targets: - localhost #收集的主机 labels:    host: 1.1.1.1 #给收集主机打标签host:1.1.1.1 log: gw #给收集主机打标签log: gw __path__:/export/servers/nginx/logs/gw.o2o.jd.local/gw.o2o.jd.local_access.log #要收集的日志路径

 

 

4、总结及规划

目前已经有1000多台应用服务器的日志收集到了基于Loki的到家日志系统中,每天的日志量占用空间才1.4T,原来在ES中,这么多的日志量需要近30T的存储空间,极大节省了硬件成本。而且根据前端研发提交过来的日志名称,可以自动化日志收集,减少了运维日志相关的手工操作,提高了运维的工作效率。

   整个日志平台只使用了148/256G内存/12*6T sata硬盘的存储型物理机,loki  servercassandra存储都部署在这台机器上。后续日志客户端接入量增加后, Loki server可以通过增加节点进行扩容,提高日志接收能力。后端存储Cassandra也可以通过增加Cassandra集群节点来横向扩容。另外前端展示方面,后续要针对搜索结果进一步分析处理和展示