Redisson分布式锁释放超时导致MQ消费过慢

一、问题现象

一个需要通过消费MQ导入200w数据量的项目。在项目上线前一天,在QA环境对MQ消费进行压测,发现消费链路异常的长,导致整体消费速率过慢。
Redisson分布式锁释放超时导致MQ消费过慢_第1张图片
因为本身已经用sentinel对MQ消费做了限流,限流速率又正好和这个缓慢的速度差不多,所以一直没发现MQ消费本身就过慢:tw-1f605:。

二、排查过程

1.在解除sentinel限流之后发现MQ依然龟速消费,一开始怀疑是不是sentinel限流控制有延迟,又或者我们公司中间件有其他对mq消费的默认限速。在重启服务和询问中间件相关同事后确认应该不是限流导致的问题。

2.怀疑自己代码拉垮了(常有的事~),于是去查具体的消费链路,一看还真是。
Redisson分布式锁释放超时导致MQ消费过慢_第2张图片
但是公司的监控系统只会在rpc调用、数据源访问上打点,可是看链路,这些都没啥异常,那这个将近4000ms的时间到底耗费在哪里了呢?

3.搬出神器,鼎鼎大名的Arthas,用来诊断java程序各种问题。在容器里安装启动Arthas后,复现了MQ消费的场景,然后trace咱们的消费方法发现:

竟然是释放锁超时了。我这里使用的是Redission的Rlock进行加锁,这个RedisUtils里除了对线程是否持有锁进行了简单的判断,其他就是Rlock.unlock()。

4.点开unlock()的源码,发现这是一个本质使用异步提交lua脚本任务,阻塞等待future结果来实现同步解锁效果的方法。再往下看就是使用netty的promise实现异步通信了,不是我们需要关注的。
Redisson分布式锁释放超时导致MQ消费过慢_第3张图片

Redisson分布式锁释放超时导致MQ消费过慢_第4张图片

Redisson分布式锁释放超时导致MQ消费过慢_第5张图片

于是又trace这个unlock()方法:

发现果真是阻塞等待太久了。到这里我基本初步断定是Redission本身的性能问题或是QA环境redis通信的速度问题。之后我又尝试将解锁改为异步,发现解锁异步的话,加锁就会超时。
Redisson分布式锁释放超时导致MQ消费过慢_第6张图片
在网上查阅相关资料和相关性能测试报告,确认了Redission确实存在比较大的性能损耗,于是改用lua脚本的setNx()方法来加锁,问题完美解决。

三、总结与收获

其实这个问题倒没多高深,但是排查的过程学到了很多。Arthas的使用,Redission的源码我都是第一次主动去了解。最后这个项目也不负我所望,顺利抗下1600的tps,一个小时完成了200w数据的计算和导入。
分布式锁是个值得深入研究的东西,如何权衡性能和安全性,是之后技术选型需要重点考虑的问题。

你可能感兴趣的:(踩坑总结,中间件,java,高并发,分布式锁,RocketMQ)