Flink 实时写入数据到 ElasticSearch 性能调优

本文涉及的产品
实时计算 Flink 版,1000CU*H 3个月
简介: 线上业务反应使用 Flink 消费上游 kafka topic 里的轨迹数据出现 backpressure,数据积压严重。单次 bulk 的写入量为:3000/50mb/30s,并行度为 48。针对该问题,为了避免影响线上业务申请了一个与线上集群配置相同的 ES 集群。

作者:张刘毅

背景说明

线上业务反应使用 Flink 消费上游 kafka topic 里的轨迹数据出现 backpressure,数据积压严重。单次 bulk 的写入量为:3000/50mb/30s,并行度为 48。针对该问题,为了避免影响线上业务申请了一个与线上集群配置相同的 ES 集群。本着复现问题进行优化就能解决的思路进行调优测试。

测试环境

  • Elasticsearch 2.3.3
  • Flink 1.6.3
  • flink-connector-elasticsearch 2_2.11
  • 八台 SSD,56 核 :3 主 5 从

Rally 分布式压测 ES 集群

1.jpg

从压测结果来看,集群层面的平均写入性能大概在每秒 10 w+ 的 doc。

Flink 写入测试

配置文件

config.put("cluster.name", ConfigUtil.getString(ES_CLUSTER_NAME, "flinktest"));
config.put("bulk.flush.max.actions", ConfigUtil.getString(ES_BULK_FLUSH_MAX_ACTIONS, "3000"));
config.put("bulk.flush.max.size.mb", ConfigUtil.getString(ES_BULK_FLUSH_MAX_SIZE_MB, "50"));
config.put("bulk.flush.interval.ms", ConfigUtil.getString(ES_BULK_FLUSH_INTERVAL, "3000"));

执行代码片段

final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
 initEnv(env);
 Properties properties = ConfigUtil.getProperties(CONFIG_FILE_PATH);
 //从kafka中获取轨迹数据
 FlinkKafkaConsumer010<String> flinkKafkaConsumer010 =
     new FlinkKafkaConsumer010<>(properties.getProperty("topic.name"), new SimpleStringSchema(), properties);
 //从checkpoint最新处消费
 flinkKafkaConsumer010.setStartFromLatest();
 DataStreamSource<String> streamSource = env.addSource(flinkKafkaConsumer010);
10//Sink2ES
streamSource.map(s -> JSONObject.parseObject(s, Trajectory.class))
    .addSink(EsSinkFactory.createSinkFunction(new TrajectoryDetailEsSinkFunction())).name("esSink");
env.execute("flinktest");

运行时配置

3.jpg

任务容器数为 24 个 container,一共 48 个并发。savepoint 为 15 分钟:

4.jpg

  • 运行现象

(1)source 和 Map 算子均出现较高的反压

5.jpg

(2)ES 集群层面,目标索引写入速度写入陡降

平均 QPS 为:12 k 左右。

(3)对比取消 sink 算子后的 QPS

streamSource.map(s -> JSONObject.parseObject(s, FurionContext.class)).name("withnosink");

66.jpg

平均QPS为:116 k 左右。

有无sink参照实验的结论:

取消 sink 2 ES 的操作后,QPS 达到 110 k,是之前 QPS 的十倍。由此可以基本判定: ES 集群写性能导致的上游反压

优化方向

索引字段类型调整

77.jpg

bulk 失败的原因是由于集群 dynamic mapping 自动监测,部分字段格式被识别为日期格式而遇到空字符串无法解析报错。

解决方案:关闭索引自动检测。

6.jpg

效果: ES 集群写入性能明显提高但 Flink operator 依然存在反压:

7.jpg

降低副本数

curl -XPUT{集群地址}/{索引名称}/_settings?timeout=3m -H "Content-Type: application/json" -d'{"number_of_replicas":"0"}'

提高 refresh_interval

针对这种 ToB、日志型、实时性要求不高的场景,我们不需要查询的实时性,通过加大甚至关闭 refresh_interval 的参数提高写入性能。

curl -XPUT{集群地址}/{索引名称}/_settings?timeout=3m -H "Content-Type: application/json" -d '{ "settings": {  "index": {"refresh_interval" : -1   }   }  }'

检查集群各个节点 CPU 核数

在 Flink 执行时,通过 Grafana 观测各个节点 CPU 使用率以及通过 Linux 命令查看各个节点 CPU 核数。发现 CPU 使用率高的节点 CPU 核数比其余节点少。为了排除这个短板效应,我们将在这个节点中的索引 shard 移动到 CPU 核数多的节点。

curl -XPOST {集群地址}/_cluster/reroute  -d'{"commands":[{"move":{"index":"{索引名称}","shard":5,"from_node":"源node名称","to_node":"目标node名称"}}]}' -H "Content-Type:application/json"

以上优化的效果:

8.jpg

经过以上的优化,我们发现写入性能提升有限。因此,需要深入查看写入的瓶颈点。

在 CPU 使用率高的节点使用 Arthas 观察线程

9.jpg

打印阻塞的线程堆栈

"elasticsearch[ES-077-079][bulk][T#3]" Id=247 WAITING on java.util.concurrent.LinkedTransferQueue@369223fa
   at sun.misc.Unsafe.park(Native Method)
     -  waiting on java.util.concurrent.LinkedTransferQueue@369223fa
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.LinkedTransferQueue.awaitMatch(LinkedTransferQueue.java:737)
    at java.util.concurrent.LinkedTransferQueue.xfer(LinkedTransferQueue.java:647)
    at java.util.concurrent.LinkedTransferQueue.take(LinkedTransferQueue.java:1269)
    at org.elasticsearch.common.util.concurrent.SizeBlockingQueue.take(SizeBlockingQueue.java:161)
    at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

从上面的线程堆栈我们可以看出线程处于等待状态。

关于这个问题的讨论详情查看 https://discuss.elastic.co/t/thread-selection-and-locking/26051/3,这个 issue 讨论大致意思是:节点数不够,需要增加节点。于是我们又增加节点并通过设置索引级别的 total_shards_per_node 参数将索引 shard 的写入平均到各个节点上。

线程队列优化

ES 是将不同种类的操作(index、search…)交由不同的线程池执行,主要的线程池有三:index、search 和 bulk thread_pool。线程池队列长度配置按照官网默认值,我觉得增加队列长度而集群本身没有很高的处理能力线程还是会 await(事实上实验结果也是如此在此不必赘述),因为实验节点机器是 56 核,对照官网:

10.jpg

因此修改 size 数值为 56。

11.jpg

经过以上的优化,我们发现在 kafka 中的 topic 积压有明显变少的趋势:

12.jpg

index buffer size 的优化

参照官网:

13.jpg

indices.memory.index_buffer_size : 10%

translog 优化:

索引写入 ES 的基本流程是:

  • 数据写入 buffer 缓冲和 translog;
  • 每秒 buffer 的数据生成 segment 并进入内存,此时 segment 被打开并供 search 使用查询;
  • buffer 清空并重复上述步骤 ;
  • buffer 不断添加、清空 translog 不断累加,当达到某些条件触发 commit 操作,刷到磁盘;

ES 默认的刷盘操作为 Request 但容易部分操作比较耗时,在日志型集群、允许数据在刷盘过程中少量丢失可以改成异步 async。

另外一次 commit 操作是在 translog 达到某个阈值执行的,可以把大小(flush_threshold_size )调大,刷新间隔调大。

index.translog.durability : async
index.translog.flush_threshold_size : 1gb
index.translog.sync_interval : 30s

效果:

  • Flink 反压从打满 100% 降到 40%(output buffer usage):

14.jpg

kafka 消费组里的积压明显减少:

15.jpg

总结

当 ES 写入性能遇到瓶颈时,我总结的思路应该是这样:

  • 看日志,是否有字段类型不匹配,是否有脏数据。
  • 看 CPU 使用情况,集群是否异构
  • 客户端是怎样的配置?使用的 bulk 还是单条插入
  • 查看线程堆栈,查看耗时最久的方法调用
  • 确定集群类型:ToB 还是 ToC,是否允许有少量数据丢失?
  • 针对 ToB 等实时性不高的集群减少副本增加刷新时间
  • index buffer 优化 translog 优化,滚动重启集群

▼ Apache Flink 社区推荐 ▼

Apache Flink 及大数据领域顶级盛会 Flink Forward Asia 2019 大会议程重磅发布,参与问卷调研就有机会免费获取门票!

https://developer.aliyun.com/special/ffa2019

相关文章
|
3月前
|
SQL 人工智能 JSON
Flink 2.1 SQL:解锁实时数据与AI集成,实现可扩展流处理
简介:本文整理自阿里云高级技术专家李麟在Flink Forward Asia 2025新加坡站的分享,介绍了Flink 2.1 SQL在实时数据处理与AI融合方面的关键进展,包括AI函数集成、Join优化及未来发展方向,助力构建高效实时AI管道。
731 43
|
3月前
|
SQL 人工智能 JSON
Flink 2.1 SQL:解锁实时数据与AI集成,实现可扩展流处理
本文整理自阿里云的高级技术专家、Apache Flink PMC 成员李麟老师在 Flink Forward Asia 2025 新加坡[1]站 —— 实时 AI 专场中的分享。将带来关于 Flink 2.1 版本中 SQL 在实时数据处理和 AI 方面进展的话题。
271 0
Flink 2.1 SQL:解锁实时数据与AI集成,实现可扩展流处理
|
7月前
|
存储 消息中间件 Kafka
基于 Flink 的中国电信星海时空数据多引擎实时改造
本文整理自中国电信集团大数据架构师李新虎老师在Flink Forward Asia 2024的分享,围绕星海时空智能系统展开,涵盖四个核心部分:时空数据现状、实时场景多引擎化、典型应用及未来展望。系统日处理8000亿条数据,具备亚米级定位能力,通过Flink多引擎架构解决数据膨胀与响应时效等问题,优化资源利用并提升计算效率。应用场景包括运动状态识别、个体行为分析和群智感知,未来将推进湖仓一体改造与三维时空服务体系建设,助力数字化转型与智慧城市建设。
771 3
基于 Flink 的中国电信星海时空数据多引擎实时改造
|
3月前
|
SQL 关系型数据库 Apache
从 Flink 到 Doris 的实时数据写入实践 —— 基于 Flink CDC 构建更实时高效的数据集成链路
本文将深入解析 Flink-Doris-Connector 三大典型场景中的设计与实现,并结合 Flink CDC 详细介绍了整库同步的解决方案,助力构建更加高效、稳定的实时数据处理体系。
1599 0
从 Flink 到 Doris 的实时数据写入实践 —— 基于 Flink CDC 构建更实时高效的数据集成链路
|
4月前
|
存储 消息中间件 搜索推荐
京东零售基于Flink的推荐系统智能数据体系
摘要:本文整理自京东零售技术专家张颖老师,在 Flink Forward Asia 2024 生产实践(二)专场中的分享,介绍了基于Flink构建的推荐系统数据,以及Flink智能体系带来的智能服务功能。内容分为以下六个部分: 推荐系统架构 索引 样本 特征 可解释 指标 Tips:关注「公众号」回复 FFA 2024 查看会后资料~
318 1
京东零售基于Flink的推荐系统智能数据体系
|
8月前
|
Oracle 关系型数据库 Java
【YashanDB知识库】Flink CDC实时同步Oracle数据到崖山
本文介绍通过Flink CDC实现Oracle数据实时同步至崖山数据库(YashanDB)的方法,支持全量与增量同步,并涵盖新增、修改和删除的DML操作。内容包括环境准备(如JDK、Flink版本等)、Oracle日志归档启用、用户权限配置、增量日志记录设置、元数据迁移、Flink安装与配置、生成Flink SQL文件、Streampark部署,以及创建和启动实时同步任务的具体步骤。适合需要跨数据库实时同步方案的技术人员参考。
【YashanDB知识库】Flink CDC实时同步Oracle数据到崖山
|
9月前
|
Java 关系型数据库 MySQL
SpringBoot 通过集成 Flink CDC 来实时追踪 MySql 数据变动
通过详细的步骤和示例代码,您可以在 SpringBoot 项目中成功集成 Flink CDC,并实时追踪 MySQL 数据库的变动。
2246 45
|
8月前
|
消息中间件 关系型数据库 Kafka
阿里云基于 Flink CDC 的现代数据栈云上实践
阿里云基于 Flink CDC 的现代数据栈云上实践
139 1
|
12月前
|
存储 监控 数据处理
flink 向doris 数据库写入数据时出现背压如何排查?
本文介绍了如何确定和解决Flink任务向Doris数据库写入数据时遇到的背压问题。首先通过Flink Web UI和性能指标监控识别背压,然后从Doris数据库性能、网络连接稳定性、Flink任务数据处理逻辑及资源配置等方面排查原因,并通过分析相关日志进一步定位问题。
844 61
|
11月前
|
存储 缓存 监控
极致 ElasticSearch 调优,让你的ES 狂飙100倍!
尼恩分享了一篇关于提升Elasticsearch集群的整体性能和稳定性措施的文章。他从硬件、系统、JVM、集群、索引和查询等多个层面对ES的性能优化进行分析,帮助读者提升技术水平。

相关产品

  • 实时计算 Flink版