Logstash双配置文件引发Elasticsearch重复事件,如何解决?
哈哈,这个问题我太熟了!你这情况十有八九是Logstash同时加载了两个配置文件,导致同一个事件被两套输入-过滤-输出流程各处理了一遍,自然就生成了重复的副本。我给你拆解下原因和解决办法:
先确认问题根源
你大概率是用了这样的启动命令:
bin/logstash -f /your/config/directory/
Logstash的-f参数如果指向目录,会自动加载目录下所有.conf文件,把它们合并成一个完整的配置。这时候哪怕你只测试其中一个输入源,另一个配置的输入(比如监听文件、Beats端口的类型)只要触发,或者两个输出都往同一个ES索引写,就会导致同一个事件被处理两次,生成重复数据。
解决方案1:临时测试用——每次只加载单个配置
如果你只是单独测试test1或者test2,启动时直接指定单个文件就行:
测试test1时:
bin/logstash -f /your/config/directory/test1.conf
测试test2时:
bin/logstash -f /your/config/directory/test2.conf
这样Logstash只会运行对应配置的流程,不会重复处理事件。
解决方案2:长期最优解——合并配置,复用过滤器
既然两个配置的过滤器完全相同,不如把它们合并成一个配置文件,用type或者标签区分输入,这样既避免重复加载,又能复用过滤器逻辑,还能减少Logstash实例的资源占用。示例如下:
# 合并后的 combined.conf input { # test1的输入,给个type标记 beats { port => 5044 type => "test1" } # test2的输入,同样标记type file { path => "/var/log/test2.log" type => "test2" } } filter { # 这里是你共用的所有过滤器逻辑,不用重复写两遍 grok { match => { "message" => "%{COMBINEDAPACHELOG}" } } mutate { remove_field => ["message"] } # 如果需要针对不同输入做微调,还可以加条件判断 if [type] == "test1" { mutate { add_tag => ["from_test1"] } } } output { elasticsearch { hosts => ["http://localhost:9200"] index => "shared-index-%{+YYYY.MM.dd}" } }
这样一个Logstash实例就能处理两个输入源,每个事件只会被处理一次,从根源上解决重复问题。
解决方案3:必须分开配置时——ES侧强制去重
如果因为业务原因必须保留两个独立的配置文件,那可以给每个事件生成唯一标识,让ES自动覆盖重复数据:
- 在两个配置的过滤器里,添加一个唯一的元数据字段:
filter { mutate { # 用type、时间戳、主机名组合成唯一ID,你也可以根据实际字段调整 add_field => { "[@metadata][unique_id]" => "%{type}-%{@timestamp}-%{host}" } } }
- 在两个配置的ES输出里,指定
document_id为这个唯一ID:
output { elasticsearch { hosts => ["http://localhost:9200"] index => "shared-index" # 用唯一ID作为文档ID,重复事件会直接覆盖旧的 document_id => "%{[@metadata][unique_id]}" } }
这样就算同一个事件被两个流程处理,ES会因为文档ID相同而覆盖,不会生成重复副本。
总结
优先选方案2,合并配置不仅解决重复问题,还让维护更简单;临时测试用方案1;实在不能合并的话用方案3兜底。
内容的提问来源于stack exchange,提问作者Ofek Hod
相关产品推荐
相关产品推荐

