下单接口调优实战,性能提高10倍
概述
最近公司的下单接口有些慢,老板担心无法支撑双11,想让我优化一把,但是前提是不允许大改,因为下单接口太复杂了,如果改动太大,怕有风险。另外开发成本和测试成本也非常大。对于这种有挑战性的任务,我向来是非常喜欢的,因为在解决问题的过程中,可以学习到很多东西。
当时我只是知道下单接口慢,但是没人告诉我慢在哪里,也即是说,哪些瓶颈导致下单接口慢了。其实没人知道也没关系的,因为我们可以通过压测来找到具体的瓶颈。
下面会详细介绍一下,在本次压测中遇到的问题以及如何解决,期间用了什么工具。
用到的工具和环境
工具
- Jmeter
- JAVA自带的jvisualvm
- JMX
- nmon
环境
-
腾讯云Mysql
-
腾讯云2核4g的服务器1台
找瓶颈
下单属于写接口,大部分情况下,瓶颈都出在DB
里,程序可能都在等待DB
锁的释放。为了验证这个想法,我们可以使用Jmeter
和jvisualvm
来验证一下。
为了监控服务器和服务器中JAVA进程,我们需要开启JMX,可以在JAVA进程启动的时候,添加如下几个参数:
JMX_OPTS="-Dcom.sun.management.jmxremote.port=7969 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=xx.xx.xx.xx" nohup java ${JMX_OPTS} -jar xxxxx.jar
Djava.rmi.server.hostname
填写JAVA
进程所在服务器的IP
地址,-Dcom.sun.management.jmxremote.port=7969
是指定JMX
监控端口的,这里是7969。
重新启动进程后,打开本地的(我用的是Window10)jvisualvm
,添加JMX
配置。配置成功后,可以点击线程那个tab
,因为我们要做线程dump
,观察线程的执行情况。
好了,现在我们可以使用Jmeter
来对下单接口进行压测了。可以先用50线程并发压,执行时间是1分钟。
在压测的过程中,做一下线程dump
,同时利用nmon
观察应用服务器CPU
的负载情况。
负载很低,将线程并发调整到100后,CPU还是上不去,这样的话,初步可以判断,代码里有锁。 通过观察dump文件,发现如下信息:
- locked <22f6e7f3> (a com.mysql.cj.core.io.ReadAheadInputStream) - at com.sun.proxy.$Proxy231.reduceSkuStock(Unknown Source)
触发这个lock的业务代码是reduceSkuStock
方法。通过阅读代码,发现reduceSkuStock
被包在一个大事务里面。
@Transactional(rollbackFor = {Exception.class}) createOrder() { //1、扣减库存 reduceSkuStock(); //2、创建订单 insertOrder(); //3、其他写操作 。。。。 }
库存记录通常存在一张独立的库存表,由于创建订单的方法,是一个大事务,这样就会导致某条库存记录只有当整个createorder()
方法执行完后,数据库行锁才会被释放,在这个期间,其他线程是无法对这条库存记录进行写操作的。因此我们可以在reduceSkuStock()
中,再开一个事务,操作完这条库存记录后,立刻释放锁,这样应该可以提高一些性能。为了验证是否是因为事务的原因导致下单接口慢,我们可以直接将createOrder()
方法的事务去掉,再压测一下。
压测结果发现,下单接口的TPS
提高了一倍,CPU
也上去了不少,但是仍然不够理想,代码里,应该还有其他的锁。再次做线程dump
,又发现了一个锁。
- locked <438be230> (a org.apache.http.pool.AbstractConnPool$2) - at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
导致锁的代码是HttpClient
的execute
方法,该方法在执行的时候,一直在等待获取HTTP
连接,通过查看源代码,发现居然没有使用连接池,醉了。赶紧加上如下代码:
PoolingHttpClientConnectionManager pool = new PoolingHttpClientConnectionManager(); pool.setDefaultMaxPerRoute(400); httpClient = HttpClients.custom().setConnectionManager(pool).build();
再次压测后,发现代码里已经没有锁了。TPS
提升了5倍。但是接下来还得做几件事情:
1、打印下单接口的所有SQL
,然后逐一进行explain
操作,看看有没有全表扫描的语句或者没用到索引的SQL
语句;
2、观察下单接口执行的过程中,FULL GC
发生的次数;
3、增加应用的MYSQL
连接数;
好了,到了这地方,我们可以回到前面,来解决库存问题了。由于老板说,不能大改,因此我就在reduceSkuStock
方法上,再开一个事务。
@Transactional(propagation = Propagation.REQUIRES_NEW) reduceSkuStock(){}
让执行库存操作的线程执行完后,赶紧释放行锁。这样做也有个风险,就是库存扣减成功后,下单失败了。不过这种情况比较少,因为当时的下单接口中,大部分业务逻辑都在前面做好判断了,到达插入订单的代码时,就只是单独的insert了,除非数据库挂了,不然不会出现下单失败的情况。
在开发环境下,经过调优后,下单接口的TPS提升了3倍左右,当然由于开发环境的数据库和应用服务器都比较差,也会对TPS有影响的。当时优化完后,在生产上进行了压测,发现TPS提升了10倍。
总结
这个是下单接口的逻辑不能大改的情况下的优化方案,一般来说,库存操作应该是单独的服务,可以单独优化的。而单纯的下单逻辑也是可以优化的。
原文链接

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
使用JDK自带的VisualVM进行Java程序的性能分析
VisualVM是什么? VisualVM是JDK自带的一个用于Java程序性能分析的工具,JDK安装完毕后就有啦,在JDK安装目录的bin文件夹下能找到名称为jvisualvm.exe。 要使用VisualVM分析您的应用性能,首先得让VisualVM识别出您的应用。Eclipse有个插件名叫“VisualVM Launcher for Eclipse”,可以帮助我们做到这一点。 Eclipse VisualVM Launcher的安装和配置 1. 从下面的链接下载VisualVM Launcher插件。下载完毕后,放到您本地Eclipse文件夹的plugins文件夹下。 http://visualvm.java.net/eclipse-launcher.html 你可以参考下图我本地的Eclipse文件夹。注意这个插件解压之后,应该有一个名叫site.xml的文件。 2. 在Eclipse里,菜单 “Help->Install New Software”, 点 “Local”, 把第一步下载的插件文件加载进去。 Plugin文件已经被成功识别出来,可以安装了。 3. 安装完毕...
- 下一篇
绕过Cloudflare-JSfuck防护验证
近日在爬取某个站点的时候发现,默认必须通过首页跳转才可以访问其内容页,就像这样.. 经过使用Chrome调试工具审查Network过程后我们可以发现,在未设置cf_clearancecookie时,访问将无法进行。 我们可以红框内容看到首次访问返回503其后通过访问chk_jschi后触发302跳转至main并成功响应,并且在绿框中我们可以看到在第二个set-cookie取到后再次加载main界面成功 通过查看 chk_jschi 响应头我们可以看到其中的set-cookie内容正是我们所需要的 那么问题来了,这个是请求是怎么生成的呢?此时我们通过搜索蓝框内的键 我们来测试一下如果通过View-source会返回怎么样的结果,这里要注意要先将cookie清理干净 成功找到相关参数,看起来似乎是没啥问题了。不过有没有注意到jschl_answer并没有内容 并且存在一个id属性 这就让我立即想到会通过js将其赋值的可能。 于是根据ID查找,发现了惊喜 那么上面一堆乱七八糟的东西是什么呢。。 或许大部分人并不知道,这就是Jsfuck 也就是说,这些代码是可执行的 我们直接取出部分代码丢入c...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7,CentOS8安装Elasticsearch6.8.6
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- 2048小游戏-低调大师作品
- Mario游戏-低调大师作品
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS8编译安装MySQL8.0.19
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS8安装Docker,最新的服务器搭配容器使用
- CentOS7,8上快速安装Gitea,搭建Git服务器