0x01 前言

elastic stack在4月11日发布了7.0正式版,而我也在第一时间完成家里测试环境的升级工作。因为我是从6.7.0升级到7.0的,同时经过x-pack升级助手的检查,升级前后均没问题。

但在升级filebeat之后却出现大量错误日志,而在此之前,我QQ群内一位朋友也发现类似的问题,而他找出了报错的原因。

0x02 BUG

首先是日志,为了方便查看,我对日志格式做了些调整:

以上是logstash7.0的日志,而且这些日志只出现在使用7.0版本的filebeat服务器中。由以上日志信息可以发现处理名为agent的字段失败,而出现illegal_state_exception的原因一般是字段异常。

经过群友的耐心debug发现这个问题是因为我以前文章中logstash过滤器的grok规则导致的。

如果大家有关注我的博客,可以在以下文章中找到相关的nginx日志的grok规则:

以上文章中均包含以下字段:

它匹配的是日志中的useragent,如下所示:

上述的分词规则会匹配被双引号包裹的相关字符,并赋值给名为agent的字段,最终导入到elasticsearch,结果如下:

而useragent分析规则则是从agent字段中取值并调用useragent 插件处理,处理完的结果赋值给名为ua的字段,结果如下:

这个日志分词和useragent分析功能在7.0之前是正常的;但从7.0开始,agent字段属于内置的保留字段,主要记录着该beat所在的主机的一些信息:

所以问题很简单,就是新旧版本的字段冲突了。

0x03 DEBUG

既然字段名冲突,那只需要修改字段名即可,但实际上没那么简单。

因为数据是不断传入logstash进行处理的,所以logstash和elasticsearch的服务不能长时间中断;其次是历史数据不能丢失。

因为我只有一个logstash节点,所以修改过滤器规则后重启logstash会导致一小段时间的服务中断,而且服务中断期间的日志会丢失。但对于我的环境来说,这一部分日志的丢失是可以接受的;如果需要高可用,则建议部署多个logstash节点后再进行调整。

首先修改过滤器规则:

我修改了grok规则中与useragent插件中的字段名称为ngx_ua,修改完成后即可重启logstash。

然后需要使用kibana中的Dev Tools调用elasticsearch API。首先建立一个新的索引:

然后修改别名的指向,在此之前先获取目前的别名指向情况:

接下来即可进行修改:

成功执行该API后,所有数据都会写入到public-nginx-index-v3索引中。

完成上述步骤后才可以进行历史数据字段名称的修改,要不然有可能会使历史数据受损或遭到污染。

对于历史数据,我才用较为简单的手段处理:将历史数据中的agent字段的数据传递给新字段ngx_ua,而后删除旧字段,最终将数据写入新索引。

这一系列步骤我通过reindex API完成:

上面命令的意思是将v2索引中的数据迁移至v3中,在这过程中将旧索引的agent字段赋值给新索引的ngx_ua字段后删除自身。

根据数据量的不同,reindex所需要的时间也各有长短,完成后即可删除该索引以减少空间消耗:

0x04 结语

为了减少不必要的操作,确保数据安全与洁净,建议对历史数据操作前先通过快照API对数据做快照;另外,在进行实操前需进行全盘规划。

整个过程会对IO造成极大压力,请适当调整elasticsearch节点数以均衡负载,减少对线上业务的影响。