线上KAFKA消息堆积及数据库连接打满,CPU飙高问题解决

事件背景:

前段时间我们收到用户反馈app上的车的位置和电量不是最新的数据,这个车位置和电量数据是通过车端上传到云端解析服务,然后云端解析服务发送到Kafka,然后下游服务消费Kafka去更新到库里的。

问题分析:

 数据没有事实更新一种原因是源头出现问题,那就是车端没有上传相关数据,于是我们查看云端解析服务日志,发现车端是在正常上传数据的,这种情况排除。还有一种情况就是下游服务出现问题导致消息没有消费,接着我们又查看消费服务日志,也没有发现异常和相关报错,服务也在正常运行。这个时候我陷入了沉思,生产者和消费者都是正常,但是数据却不是最新的,那很有可能是消费积压了,导致消费者没有消费到最新的数据。我上Kafka的控制台查看这个topic的对应的消费者,果然是积压了几百万的数据。但是这个项目上线有一段时间了运行都是正常也没有出现积压过,是什么原因导致积压的呢?问了IT,才知道前天晚上机房断电了,导致下游消费服务宕机,因而出现消息积压了。问题找出来了接下来就是去解决了,消息积压,常见的方式是增加消费者,扩大分区,我们也是这么做了。但是好景不长,没过多久就收到告警,发现数据库连接被打满,cpu也飙高。于是我登上监控进一步查看发现CPU飙高的同时有大量sql的锁耗时比较长,平均1.5s,高峰期有4-5s。于是进一步查看sql详情。发现是一个update语句,这个语句的作用主要是根据车架号字段去更新经纬度和电量等相关字段。mysql InnoDB 默认的是行级别的锁,当执行update语会给这行数据加上行锁。并发情况下,多个线程同时请求同一个数据资源时,如果某一个线程占用了资源没有释放,那么其他的线程就无法获取资源,就会一直等待,从而导致CPU占用率升高。这个车架号字段没有设置索引,这样导致在更新的时候会去表扫描,效率低。并发情况下就会出现锁等待,而且排队的事物是没有释放数据库连接的,最终也导致了数据库连接被耗尽。

解决方案:

问题找出来了接下来就是具体解决方案了。

1.Kafka消息积压了,没有及时主动发现是缺少了对消息积压的监控,于是让devops加上消息积压的监控。

2.消息积压了,扩大分区,增加消费者,多线程处理应用程序程序增加消费速度。

3.并发更新同一行记录情况下,数据库锁导致的数据库CPU升高和连接耗尽。可以考虑给车架号字段添加索引,但是加了索引其实也还是会有锁,只是避免全表扫描,执行效率高了,并发情况下还是可能会导致锁等待。结合业务,有些情况是可以在应用程序层面去将多个记录批量合并汇总成一条记录去更新数据库,这样可以减少与数据的连接和交互。针对我们的业务场景,只是实时显示车的位置和电量,完全没有必要放在数据库,我们改成存在redis里,去更新和查询redis,这样效率就高了很多。

注意事项:

在 Kafka 中,扩大分区可能会带来分区的重平衡(Partition Rebalance)可能会导致消息乱序的问题。这是因为当消费者组成员发生变化时(例如添加或移除消费者),Kafka 会重新分配分区给消费者,这可能导致之前有序的消息在分配给新的消费者后变得乱序。

解决此问题的一种常见方法是使用 Kafka 提供的分区键(Partition Key)功能。分区键是与每条消息相关的一个标识符,如果多个消息具有相同的分区键,它们将被分配到同一个分区。通过在生产者端设置合适的分区键,可以确保具有相同键的消息会被分配到同一个分区,从而保持消息的顺序性。下游服务可以针对每个分区独立消费消息,并通过控制消费者实例数和分区数的关系,尽可能保持消息的有序性。

以下是一些实践建议来解决消息乱序的问题:

  1. 合理设置分区数量: 根据业务需求和数据量,合理设置主题的分区数量。较少的分区数量可以减少分区重平衡带来的乱序问题。

  2. 使用数据的特定字段作为分区键: 如果数据中存在某个字段表示有序性,可以将其作为分区键。确保相关的有序消息具有相同的分区键,以确保它们在同一分区中。

  3. 使用精确的分区器: 可以自定义一个精确的分区器,以保持有序性。使用自定义分区器可以根据业务规则将消息分配到特定的分区。

  4. 控制消费者的数量和分区的关系: 避免过度的消费者数量,以至于每个消费者被分配到多个分区。确保消费者实例数不大于分区数,以保持有序性。

  5. 使用消息的时间戳: 如果消息的时间戳对于有序性很重要,可以在消费端使用时间戳来重新排序消息。

需要注意的是,虽然上述方法可以减少消息乱序的可能性,但无法完全消除分区重平衡带来的潜在乱序问题。在设计系统时,应该根据业务需求和数据的有序性等因素进行权衡和选择。

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值