Logstash问题汇总

背景

在公司采用ELK架构之后,度过了开始——不稳定——稳定期之后,来总结一下期间出现过的问题以及解决方案

问题

logstash能否try catch

在logstash中,是不能够使用类似Java的try catch语句的,那么问题来了,如果我们从filebeta传入数据,通过logstash json插件解析,logstash 解析失败了,那这些数据是不是就丢了?但是我想保留这部分数据,该怎么做?

解决方案:

通过json-parse-failed,具体用法如下:

input {
   beats{
     port => "5057"
   }
}

filter {
    json {
      source => "message"
      tag_on_failure => ["json-parse-failed"]
    }
    date {
      match => ["#datetime","yyyy-MM-dd HH:mm:ss.SSS"]
      target => "@timestamp"
    }
}  
output {
    if "json-parse-failed" in [tags] {
      elasticsearch {
        hosts => ["xxx:9200"]
        index => "biz-error-logs-test-%{+YYYY.MM.dd}"
        user => xxx
        password => "xxxx"
       }
    }else{
      elasticsearch {
        hosts => ["xxx:9200"]
        index => "%{#fb_collect_app}-%{+YYYY.MM.dd}"
        user => xxx
        password => "xxxx"
      }
    }
}

相当于是将json解析失败的数据保留到biz-error-logs-test-%{+YYYY.MM.dd}这个索引里面了,如果我们没找到相关数据,就去这个索引里面找

logstash 数据备份,最长保留期限

其实对于这个问题来说,其实是个伪命题,虽然logstash可以做持久化,但是它不是专门做的,它内部队列的大小是一定的(磁盘空间),并不适合高并发量的应用,也不适合做,它并不能保证数据不丢失,事实上,对于高并发的应用,架构应该是filebeat ——> kafka——>logstash——> ES,这种在很大程度上保证了数据不丢失

不过,logstash也可以做,在logstash.yml添加以下内容:

queue.type: persisted
path.queue: /usr/share/logstash/data    #队列存储路径;如果队列类型为persisted,则生效
queue.page_capacity: 250mb         #队列为持久化,单个队列大小
queue.max_events: 0               #当启用持久化队列时,队列中未读事件的最大数量,0为不限制
queue.max_bytes: 1024mb           #队列最大容量
queue.checkpoint.acks: 1024       #在启用持久队列时强制执行检查点的最大数量,0为不限制
queue.checkpoint.writes: 1024     #在启用持久队列时强制执行检查点之前的最大数量的写入事件,0为不限制
queue.checkpoint.interval: 1000   #当启用持久队列时,在头页面上强制一个检查点的时间间隔

持久化队列将事件存储在硬盘上,但由于硬盘空间也不是无限的,所以需要根据应用实际需求配置持久化队列的容量大小。Logstash持久化队列容量 可通过事件数量和存储空间大小两种方式来控制,在默认情况下 Logstash 持久化队列容量为 1024MB,而事件数量则没有设置上限。当持久化队列达到了容量上限,Logstash 会通过控制输入插件产生事件的频率来防止队列溢出,或者拒绝再接收输入事件直到队列有空闲空间。持久化队列事件数量容量可通过 queue. max events 修改,而存储空间容量则可通过 queue. max bytes 来修改。

当 Logstash 开启了持久化队列时,即使 Logstash 发生了宕机,其实也不会造成数据的丢失。对于 ES 侧而言,Logstash 是调用 Bulk API 向 ES 批量输出事件的,只有 ES 输出插件确认已经处理了事件,持久化队列才会将事件从持久化队列即磁盘中删除。因此,当 Logstash 重启时,仍然能从磁盘中恢复之前未曾处理的数据。

死信队列介绍可参考:logstash高可用之队列、死信队列

ES数据重复采集问题

在项目运行的过程中,忽然发现某一天的数据采集每条日志都采入了两次,这是什么原因?

主要有两方面原因:

  • 多个filebeat采集同一条日志发送给logstash;
  • Filebeat 在处理过程中关闭,或者在确认事件之前断开了连接(filebeat重试功能)

我们是第一个原因,因为我们项目中,一个pod有两个容器,一个是filebeat容器,一个是app容器,然后我们起了两个pod,并且我们将日志挂到了共享磁盘上,就导致两个filebeat读了同一个文件两次

解决方案

要么改filebeat扫描位置,要么在logstash统一处理,但是filebeat那块处理起来有点麻烦,需要制定规则,所以我们统一在logstash这里做了处理

需要处理两部分

  • logstash插件fingerprint

    这个东西就类似一个指纹,给你唯一标识原始事件。可以将原始事件中的一个或多个字段(默认为消息字段)作为源来创建一致的哈希值 (hash)。一旦创建了这些指纹,你就可以将其用作下游Elasticsearch输出中的文档 ID

  • es添加document_id

    Elasticsearch 的索引编制过程。 Elasticsearch 提供了一个 REST API 来为你的文档建立索引。你可以选择提供唯一代表你的文档的 ID,也可以让 Elasticsearch 为你生成ID。如果你将 HTTP PUT 与索引 API 一起使用,Elasticsearch 希望你提供一个 ID。如果已经存在具有相同 ID 的文档,Elasticsearch 将用你刚才提供的文档替换现有内容-最后索引的文档将获胜。如果使用 POST 动词,则即使语料库中已经存在内容,Elasticsearch 也会生成具有新ID的新文档。例如,假设你刚在一秒钟之前为博客文章建立了索引,并使用 POST 动词重新发送了同一篇博客文章,Elasticsearch 创建了另一个具有相同内容但新具有 ID 的文档

具体用法

input {
    http {
        id => "data_http_input"
    }
}
 
filter {
    fingerprint {
        # 在这里可以定义任何你想定义的字段,用部分字段进行加密
        source => [ "sensor_id", "date"]
        # 输出到指定字段
        target => "[@metadata][fingerprint]"
        # 加密算法
        method => "SHA1"
        # 密钥
        key => "liuxg"
        concatenate_sources => true
        base64encode => true
    }
}
 
output {
    stdout {
        codec => rubydebug
    }
 
  elasticsearch {
        manage_template => "false"
        index => "fingerprint"
     	hosts => "localhost:9200"
     	# es文档id
        document_id => "%{[@metadata][fingerprint]}"
    }
}

参考文献: Beats:如何避免重复的导入数据

logstash采集json之后,有好多/u0000问题

这个问题比较恶心,总体来说是编码问题,网上很多帖子都采用下列方案来解决:

    filter {
        mutate{
          gsub => [ "message", "\u0000", " " ]
        }
	}

但其实是不对的,本质问题还是编码问题,你如果按照上面配置后,就会将一个原本是json的内容,变成不是json了,也会丢失很多数据,这种解决方案是下下策

解决方案

本质上还是应该在编码问题上找,要么在logstash上处理编码,要么在filebeat处理编码,还有一种是在日志输出上处理编码(比如logback)

我这里在filebeat上处理的编码,因为不是所有项目都用到了logback,还有,在logstash上处理也行(我在logstash上没找到encoding类似的参数=.=//)

filebeat配置如下:

filebeat.inputs:
- type: log
  paths:
  - /home/logs/biz/*.log
  encoding: utf-8
  fields:
    fb_collect_type: bizlog 
    send_kafka: "false"
  fields_under_root: true
- type: log
  paths:
  - /home/logs/sys/*.log
  encoding: utf-8
  fields:
    fb_collect_type: syslog 
  fields_under_root: true
output.logstash:
  hosts:
  - "xxxxxx"
processors:
  - drop_fields:
      fields: ["ecs", "agent", "log"]

或许这个方案还有问题,我现在还是或多或少的露一点日志,现在这里记一下,后续解决了,再来更新解决方案

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值