记录一次filebeat日志丢失的问题

在java化项目中,部署到k8s集群后,一度出现无法定位问题的情况。起初怀疑是日志调用链改造导致的,也修复了一些问题,但没有解决根本问题


问题表现

  1. 日志搜集不够实时
    在k8s中执行kubectl logs --tail=500 test-6bb5648c4c-4fmrr -n testns随机取一条记录,在kibana界面无法查询
  2. 日志没有被搜集
    上个问题或许过一段时间能查询到,但有些日志则是完全无法查到,就算过了10分钟也无法查到
  3. 查看近几天的日志,发现如下规律:


    image.png

由上图可知,日志在某个时间正常,然后越来越少。

问题定位

  1. 首先查看elasticsearch
    • 查看索引状态,一切正常
    get http://localhost :9200/test*
    green  open  test-2020.09.08                         6xRJEYkbRa-EIJRwFvXaow   3   1   37078449            2    205.3gb         97.7gb
    green  open   test-2020.09.07                         RrUCdqUFR26FBKcM91yMiA   3   1   39189071            0    190.2gb         95.1gb
    
    • 查看日志:除了个几个由于mapping 解析错误的日志,没有异常
  2. 再定位logstash日志
    • 曾发现有大量的grokFailure日志,这个问题也会导致日志丢失,修正了grok,但依然出现如上问题
    • 也曾发现由于匹配规则导致的一些日志遗漏。但同样没有解决问题
  3. 再查看kafka是否异常
    • 首先定位消费是否有延后,执行如下命令
      ./kafka-consumer-groups.sh --bootstrap-server 10.64.175.183:9092 --describe --group test_k8
      发现一切正常,并没有阻塞导致日志查不到的现象。
  4. 定位filebeat
    通过以上定位,那基本出问题的可能只能是filebeat了。
    • 查看filebeat日志
      kubectl logs filebeat-7sx7r -n kube-syste
       {"monitoring": {"metrics": {"beat":{"cpu":{"system":{"ticks":660940,"time":{"ms":2108}},"total":{"ticks":7503770,"time":{"ms":25202},"value":7503770},"user":{"ticks":6842830,"time":{"ms":23094}}},"handles":{"limit":{"hard":1048576,"soft":1048576},"open":21},"info":{"ephemeral_id":"3d0c7300-0a5b-405f-8fba-356fc3b3c085","uptime":{"ms":12930017}},"memstats":{"gc_next":131488384,"memory_alloc":74631384,"memory_total":1093590548216},"runtime":{"goroutines":128}},"filebeat":{"events":{"active":145,"added":61940,"done":61795},"harvester":{"open_files":13 1,"running":131,"started":2}},"libbeat":{"config":{"module":{"running":0}},"output":{"events":{"acked":61793,"batches":47,"total":61793}},"outputs":{"kafka":{"bytes_read":51946,"bytes_write":9380778}},"pipeline":{"clients":4,"events":{"active":573,"filtered":2,"published":61938,"total":61940},"queue":{"acked":61793}}},"registrar":{"states":{"current":39,"update":61795},"writes":{"success":49,"total":49}},"system":{"load":{"1":3.62,"15":3.97,"5":4.14,"norm":{"1":0.2263,"15":0.2481,"5":0.2588}}}}}}```  
      
    上面是filebeat自带的monitoring日志,也就是filbeat的运行状态,我们重点关注:
    "harvester":{"open_files":131,"running":131,"started":2}
    发现filbeat居然持有这么多文件,也就是说还有131个文件还在搜集的状态。
    • 回到对应节点,查看文件状态。lsof |grep deleted

    之所以有这个步骤,1是因为之前cmo发现k8s报错了,大量的文件显示被删除,但实际没有删除,仍然被filebeat持有。不过因为当时只发现只有某个节点存在这种现象,不是普遍现象,所以没有在意。2.是filbeat持有这么多文件不正常,现在发现是只要部署了该应用的节点就有这种现象,也就是filebeat启动了搜集。

终极原因

定位到上面,其实已经差不多了,但要想揭开真相,还需要解决以下三个问题:

  1. 为什么持有这么多文件?
  2. 为什么持有这么多文件会导致上面的一系列问题呢?
  3. 还有没有其他问题呢?
    除了第三个我们可以再解决了前面两个问题之后观察就能看出,那么我们重点就是上面两个问题了。

出现上述情况,直接原因我们可想而知是在##系统删除了相关的日志文件之后,filbeat还持有文件。

这里可能有两个原因:

  1. filebeat持有的文件没有搜集完,所以继续持有,也就是那么多文件它都没有搜集完。
  2. filebeat已经搜集完了,但仍然没有释放文件。

最开始我们怀疑是因为filebeat没有配置正确,比如close_*配置选项。最后结合k8s中日志的轮转方式排查,filebeat采取的是默认配置:

  1. close_renamed :这种情况在日志轮转的时候发生,默认值是flase。
  2. close_removed: 这个一般发生在日志真正删除后。 默认值是true。也就是会出现上述情况,日志被删除了,filebeat仍继续持有文件。
  3. close_inactive: 默认值是5分钟

理论上说这个配置是正确的,因为要保证日志搜集完,且发生轮转的时候日志依然继续搜集,也能基本上保证搜集完以后关闭harvest。那么我们暂时排除第二种可能。

filebeat搜集速度过慢

我们继续定位第一种可能:filebeat持有的文件没有搜集完,所以继续持有,也就是那么多文件它都没有搜集完。

  • 如何定位?
    现在单从filebeat的日志已经无法看出了。于是想到去看filebeat的注册表,filebeat的registry文件中存放的是被采集的所有日志的相关信息。

    1. 进入到k8s中相应的filebeat节点
      kubectl exec -it filebeat-lh2bq -n kube-system /bin/bash
    2. 查看其中registry文件,截取一条
    {"source":"/data/docker/containers/0eb0397149bcd687a40cd4313b853354ff43e41a6257ccb5ab972d7170881037/0eb0397149bcd687a40cd4313b853354ff43e41a6257ccb5ab972d7170881037-json.log","offset":114912226,"timestamp":"2020-09-08T08:43:41.079295459Z","ttl":-1,"type":"container","meta":null,"FileStateOS":{"inode":8143887,"device":64512}}
    

    重点关注inode和offset,inode代表某个文件,offset代表filebeat读到该文件的位置,字节数。

    1. 结合使用stat查看所在node的真正文件状态,持续观察(也就是每隔一段更新registry信息):
      发现,当文件被删除时,inode依然还在,同时filebeat中的注册表信息依然在更新,也就是offset持续增长,
      114912226->117408238->122393532。最后缓慢增长到198596250,也就是200M。至此filebeat关闭这个文件,文件被真正删除。

docker中的配置:

 "storage-opts":["overlay2.override_kernel_check=true"],
  "log-driver": "json-file",
   "log-opts": {
  "max-size": "200m",
  "max-file": "3"
 }

至此就可以解释上面两个问题了,filebeat没有搜集完导致一直持有文件,文件轮转越快,filebeat持有的文件数越多,搜集性能相应的下降,因此越来越慢,最终导致日志不能实时的查询,以及日志丢失的问题(也许并不会丢失,只是长时间查不到)。

解决问题

既然发现了这个问题就要着手解决
最开始想到两个解决方案:

  1. 日志轮转文件数设置更大
  2. 日志级别设置设置高一点,之前是debug

读者可以想一想这两个方案有没有问题?

显然是有问题的,这两个方案并没有真正解决问题,只是延缓了问题的发生。第一个问题照旧,第二个在并发量暴增或者日志需要放开是就有问题。

问题真正的根因所在是filebeat搜集的速度跟不上日志打印的速度。 我们必须找出filebeat慢的原因,按理说读文件应该相当快才对,肯定是有哪里的配置不对,导致filebeat的性能如此的低。
最终重新审视filebeat部署文档,发现我们部署的时候限制了filebeat的性能:

# filebeat.yaml部分片段 
resources:
  limits:
    memory: 500Mi
    cpu: 200m
  requests:
    cpu: 200m
    memory: 500Mi

这里的200m代表了200*1/1000 个cpu,也就是只有20%的cpu,这样显然filebeat在多线程处理的时候性能被大大压缩,也就无法跟上我们日志输出的速度。而且k8s具有cpu压缩的问题,它在低cpu的时候仍然能运行,我们无法监控到错误,所以很难发现。
修改配置文件取消限制,重新部署filebeat 解决
再次查看cpu:

cpu状态

再次查看日志,果然 飞起!

你可能感兴趣的:(记录一次filebeat日志丢失的问题)