flink实时任务因jedis连接池导致的任务阻塞问题

本文记录了一个Flink实时任务在运行一段时间后出现阻塞的问题,详细描述了从kafka消费异常到定位到Redis写操作的问题过程。任务看似正常,但实际上不再消费kafka并导致checkpoint失败。经过排查,发现是自定义的Redis setex方法未正确释放资源,导致连接池耗尽。进一步分析jedis连接池配置,发现默认设置在资源不足时不抛出异常,建议修改为在获取连接超时时抛出异常。最后,提出了问题的解决方案和预防措施。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题现象

有个flink实时任务,读kafka和redis,中间有复杂的逻辑处理过程,最终结果写redis。flink实时任务运行一段时间后阻塞了,有时是几个小时后,有时是一两天后。

任务看起来正常是正常的,但kafka消费已经停止,checkpoint也失败。看日志,当问题出现后,kafka一直WARN,提示如下

Marking the coordinator xxxxxx dead.
Marking the coordinator xxxxxx dead.
Marking the coordinator xxxxxx dead.

……

任务看起来正常运行,但不再消费kafka,checkpoint失败,除此之外,cpu、mem、io、日志,均看不出异常;集群节点登陆需要申请权限,比较麻烦。

原因分析

步骤1

刚开始以为是kafka消费的问题,导致了任务阻塞。于是寻找解决办法,发现也有部分人遇到类似的问题,但办法不管用。

后面了解到kafka集群版本之前是0.9,最近升级到了2.2.0,建议更新了kafka客户端版本。升级到2.2.0客户端版本后,没有"Marking the coordinator xxx dead."的日志了,但任务还是在运行一段时间后回挂起,问题还没有解决。

步骤2

由于没有权限登陆集群节点,只能通过flink ui,观察cpu、mem、io正常,查看job manager和task manager日志,也没有发现异常。

每次任务阻塞后查看checkpoint,都是失败。刚开始以为checkpoint间隔5秒太短,于是一直往上调整到10分钟,还是照样挂。

有次checkpoint刚挂不久,发现checkpoint挂在sink redis了,其他操作都是几到几十毫秒。那大概原因找到了,写redis有问题。

同时通过最近几次任务挂起后的观察,sink redis数量好像都是在1608,资源申请的是8核cpu、单核内存4G,配置文件prod.sink.redis.maxPools=200,(200+1)*8=1608,看起来有联系?

将prod.sink.redis.maxPools设置为1或者10,问题很快就复现了,可以基本确定,问题发生在sink redis操作了。

步骤3

分析代码,因为写redis需要设置key有效时间,所以没有用原生的flink-redis-connector,而是用了flink-redis-connector+jedis,基于二者做了稍显复杂的封装,用于读写redis三种集群模式:主从复制、哨兵模式、集群模式。

最终发现,setex实现方法有问题,使用完连接后,并没有释放资源。

基本代码逻辑如下:

    @Override
    public String setex(String key, int seconds, String value) {
        String res = null;
        Jedis jedis = null;
        try {
            jedis = getInstance();
            res = jedis.setex(key, seconds, value);
        } catch (Exception e) {
            logger.error("Cannot get Redis message with command GET to key {} error message {}", key, e.getMessage());
   

<think> 我们参考了用户提供的引用内容,结合Flink实时任务中使用group by的常见问题,总结如下: 1. **数据倾斜问题**:当group by的键分布不均匀时,可能导致某些子任务处理的数据量远大于其他子任务,造成数据倾斜。这会使得整个任务的处理速度受限于最慢的子任务,严重时可能导致任务失败。例如,引用[3]中提到,如果按商品ID进行keyBy,某些热门商品的数据量过大,就会导致处理该商品的分区负载过高。 2. **资源分配不均**:数据倾斜会导致部分TaskManager的CPU、内存和网络资源消耗过高,而其他TaskManager的资源利用率却很低。引用[1]中提到的环境是3个并发度(3个TaskManager),如果其中一个TaskManager负载过高,可能会成为瓶颈。 3. **死锁问题**:在写入外部存储(如PostgreSQL)时,如果group by的字段不等于目标表的主键字段,可能导致写入死锁。引用[1]中描述了这种场景:多个并发任务尝试以不同的顺序更新或插入同一组数据,导致数据库表级锁冲突。例如,节点A、B、C同时写入同一张表,且操作涉及非主键字段的分组,可能触发死锁。 4. **状态管理问题**:使用group by后,Flink需要维护每个键的状态(如窗口状态、累加器等)。如果分组键过多或状态数据过大,可能导致: - 状态后端压力增大(如RocksDB I/O瓶颈) - Checkpoint超时或失败(引用[2]提到需要关注checkpoint设置) - 状态过期时间设置不合理(引用[2]提到数据状态保存时间) 5. **消费组异常问题**:引用[4]提到,Flink消费Kafka时可能出现消费组"假死"现象(Marking the coordinator dead for group),导致数据重复消费。虽然该问题与group by无直接关联,但在实时任务中,如果group by操作导致处理延迟,可能间接引发Kafka消费组心跳超时,从而触发此类问题。 6. **并行度调整困难**:引用[2]指出并行度需要调整。如果group by后的操作链(如窗口聚合)并行度设置不合理,可能加剧数据倾斜或资源浪费。 ### 解决方案建议 1. **应对数据倾斜**: - 添加随机前缀打散热点键(如`CONCAT(key, '_', RAND() % 10)`),聚合后再合并结果。 - 使用局部聚合+全局聚合两层处理。 2. **避免死锁**: - 确保group by字段与目标表主键一致(引用[1]的核心启示)。 - 降低写入并发度或使用`ON CONFLICT`更新策略(针对PostgreSQL)。 3. **状态优化**: - 设置合理的状态TTL(Time-To-Live)。 - 使用增量Checkpoint(如RocksDB状态后端)。 4. **并行度调整**:根据group by键的基数调整并行度,避免单个子任务负载过重。 §§相关问题§§ 1. Flink实时任务中如何诊断数据倾斜问题? 2. 如何优化Flink状态后端以减少group by操作带来的压力? 3. 在Flink SQL中,group by与非主键字段关联写入数据库时,如何避免死锁? </think> ### Flink实时任务中使用Group By可能导致问题 根据引用内容并结合Flink特性,使用Group By时需注意以下问题: 1. **数据倾斜问题** Group By操作本质上是按Key分区处理,当Key分布不均匀时会导致数据倾斜(引用[3])。例如电商场景中按热门商品ID分组,少数TaskManager可能处理90%数据,造成: - 个别节点资源(CPU/内存)耗尽 - 反压传导至上游数据源 - 窗口计算延迟增加 $$P(\text{负载不均衡}) \propto \frac{\max(\text{Key分布熵})}{\text{并行度}}$$ 2. **状态管理风险** - **状态爆炸**:高基数Key(如用户ID)导致状态体积指数级增长(引用[2]) - **Checkpoint失败**:大状态会使Checkpoint超时(默认10分钟),可能触发任务重启 - **TTL失效**:未合理设置状态存活时间(`table.exec.state.ttl`)导致内存泄漏 3. **死锁风险(写入场景)** 当Group By字段≠目标表主键时,并发写入可能引发死锁(引用[1]): ```mermaid graph LR A[TaskManager A] -->|更新记录X| PG[(PostgreSQL)] B[TaskManager B] -->|更新记录Y| PG C[TaskManager C] -->|更新记录X| PG # 与A竞争锁 ``` 尤其在3节点部署时(引用[1]),多个并行度同时更新相同主键行会导致数据库行锁冲突。 4. **资源分配问题** - 并行度设置不当(引用[2])时,Group By可能造成: - 低并行度:无法利用集群资源 - 高并行度:Shuffle网络开销剧增 - 需要根据`hash(key) mod parallelism`动态调整负载 5. **消费组异常(Kafka源场景)** Group By处理延迟可能导致Kafka消费组心跳超时(引用[4]),引发: - `Marking the coordinator dead` 错误 - 消费组被误判死亡导致重复消费 - 偏移量提交失败 ### 最佳实践建议 1. **防倾斜**:对热点Key添加随机后缀(如`key || '_' + rand(10)`)分散负载 2. **状态优化**: - 设置合理TTL:`table.exec.state.ttl = 3600s` - 开启增量Checkpoint 3. **写入安全**:确保Group By字段包含目标表所有主键字段(引用[1]) 4. **资源调优**: ```sql SET table.exec.resource.default-parallelism = 4; -- 根据集群规模调整 SET execution.checkpointing.timeout = 5min; -- 大状态场景延长超时 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值