kafka使用_Kafka配合ELK的最佳使用姿势

7091eee1759cc0634df0b7876c6057b9.png

作者

兴丰

阿里云Elasticsearch团队

高级开发工程师

ELK是Elasticsearch、Logstash、Kibana三大开源框架首字母大写简称,也称为Elastic Stack。Elasticsearch是一个搜索和分析引擎。Logstash是服务器端数据处理管道,能够同时从多个来源采集数据、转换数据,然后将数据发送到Elasticsearch。Kibana提供了图形和图表对数据进行可视化。用户通常在ELK前引入消息队列比如Kafka进行数据缓冲,提升系统的可靠性。

通常的系统架构和数据处理流程如下:

08ccc2d1751660cb0edf654225a013a7.png

阿里云Elasticsearch已经支持完整的ELK组件一键部署,配合Kafka等消息队列,使用顺畅。

Houston, We Have A Problem

此前,某客户反馈,ES集群写入报错“es_rejected_execution_exception”,写入速度上不去,kafka堆积严重。登录监控查看后,发现ES节点的write队列堆积严重,cpu使用率很低,节点的load非常高。

e8df4ada4e265cc5d3a2a63364d85d28.png

788b7c8baa727494934440dfc803738d.png

首先登录ECS执行top查看cpu情况

1edcbd6313ca37cffacba1c7b48c4054.png

各cpu wait都非常高,超过20%。

b331aa2901277cff005863dbcdcf011a.png

查看当前磁盘的状态,从iostat的信息来看,磁盘的写入量不高,延迟虽然稍微有点大,但基本符合预期。联系块存储的值班同学,反馈云盘的后端各项指标正常。

进一步查看load高的进程和线程是哪些。

8f80cf3c37a74b0cd9973eca73496448.png

这次有了新的发现,这些线程基本都属于同一个进程,就是Elasticsearch所在的进程。这些线程都处于D状态,ps命令输出的linux的进程状态有下面几种:

D    uninterruptible sleep (usually IO)

R    running or runnable (on run queue)

S    interruptible sleep (waiting for an event to complete)

T    stopped by job control signal

t    stopped by debugger during the tracing

W    paging (not valid since the 2.6.xx kernel)

X    dead (should never be seen)

Z    defunct ("zombie") process, terminated but not reaped by its parent

linux的top命令在计算负载时包含了处于D和R状态的进程和线程,那么,load高的原因就很明确了——ES有很多线程阻塞在IO中。

真相大白

用jstack获取Es进程,随便搜了几个线程id, 发现全是write线程,而且都阻塞在translog的sync函数上。

c2bc7e58f253fc0cdae94a02c500c96e.png

根据ES官方文档的介绍 ,对于每一个bulk请求,每个shard都会调用系统的fsync,保证translog持久化到磁盘上,避免硬件故障导致数据丢失。

4585c24986dba4bfd12921a685eb4029.png

此问题看上去应该是每个shard每次requst分到的条数太小,频繁触发fsync导致的。用户提到logstash消费kafka然后采用bulk推送,每次3000条,每个doc 1KB大小。但是这个描述和kibana中的监控不符合,不少索引每秒只有几十篇doc写入,如果每个索引都是bulk 3000条,则曲线不会是下面这种平滑的曲线,应该是非常明显的锯齿状,波峰是3000,波谷是0。

d41da822e07bedd3b23f2028c609eb99.png

在和用户仔细沟通后发现,所有索引的源数据都混在Kafka的同一个topic里面,logstash每次bulk数据包含几十个索引,总共上百个shard,每个shard在每次请求只能分到几十条doc,导致write线程平均每处理几十条doc就要fsync translog一次,延迟再低的SSD也支持不住。

解决方案

通常,对于一般的性能问题没有加节点解决不了的,如果有,那就升级节点规格,但费用成本较高。

临时方案
  • 调大bulk条数,控制每个请求在10MB到30MB之间,增加每次shard分到的doc条数,间接降低fsync的频率

  • 适当增加写入队列大小,避免集群偶尔抖动导致队列快速塞满而报错

  • 修改索引setting,将translog索引的刷新(flush)改为异步

修改参数如下,除了translog必须为aysnc,其他的可按需调整。

"settings": {    "index": {        "refresh_interval": "60s",        "translog": {                   "flush_threshold_size": "2gb",                   "sync_interval": "100s",                   "durability": "async"               },        "merge": {                   "policy": {                       "segments_per_tier": "30",                       "max_merged_segment": "512m"                   }               }       }}
终极方案 & 最佳实践

需要把不同索引的数据拆分到不同的Kafka topic中,和上面的临时方案结合效果更佳。

  • 避免每个shard在每次bulk请求分到的doc太少,产生频繁的fsync

  • 当上游数据产生太快,ES集群性能不足或者故障恢复、索引重建时,可以按优先级消费topic,推送指定索引到ES,提高整个系统的稳定性

实行效果

该客户采用了临时方案,吞吐很快就上去了,节点load也降下来了,kafka的堆积数据很快消费完,不再有堆积。

0d4ee3f89fff5d94987822b097b43f7a.png

396a9a0901d60aef7b7acce684247f86.png

以前写入50k/s会产生瓶颈,现在峰值可达到100k/s,从cpu和磁盘io的监控来看,整体还有相当大的提升空间。

3184aa36f1b5b6ccd7a63aa2bf439190.png

虽然translog改为异步后,写入性能得到了极大的提升,但write线程从节点队列获取每个shard的请求数据时需要加锁,每次获取数据条数太少,频繁的加锁会有不少cpu消耗在自旋锁上。如果索引按topic拆分,写入性能还将有进一步的提升。

END

|  往期精彩  |

2f3ab92315fd7c5780f9015004929592.png

417d8eb4677589c8a2fd823dc6a5909f.png

7ce8472efe8ca1514d147bd820d09fda.png

3a8ef4e660c51f73d983e8e97fa0bb1f.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值