查询列表分页的接口慢怎么解决_java应用监控之利用cat接口性能优化,每一次都是血的教训...

ae7fbab0f09db676a6d65fd7db4cd95f.png

之前几篇文章对cat进行了简介、安装部署、代码埋点,今天分享一下如何利用cat帮助我们做接口优化。

为什么要接口性能优化?

1.用户体验差:接口访问速度慢、如果一个页面打开需要好几秒,用户可能在页面没有完全打开时,就关掉页面离开了,造成用户流失,通过性能优化,减少服务器响应时长,可提高用户体验,较少用户的流失。

2.雪崩效应:接口访问速度慢,会带来雪崩效应,在微服务时代,一个功能页面可能需要调用多个服务接口,如果某一个接口响应速度慢,会导致调用这个接口的服务也变得很慢,最后会导致所有的服务整体变慢。

什么样的接口值得优化?

1.调用频繁且调用时间长的接口,值得优化。接口a被调用10000次,平均调用时长500ms,接口b被调用10次,平均调用时长3秒。优化接口a,假设从500ms优化到300ms,每一次节省200ms,总体优化时长是200万毫秒。优化接口b,即使从3秒优化到100ms,总体优化时长也只有29000毫秒。碰到这种情况建议优化接口a,性价比更高,更值得优化。

2.调用次数少,但每次调用都异常(如超时无返回),这样的接口也必须优化。

如何使用cat定位需要优化的接口?

1.挑选性价比高的接口(Transaction)

37682724c1845a7f6d53f18ac7eae273.png

如上图选择的是cache-service应用,CacheService.mutliExecute调用最频繁,调用72万次,调用时长也比较多,可以作为被优化的接口。

2.通过条件筛选,提供Long-url、Long sql、Long sevice、Long call筛选条件,可以自行组合,调整时间长度。(Promblem)

8fb8e8b4b77c018a11b8b6e3222e723c.png

3.调用出错,必须要修改处理(promblem)

fe4378dfeb1975e7371bb55494977c1a.png

接口如何优化?

1.查看调用链,定位哪个方法调用时间长

7d10dc85d36b4bd14e79697a34ca79aa.png

通过上图,发现接口存在循环调用,优化方案:调用批量操作接口,减少接口调用次数。

2.慢sql优化方法

第一步:explain查看sql执行计划,确认sql是否走索引。

第二步:确认数据库表是否建立索引,如果没有索引,创建合适的索引,保持最左原则。

第三步:如果存在索引,没有索引,分析其中原因

第四步:如果sql走了索引,依然很慢,缓存中间结果(异构一张中间表或者将结果缓存到redis中)

具体优化例子:

1.查询库存接口,数据库表存在索引,而没有使用到索引,是因为数据库表属性类型是varchar,sql中使用了in,然而传参的时候使用的是数值类型,导致发生了数据类型转换,导致没有走索引。优化方案,修改传参类型,使用字符串进行传参,优化之后从300ms降低到60ms。(如果数据库中是数值类型,参数使用字符串类型,即便发生了类型转换,依然可以走索引,很奇怪)。sql中使用in,作为多条件查询,有时候能走索引,有时候不能走索引,当in中只有1个值的时候,一定会走索引,当in中查询的结果,达到所有记录的一定比例的时候,不会走索引。

2.大表分页优化,定时任务,需要对大表分页查询,可以使用子查询的方式进行优化。举例:商品表100万条记录,需要每天定时更新商品的销量。一般做法使用多线程,每个线程处理200条数据

select * from item limit 900000,200

越往后执行,时间会越长,因为mysql需要定位前90万条记录,之后再取出后面的200条数据,因为没有走索引,所以会比较慢。

优化方案一:利用子查询

select * from item i,(select id from item limit 900000,200) as g where g.id = i.id

因为可以走索引,而且子查询使用到了覆盖索引,不需要进行第二次查询,可以提高查询速度。

优化方案二:主键Id区间法

前提条件表结构中存在自增长主键。取出表的最小值和最大值,将这两个值进行分段,每个线程处理一个区间。这样查询可以利用主键索引。

select * from item where id in (1,2,3,4,5,..200)

3.Jvm优化

查询库存优化之后,走了索引之后,的确快了很多,通过cat发现,库存服务有两个应用实例,有一个实例接口非常快,一个很慢,通过cat的Heartbeat发现慢的那台机器存在full gc,每隔一段时间就发生一次fullgc。

16ea95b1597c5459dbbba83bca546aab.png

查看jvm的Gc命令

jstat -gcutil pid 2000
bfd8a216801f3e17d9e95a5163f7fec5.png

如果存在大量的YGC可以通过jmap命令定位哪些对象创建的多,然后进行代码优化,尽量减少对象的创建。或者调整jvm参数,增加Eden区的大小。如果存在大量的fullGC这种情况要引起注意,因为一次fullGC会消耗时间比较长,严重影响性能,需要调整jvm参数。

jmap -histo pid | grep com.galaxy(包路径)
e82bbdd8de1afa501fab5408b06b8667.png

top命令查看cpu,内存等使用情况

top
0ae930dd982a8de6b376024e1a4d3d71.png

cpu使用过高优化方案

首先显示线程列表:

ps -mp pid -o THREAD,tid,time
209bfbc2bacbb97cb72b9191c9f7918d.png

找到了耗时最高的线程28802,占用CPU时间快两个小时了!

其次将需要的线程ID转换为16进制格式:

printf "%x" tid
904742c326549256deb06f3035309c90.png

最后打印线程的堆栈信息:

jstack pid |grep tid -A 30
d99fececef744f6b88d60306480a25dc.png

无法获取数据库连接

可能是因为数据库在执行修改表结构造成了锁表

select * from information_schema.processlist where db = 'item' and state like '%lock%'

需要对查出来的进程进行kill掉。可以通过命令

kill 进程Id

获取redis连接失败,可能存在某些地方没有释放连接,可通过jstack命令进行定位

jstack –l pid > jstack.txt

下载jstack.txt进行分析,搜索Lock关键词,可以方便定位问题。最好的方法,对连接的操作,进行统一的封装,不留给开发人员犯错的机会。

遇到问题不可怕,可怕的是同样的问题重复犯。将开发过程中遇到的问题,记录下来,总结定期复盘,可避免重犯同样的错误。吃一堑,长一智,特此记录下来和大家分享,希望对你有所帮助。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值