背景
业务接口经常504,直接被拉群上压力,让排查排查怎么回事。
排查 and 优化
优化1
先上阿里云arms
看了下接口耗时情况,不看不知道,一看吓一跳,耗时尖刺多如牛毛。。。怪不得给我上压力 hhh
然后挑一条耗时比较高的Trace
查看,发现有条sql
执行的贼慢,还是count(*)
拿着这条sql
,代入一些参数,自己去生产环境跑了下,倒没有这么慢啊
因为用的是
pg
,可以直接用EXPLAIN ANALYZE
命令统计sql
真实的执行耗时
所以我觉得还是参数的问题,但是arms
是看不到参数的,所以用arthas
进入容器
利用watch
命令,在进行耗时过滤的同时,并打印出方法的入参出参
等了一段时间后,终于捉到了入参出参,然后代入到SQL
中再重新EXPLAIN ANALYZE
,确实慢的离谱
好叭,问题查到了,SQL
太慢了,该怎么优化呢?
一开始想着缓存替代,虽然有那么点数据不一致性,但是这个业务也能接受;
但后来分析了下这个参数,他没必要走这个查询,也就是说没必要去执行这个SQL
因为这个查询也是个配置化的东西,所以针对这个参数,可以直接去掉这个配置,这样就可以省略这段的SQL
耗时了
优化2
在优化1中,我们可以看到,因为参数的特殊性会导致接口的耗时突然形成大尖刺,但还有一些中等尖刺存在,很显然还有别的影响耗时的因素。
再找条中等尖刺Trace
看看
尼玛,又是条SQL
,尬住了
这个倒还好,结合代码看了下,是固定参数的查询,不用再自己watch
捉参数了
老规矩,代入参数EXPLAIN ANALYZE
分析下,还真是300多ms
那咋办嘛,又要优化sql
,hhh,真是跟sql
过不去了
结合代码看看啦
梳理下那块的业务逻辑,是需要查询用户有没有领取过这个券,所以很简单的办法,我们只需要count
一下就ok
而上面那个sql
不仅联表查询了,而且还把两个表的大部分参数都查出来了,并且传参也不合适,没有利用到联表查询字段的索引进行数据扫描过滤,一切的一切累加起来,导致这个sql
成为了一个慢SQL
所以优化后,处理很简单,单表查询 + count(*) + 走索引,快的离谱!
优化3
在排查上面优化2的时候,发现了一个问题
在优化2
的参数下,虽然会有300多ms
的SQL
耗时,但整体接口却可能还是存在1s+
的耗时情况,这个就比较离谱了,因为我以为只有优化1
的参数会导致这种情况,所以我用到了下面这个
最终发现下面这个耗时😒
尼玛,是有点离谱啊,等锁等了这么久,这是超大大耗时尖刺啊!!!
为什么呢?
这又得跟我很久之前做的一个优化相关了,很久之前做过一些逻辑收拢
怎么理解呢?
重复代码太多了,让各个逻辑上游调用同一个method
,同时还能利用JIT
热点代码缓存优化,这不是yyds
但是这个回旋镖终究还是打到了我自己
因为逻辑收拢后,是做了一个 uid
维度的分布式锁的,防止并发情况,giao!
但是随着业务的发展,这个并发冲突导致获取不到锁阻塞的场景出现频次会增高,所以就有了如上图所示的获取分布式锁,等了快四十秒,这不得枪毙我好几次 哈哈哈哈(开玩笑一下~
所以结合业务逻辑来看,我们是可以降低锁粒度的,uid
维度锁粒度还是太粗了
所以最后改成了,uid + 业务唯一属性值
做的分布式锁,这样冲突就是大大降低,耗时也能大大降低!
最终效果
最终以每天耗时来看,效果就如下啦,这线看着真舒服,😋,总算是把这份压力化解咯~
总结
这次接口耗时的排查相比于之前我做的一些耗时优化还是蛮有意思的
之前无非是一些同步改异步的优化,此次不仅是结合业务逻辑做了一些SQL
的优化,还认识到了锁粒度如果过粗,在高并发环境下的锁阻塞问题是十分严重的。
我是 Code皮皮虾 ,会在以后的日子里跟大家一起学习,一起进步! 觉得文章不错的话,可以在 掘金 关注我,这样就不会错过很多技术干货啦~