最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JAVA下單接口優(yōu)化實(shí)戰(zhàn)TPS性能提高10倍

 更新時(shí)間:2018年12月06日 15:10:07   作者:Sam哥哥  
今天小編就為大家分享一篇關(guān)于JAVA下單接口優(yōu)化實(shí)戰(zhàn)TPS性能提高10倍,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧

概述

最近公司的下單接口有些慢,老板擔(dān)心無(wú)法支撐雙11,想讓我優(yōu)化一把,但是前提是不允許大改,因?yàn)橄聠谓涌谔珡?fù)雜了,如果改動(dòng)太大,怕有風(fēng)險(xiǎn)。另外開(kāi)發(fā)成本和測(cè)試成本也非常大。對(duì)于這種有挑戰(zhàn)性的任務(wù),我向來(lái)是非常喜歡的,因?yàn)樵诮鉀Q問(wèn)題的過(guò)程中,可以學(xué)習(xí)到很多東西。

當(dāng)時(shí)我只是知道下單接口慢,但是沒(méi)人告訴我慢在哪里,也即是說(shuō),哪些瓶頸導(dǎo)致下單接口慢了。其實(shí)沒(méi)人知道也沒(méi)關(guān)系的,因?yàn)槲覀兛梢酝ㄟ^(guò)壓測(cè)來(lái)找到具體的瓶頸。

下面會(huì)詳細(xì)介紹一下,在本次壓測(cè)中遇到的問(wèn)題以及如何解決,期間用了什么工具。

用到的工具和環(huán)境

工具

  • Jmeter
  • JAVA自帶的jvisualvm
  • JMX
  • nmon

環(huán)境

  • 騰訊云Mysql
  • 騰訊云2核4g的服務(wù)器1臺(tái)

找瓶頸

下單屬于寫(xiě)接口,大部分情況下,瓶頸都出在DB里,程序可能都在等待DB鎖的釋放。為了驗(yàn)證這個(gè)想法,我們可以使用Jmeterjvisualvm來(lái)驗(yàn)證一下。

為了監(jiān)控服務(wù)器和服務(wù)器中JAVA進(jìn)程,我們需要開(kāi)啟JMX,可以在JAVA進(jìn)程啟動(dòng)的時(shí)候,添加如下幾個(gè)參數(shù):

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填寫(xiě)JAVA進(jìn)程所在服務(wù)器的IP地址,-Dcom.sun.management.jmxremote.port=7969是指定JMX監(jiān)控端口的,這里是7969。

重新啟動(dòng)進(jìn)程后,打開(kāi)本地的(我用的是Window10)jvisualvm,添加JMX配置。配置成功后,可以點(diǎn)擊線(xiàn)程那個(gè)tab,因?yàn)槲覀円鼍€(xiàn)程dump,觀(guān)察線(xiàn)程的執(zhí)行情況。

好了,現(xiàn)在我們可以使用Jmeter來(lái)對(duì)下單接口進(jìn)行壓測(cè)了??梢韵扔?0線(xiàn)程并發(fā)壓,執(zhí)行時(shí)間是1分鐘。

在壓測(cè)的過(guò)程中,做一下線(xiàn)程dump,同時(shí)利用nmon觀(guān)察應(yīng)用服務(wù)器CPU的負(fù)載情況。

負(fù)載很低,將線(xiàn)程并發(fā)調(diào)整到100后,CPU還是上不去,這樣的話(huà),初步可以判斷,代碼里有鎖。
通過(guò)觀(guān)察dump文件,發(fā)現(xiàn)如下信息:

- locked <22f6e7f3> (a com.mysql.cj.core.io.ReadAheadInputStream)
- at com.sun.proxy.$Proxy231.reduceSkuStock(Unknown Source)

觸發(fā)這個(gè)lock的業(yè)務(wù)代碼是reduceSkuStock方法。通過(guò)閱讀代碼,發(fā)現(xiàn)reduceSkuStock被包在一個(gè)大事務(wù)里面。

@Transactional(rollbackFor = {Exception.class})
 createOrder() {
 //1、扣減庫(kù)存
 reduceSkuStock();
 //2、創(chuàng)建訂單
 insertOrder();
 //3、其他寫(xiě)操作
 。。。。
}

庫(kù)存記錄通常存在一張獨(dú)立的庫(kù)存表,由于創(chuàng)建訂單的方法,是一個(gè)大事務(wù),這樣就會(huì)導(dǎo)致某條庫(kù)存記錄只有當(dāng)整個(gè)createorder()方法執(zhí)行完后,數(shù)據(jù)庫(kù)行鎖才會(huì)被釋放,在這個(gè)期間,其他線(xiàn)程是無(wú)法對(duì)這條庫(kù)存記錄進(jìn)行寫(xiě)操作的。因此我們可以在reduceSkuStock()中,再開(kāi)一個(gè)事務(wù),操作完這條庫(kù)存記錄后,趕緊釋放鎖,這樣應(yīng)該可以提高一些性能。為了驗(yàn)證是否是因?yàn)槭聞?wù)的原因?qū)е孪聠谓涌诼覀兛梢灾苯訉?code>createOrder()方法的事務(wù)去掉,再壓測(cè)一下。

壓測(cè)結(jié)果發(fā)現(xiàn),下單接口的TPS提高了一倍,CPU也上去了不少,但是仍然不夠理想,代碼里,應(yīng)該還有其他的鎖。再次做線(xiàn)程dump,又發(fā)現(xiàn)了一個(gè)鎖。

- locked <438be230> (a org.apache.http.pool.AbstractConnPool$2)
- at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)

導(dǎo)致鎖的代碼是HttpClientexecute方法,該方法在執(zhí)行的時(shí)候,一直在等待獲取HTTP連接,通過(guò)查看源代碼,發(fā)現(xiàn)居然沒(méi)有使用連接池,醉了。趕緊加上如下代碼:

 PoolingHttpClientConnectionManager pool = new PoolingHttpClientConnectionManager();
 pool.setDefaultMaxPerRoute(400);
 httpClient = HttpClients.custom().setConnectionManager(pool).build();

再次壓測(cè)后,發(fā)現(xiàn)代碼里已經(jīng)沒(méi)有鎖了。TPS提升了5倍。但是接下來(lái)還得做幾件事情:

1、打印下單接口的所有SQL,然后逐一進(jìn)行explain操作,看看有沒(méi)有全表掃描的語(yǔ)句或者沒(méi)用到索引的SQL語(yǔ)句;
2、觀(guān)察下單接口執(zhí)行的過(guò)程中,FULL GC發(fā)生的次數(shù);
3、增加應(yīng)用的MYSQL連接數(shù);

好了,到了這地方,我們可以回到前面,來(lái)解決庫(kù)存問(wèn)題了。由于老板說(shuō),不能大改,因此我就在reduceSkuStock方法上,再開(kāi)一個(gè)事務(wù)。

@Transactional(propagation = Propagation.REQUIRES_NEW)
reduceSkuStock(){}

讓執(zhí)行庫(kù)存操作的線(xiàn)程執(zhí)行完后,趕緊釋放行鎖。這樣做也有個(gè)風(fēng)險(xiǎn),就是庫(kù)存扣減成功后,下單失敗了。不過(guò)這種情況比較少,因?yàn)楫?dāng)時(shí)的下單接口中,大部分業(yè)務(wù)邏輯都在前面做好判斷了,到達(dá)插入訂單的代碼時(shí),就只是單獨(dú)的insert了,除非數(shù)據(jù)庫(kù)掛了,不然不會(huì)出現(xiàn)下單失敗的情況。

在開(kāi)發(fā)環(huán)境下,經(jīng)過(guò)調(diào)優(yōu)后,下單接口的TPS提升了3倍左右,當(dāng)然由于開(kāi)發(fā)環(huán)境的數(shù)據(jù)庫(kù)和應(yīng)用服務(wù)器都比較差,也會(huì)對(duì)TPS有影響的。當(dāng)時(shí)優(yōu)化完后,在生產(chǎn)上進(jìn)行了壓測(cè),發(fā)現(xiàn)TPS提升了10倍。

這個(gè)是下單接口的邏輯不能大改的情況下的優(yōu)化方案,一般來(lái)說(shuō),庫(kù)存操作應(yīng)該是單獨(dú)的服務(wù),可以單獨(dú)優(yōu)化的。而單純的下單邏輯也是可以?xún)?yōu)化的。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接

相關(guān)文章

  • mybatis-plus動(dòng)態(tài)數(shù)據(jù)源讀寫(xiě)分離方式

    mybatis-plus動(dòng)態(tài)數(shù)據(jù)源讀寫(xiě)分離方式

    在分布式項(xiàng)目開(kāi)發(fā)中,動(dòng)態(tài)數(shù)據(jù)源的配置與使用至關(guān)重要,通過(guò)創(chuàng)建DynamicDatasourceService,實(shí)現(xiàn)數(shù)據(jù)源的動(dòng)態(tài)添加與調(diào)用,有效管理主從庫(kù)操作,減輕數(shù)據(jù)庫(kù)壓力,此外,通過(guò)配置類(lèi)與@DS注解,實(shí)現(xiàn)了靈活的分庫(kù)查詢(xún)功能,為高效處理數(shù)據(jù)提供了強(qiáng)有力的支持
    2024-10-10
  • springboot實(shí)現(xiàn)簡(jiǎn)單的消息對(duì)話(huà)的示例代碼

    springboot實(shí)現(xiàn)簡(jiǎn)單的消息對(duì)話(huà)的示例代碼

    本文主要介紹了springboot實(shí)現(xiàn)簡(jiǎn)單的消息對(duì)話(huà)的示例代碼,可以使用WebSocket技術(shù),WebSocket是一種在客戶(hù)端和服務(wù)器之間提供實(shí)時(shí)雙向通信的協(xié)議,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-09-09
  • Spring?Bean獲取方式的實(shí)例化方式詳解

    Spring?Bean獲取方式的實(shí)例化方式詳解

    工作中需要對(duì)一個(gè)原本加載屬性文件的工具類(lèi)修改成對(duì)數(shù)據(jù)庫(kù)的操作當(dāng)然,ado層已經(jīng)寫(xiě)好,但是需要從Spring中獲取bean,然而,工具類(lèi)并沒(méi)有交給Spring來(lái)管理,所以需要通過(guò)方法獲取所需要的bean。于是整理了Spring獲取bean的幾種方法
    2023-03-03
  • SpringBoot自定義Starter與自動(dòng)配置實(shí)現(xiàn)方法詳解

    SpringBoot自定義Starter與自動(dòng)配置實(shí)現(xiàn)方法詳解

    在Spring Boot官網(wǎng)為了簡(jiǎn)化我們的開(kāi)發(fā),已經(jīng)提供了非常多場(chǎng)景的Starter來(lái)為我們使用,即便如此,也無(wú)法全面的滿(mǎn)足我們實(shí)際工作中的開(kāi)發(fā)場(chǎng)景,這時(shí)我們就需要自定義實(shí)現(xiàn)定制化的Starter
    2023-02-02
  • 如何搭建一個(gè)完整的Java開(kāi)發(fā)環(huán)境

    如何搭建一個(gè)完整的Java開(kāi)發(fā)環(huán)境

    這篇文章主要教大家如何搭建一個(gè)完整的Java開(kāi)發(fā)環(huán)境,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • Java并發(fā)編程之線(xiàn)程中斷

    Java并發(fā)編程之線(xiàn)程中斷

    這篇文章主要介紹了Java并發(fā)編程線(xiàn)程中斷,java線(xiàn)程中斷是一種線(xiàn)程間的協(xié)作模式,通過(guò)設(shè)置線(xiàn)程的中斷標(biāo)志并不能直接終止該線(xiàn)程的運(yùn)行,而是被中斷的線(xiàn)程根據(jù)中斷狀態(tài)自行處理,需要的朋友可以參考一下
    2021-09-09
  • SpringBoot事務(wù)不回滾的解決方案

    SpringBoot事務(wù)不回滾的解決方案

    這篇文章主要介紹了SpringBoot事務(wù)不回滾的解決方案的相關(guān)資料,需要的朋友可以參考下
    2022-09-09
  • 詳解MyBatis開(kāi)發(fā)Dao層的兩種方式(Mapper動(dòng)態(tài)代理方式)

    詳解MyBatis開(kāi)發(fā)Dao層的兩種方式(Mapper動(dòng)態(tài)代理方式)

    這篇文章主要介紹了詳解MyBatis開(kāi)發(fā)Dao層的兩種方式(Mapper動(dòng)態(tài)代理方式),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • Java自定義線(xiàn)程池的實(shí)現(xiàn)示例

    Java自定義線(xiàn)程池的實(shí)現(xiàn)示例

    本文主要介紹了Java自定義線(xiàn)程池的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 如何在Spring data中使用r2dbc詳解

    如何在Spring data中使用r2dbc詳解

    這篇文章主要給大家介紹了關(guān)于如何在Spring data中使用r2dbc的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11

最新評(píng)論

江阴市| 景泰县| 娱乐| 宝坻区| 科技| 吴川市| 九龙城区| 安义县| 元朗区| 张家口市| 泰州市| 黑河市| 凤山市| 靖边县| 葵青区| 库尔勒市| 大英县| 元氏县| 大名县| 海城市| 剑阁县| 都兰县| 连州市| 罗平县| 报价| 普兰县| 汉中市| 内丘县| 垦利县| 武义县| 金湖县| 特克斯县| 蒲江县| 穆棱市| 开平市| 弥渡县| 凤庆县| 古交市| 台南市| 来凤县| 德保县|