在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

聊聊接口優化的幾個方法

馬哥Linux運維 ? 來源:稀土掘金技術社區 ? 2023-01-30 09:37 ? 次閱讀

哪些問題會引起接口性能問題?

這個問題的答案非常多,需要根據自己的業務場景具體分析。這里做一個不完全的總結:

數據庫慢查詢

深度分頁問題

未加索引

索引失效

join過多

子查詢過多

in中的值太多

單純的數據量過大

業務邏輯復雜

循環調用

順序調用

線程池設計不合理

鎖設計不合理

機器問題(fullGC,機器重啟,線程打滿)

問題解決

1、慢查詢(基于mysql)

1.1 深度分頁

所謂的深度分頁問題,涉及到mysql分頁的原理。通常情況下,mysql的分頁是這樣寫的:

selectname,codefromstudentlimit100,20

含義當然就是從student表里查100到120這20條數據,mysql會把前120條數據都查出來,拋棄前100條,返回20條。當分頁所以深度不大的時候當然沒問題,隨著分頁的深入,sql可能會變成這樣:

selectname,codefromstudentlimit1000000,20

這個時候,mysql會查出來1000020條數據,拋棄1000000條,如此大的數據量,速度一定快不起來。那如何解決呢?一般情況下,最好的方式是增加一個條件:

selectname,codefromstudentwhereid>1000000limit20

這樣,mysql會走主鍵索引,直接連接到1000000處,然后查出來20條數據。但是這個方式需要接口的調用方配合改造,把上次查詢出來的最大id以參數的方式傳給接口提供方,會有溝通成本(調用方:老子不改!)。

1.2 未加索引

這個是最容易解決的問題,我們可以通過

showcreatetablexxxx(表名)

查看某張表的索引。具體加索引的語句網上太多了,不再贅述。不過順便提一嘴,加索引之前,需要考慮一下這個索引是不是有必要加,如果加索引的字段區分度非常低,那即使加了索引也不會生效。另外,加索引的alter操作,可能引起鎖表,執行sql的時候一定要在低峰期(血淚史!!!!)

1.3 索引失效

這個是慢查詢最不好分析的情況,雖然mysql提供了explain來評估某個sql的查詢性能,其中就有使用的索引。但是為啥索引會失效呢?mysql卻不會告訴咱,需要咱自己分析。大體上,可能引起索引失效的原因有這幾個(可能不完全):

88e72978-9fc3-11ed-bfe3-dac502259ad0.png

需要特別提出的是,關于字段區分性很差的情況,在加索引的時候就應該進行評估。如果區分性很差,這個索引根本就沒必要加。區分性很差是什么意思呢,舉幾個例子,比如:

某個字段只可能有3個值,那這個字段的索引區分度就很低。

再比如,某個字段大量為空,只有少量有值;

再比如,某個字段值非常集中,90%都是1,剩下10%可能是2,3,4....

進一步的,那如果不符合上面所有的索引失效的情況,但是mysql還是不使用對應的索引,是為啥呢?這個跟mysql的sql優化有關,mysql會在sql優化的時候自己選擇合適的索引,很可能是mysql自己的選擇算法算出來使用這個索引不會提升性能,所以就放棄了。這種情況,可以使用force index 關鍵字強制使用索引(建議修改前先實驗一下,是不是真的會提升查詢效率):

selectname,codefromstudentforceindex(XXXXXX)wherename='天才'

其中xxxx是索引名。

1.4 join過多 or 子查詢過多

我把join過多 和子查詢過多放在一起說了。一般來說,不建議使用子查詢,可以把子查詢改成join來優化。同時,join關聯的表也不宜過多,一般來說2-3張表還是合適的。具體關聯幾張表比較安全是需要具體問題具體分析的,如果各個表的數據量都很少,幾百條幾千條,那么關聯的表的可以適當多一些,反之則需要少一些。

另外需要提到的是,在大多數情況下join是在內存里做的,如果匹配的量比較小,或者join_buffer設置的比較大,速度也不會很慢。但是,當join的數據量比較大的時候,mysql會采用在硬盤上創建臨時表的方式進行多張表的關聯匹配,這種顯然效率就極低,本來磁盤的IO就不快,還要關聯。

一般遇到這種情況的時候就建議從代碼層面進行拆分,在業務層先查詢一張表的數據,然后以關聯字段作為條件查詢關聯表形成map,然后在業務層進行數據的拼裝。一般來說,索引建立正確的話,會比join快很多,畢竟內存里拼接數據要比網絡傳輸和硬盤IO快得多。

1.5 in的元素過多

這種問題,如果只看代碼的話不太容易排查,最好結合監控和數據庫日志一起分析。如果一個查詢有in,in的條件加了合適的索引,這個時候的sql還是比較慢就可以高度懷疑是in的元素過多。一旦排查出來是這個問題,解決起來也比較容易,不過是把元素分個組,每組查一次。想再快的話,可以再引入多線程。進一步的,如果in的元素量大到一定程度還是快不起來,這種最好還是有個限制

selectidfromstudentwhereidin(1,2,3......1000)limit200

當然了,最好是在代碼層面做個限制

if(ids.size()>200){
thrownewException("單次查詢數據量不能超過200");
}

1.6 單純的數據量過大

這種問題,單純代碼的修修補補一般就解決不了了,需要變動整個的數據存儲架構。或者是對底層mysql分表或分庫+分表;或者就是直接變更底層數據庫,把mysql轉換成專門為處理大數據設計的數據庫。這種工作是個系統工程,需要嚴密的調研、方案設計、方案評審、性能評估、開發、測試、聯調,同時需要設計嚴密的數據遷移方案、回滾方案、降級措施、故障處理預案。除了以上團隊內部的工作,還可能有跨系統溝通的工作,畢竟做了重大變更,下游系統的調用接口的方式有可能會需要變化。

出于篇幅的考慮,這個不再展開了,筆者有幸完整參與了一次億級別數據量的數據庫分表工作,對整個過程的復雜性深有體會,后續有機會也會分享出來。

2、業務邏輯復雜

2.1 循環調用

這種情況,一般都循環調用同一段代碼,每次循環的邏輯一致,前后不關聯。比如說,我們要初始化一個列表,預置12個月的數據給前端:

Listlist=newArrayList<>();
for(inti=0;i

這種顯然每個月的數據計算相互都是獨立的,我們完全可以采用多線程方式進行:

//建立一個線程池,注意要放在外面,不要每次執行代碼就建立一個,具體線程池的使用就不展開了
publicstaticExecutorServicecommonThreadPool=newThreadPoolExecutor(5,5,300L,
TimeUnit.SECONDS,newLinkedBlockingQueue<>(10),commonThreadFactory,newThreadPoolExecutor.DiscardPolicy());

//開始多線程調用
List>futures=newArrayList<>();
for(inti=0;ifuture=commonThreadPool.submit(()->calOneMonthData(i););
futures.add(future);
}

//獲取結果
Listlist=newArrayList<>();
try{
for(inti=0;i

2.2 順序調用

如果不是類似上面循環調用,而是一次次的順序調用,而且調用之間沒有結果上的依賴,那么也可以用多線程的方式進行,例如:

88f74d62-9fc3-11ed-bfe3-dac502259ad0.png

代碼上看:

Aa=doA();
Bb=doB();

Cc=doC(a,b);

Dd=doD(c);
Ee=doE(c);

returndoResult(d,e);

那么可用CompletableFuture解決

CompletableFuturefutureA=CompletableFuture.supplyAsync(()->doA());
CompletableFuturefutureB=CompletableFuture.supplyAsync(()->doB());
CompletableFuture.allOf(futureA,futureB)//等ab兩個任務都執行完成

Cc=doC(futureA.join(),futureB.join());

CompletableFuturefutureD=CompletableFuture.supplyAsync(()->doD(c));
CompletableFuturefutureE=CompletableFuture.supplyAsync(()->doE(c));
CompletableFuture.allOf(futureD,futureE)//等de兩個任務都執行完成

returndoResult(futureD.join(),futureE.join());

這樣A B 兩個邏輯可以并行執行,D E兩個邏輯可以并行執行,最大執行時間取決于哪個邏輯更慢。

3、線程池設計不合理

有的時候,即使我們使用了線程池讓任務并行處理,接口的執行效率仍然不夠快,這種情況可能是怎么回事呢?

這種情況首先應該懷疑是不是線程池設計的不合理。我覺得這里有必要回顧一下線程池的三個重要參數:核心線程數、最大線程數、等待隊列。這三個參數是怎么打配合的呢?當線程池創建的時候,如果不預熱線程池,則線程池中線程為0。當有任務提交到線程池,則開始創建核心線程。

892629ac-9fc3-11ed-bfe3-dac502259ad0.png

當核心線程全部被占滿,如果再有任務到達,則讓任務進入等待隊列開始等待。

8942b072-9fc3-11ed-bfe3-dac502259ad0.png

如果隊列也被占滿,則開始創建非核心線程運行。

89600fdc-9fc3-11ed-bfe3-dac502259ad0.png

如果線程總數達到最大線程數,還是有任務到達,則開始根據線程池拋棄規則開始拋棄。

897d83f0-9fc3-11ed-bfe3-dac502259ad0.png

那么這個運行原理與接口運行時間有什么關系呢?

核心線程設置過小:核心線程設置過小則沒有達到并行的效果

線程池公用,別的業務的任務執行時間太長,占用了核心線程,另一個業務的任務到達就直接進入了等待隊列

任務太多,以至于占滿了線程池,大量任務在隊列中等待

在排查的時候,只要找到了問題出現的原因,那么解決方式也就清楚了,無非就是調整線程池參數,按照業務拆分線程池等等。

4、鎖設計不合理

鎖設計不合理一般有兩種:鎖類型使用不合理 or 鎖過粗。

鎖類型使用不合理的典型場景就是讀寫鎖。也就是說,讀是可以共享的,但是讀的時候不能對共享變量寫;而在寫的時候,讀寫都不能進行。在可以加讀寫鎖的時候,如果我們加成了互斥鎖,那么在讀遠遠多于寫的場景下,效率會極大降低。

鎖過粗則是另一種常見的鎖設計不合理的情況,如果我們把鎖包裹的范圍過大,則加鎖時間會過長,例如:

publicsynchronizedvoiddoSome(){
Filef=calData();
uploadToS3(f);
sendSuccessMessage();
}

這塊邏輯一共處理了三部分,計算、上傳結果、發送消息。顯然上傳結果和發送消息是完全可以不加鎖的,因為這個跟共享變量根本不沾邊。因此完全可以改成:

publicvoiddoSome(){
Filef=null;
synchronized(this){
f=calData();
}
uploadToS3(f);
sendSuccessMessage();
}

5、機器問題(fullGC,機器重啟,線程打滿)

造成這個問題的原因非常多,筆者就遇到了定時任務過大引起fullGC,代碼存在線程泄露引起RSS內存占用過高進而引起機器重啟等待諸多原因。需要結合各種監控和具體場景具體分析,進而進行大事務拆分、重新規劃線程池等等工作

6、萬金油解決方式

萬金油這個形容詞是從我們單位某位老師那里學來的,但是筆者覺得非常貼切。這些萬金油解決方式往往能解決大部分的接口緩慢的問題,而且也往往是我們解決接口效率問題的最終解決方案。當我們實在是沒有辦法排查出問題,或者實在是沒有優化空間的時候,可以嘗試這種萬金油的方式。

6.1 緩存

緩存是一種空間換取時間的解決方案,是在高性能存儲介質上(例如:內存、SSD硬盤等)存儲一份數據備份。當有請求打到服務器的時候,優先從緩存中讀取數據。如果讀取不到,則再從硬盤或通過網絡獲取數據。由于內存或SSD相比硬盤或網絡IO的效率高很多,則接口響應速度會變快非常多。緩存適合于應用在數據讀遠遠大于數據寫,且數據變化不頻繁的場景中。從技術選型上看,有這些:

簡單的map

guava等本地緩存工具包

緩存中間件:redis、tair或memcached

當然,memcached現在用的很少了,因為相比于redis他不占優勢。tair則是阿里開發的一個分布式緩存中間件,他的優勢是理論上可以在不停服的情況下,動態擴展存儲容量,適用于大數據量緩存存儲。相比于單機redis緩存當然有優勢,而他與可擴展Redis集群的對比則需要進一步調研。

進一步的,當前緩存的模型一般都是key-value模型。如何設計key以提高緩存的命中率是個大學問,好的key設計和壞的key設計所提升的性能差別非常大。而且,key設計是沒有一定之規的,需要結合具體的業務場景去分析。各個大公司分享出來的相關文章,緩存設計基本上是最大篇幅。

6.2 回調 or 反查

這種方式往往是業務上的解決方式,在訂單或者付款系統中應用的比較多。舉個例子:當我們付款的時候,需要調用一個專門的付款系統接口,該系統經過一系列驗證、存儲工作后還要調用銀行接口以執行付款。由于付款這個動作要求十分嚴謹,銀行側接口執行可能比較緩慢,進而拖累整個付款接口性能。這個時候我們就可以采用fast success的方式:當必要的校驗和存儲完成后,立即返回success,同時告訴調用方一個中間態“付款中”。而后調用銀行接口,當獲得支付結果后再調用上游系統的回調接口返回付款的最終結果“成果”or“失敗”。這樣就可以異步執行付款過程,提升付款接口效率。當然,為了防止多業務方接入的時候回調接口不統一,可以把結果拋進kafka,讓調用方監聽自己的結果。

899e6584-9fc3-11ed-bfe3-dac502259ad0.png

審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 接口
    +關注

    關注

    33

    文章

    8961

    瀏覽量

    153281
  • 數據庫
    +關注

    關注

    7

    文章

    3904

    瀏覽量

    65822
  • MySQL
    +關注

    關注

    1

    文章

    849

    瀏覽量

    27610
  • 線程
    +關注

    關注

    0

    文章

    507

    瀏覽量

    20100
  • 接口優化
    +關注

    關注

    0

    文章

    4

    瀏覽量

    1398

原文標題:聊聊接口優化的幾個方法

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦
    熱點推薦

    ARM開發中幾個常見的寄存器詳解

    筆者今天來聊聊對于ARM幾個特殊寄存器的理解,FP、SP和LR。
    發表于 11-22 09:02 ?5016次閱讀

    聊聊寄存器被優化的2種情況

    在項目初期,在使用FPGA工具quartus或者vivado生成版本燒入開發板進行調試時(DC開啟優化選項后同樣會優化掉寄存器),我們有時會發現部分寄存器被優化掉了,今天簡單聊聊
    的頭像 發表于 09-08 15:09 ?2804次閱讀
    <b class='flag-5'>聊聊</b>寄存器被<b class='flag-5'>優化</b>的2種情況

    差分接口優化射頻收發器設計介紹

    實際設計過程中,工程師需要處理幾個常見問題,包括阻抗匹配、共模電壓匹配以及復雜的增益計算。了解發射機和接收機中的差分電路對優化增益匹配和系統性能很有幫助。 
    發表于 07-04 07:47

    電源優化方法是什么

    目錄一、電源優化方法1.1 功能禁用1.2 動態功耗管理 (Dynamic Power Management)1.3 頻率縮放1.4 時鐘門控1.5 使用PL加速二、四大功耗域及PMU2.1 電池
    發表于 11-12 08:36

    聊聊使用功率FET應該注意的問題有哪些

    穩壓電源,幾乎都能發現FET的影子。幾乎每個電源工程師都用過這東西,或用來逆變;或用來整流;或就當個開關。 由于用處不同;每個廠家都對不同用處FET做了專門優化。以致同樣耐壓/電流的FET;有多個
    發表于 11-12 07:10

    幾個android版本中電量優化功能

    針對電量優化android的改動在最近幾個android版本中已存在的電量優化功能基礎上,Android 9 引入了一些新功能來持續改進設備電源管理,以確保將系統資源提供給最需要它們的應用.近
    發表于 12-27 07:23

    聊聊復位電路

    時鐘電路我第一篇博客已經說講過了,今天我們來聊聊復位電路。當然,復位電路博大精深,并...
    發表于 01-17 07:50

    優化Unity程序的方法

    的幀速率,使其成為更好、更流暢的體驗。 本指南介紹了優化Unity程序的方法,尤其是它們的GPU使用。 本指南將優化分為三章: ?應用程序處理器優化?GPU
    發表于 08-02 18:52

    接口協議智能編解碼方法研究

    針對當前復雜信息系統仿真中,關于接口協議編解碼方法的缺陷,從接口協議的存儲、程序設計的數據結構和編解碼流程幾個方面,給出了復雜信息系統仿真中接口
    發表于 02-21 11:07 ?20次下載

    提升WiFi信號質量的幾個方法

    提升WiFi信號質量的幾個方法
    發表于 01-12 21:58 ?11次下載

    優化嵌入式軟件時可以遵循幾個通用技巧盤點

    早前的專欄中曾討論過在許多情況下需要優化的嵌入式系統的關鍵特征,包括系統時序、代碼大小、RAM使用率和能耗。雖然優化每個特征通常要求不同的方法和技術,但開發人員在優化嵌入式軟件時可以遵
    發表于 03-08 14:40 ?744次閱讀

    幾個Matlab編程中常用的優化技巧

    用過Matlab的同學應該都知道,Matlab的慢是出了名的,但是再慢也有優化的方式,下面我們給出幾個Matlab編程中常用的優化技巧。
    的頭像 發表于 02-08 15:18 ?4053次閱讀

    利用axi_master接口指令端的幾個靜態參數的優化技巧

    本文給大家提供利用axi_master接口指令端的幾個靜態參數的優化技巧,從擴展總線接口數量,擴展總線位寬,循環展開等角度入手。最核心的優化
    的頭像 發表于 07-01 09:39 ?1783次閱讀

    接口優化的常見方案實戰總結

    針對老項目,去年做了許多降本增效的事情,其中發現最多的就是接口耗時過長的問題,就集中搞了一次接口性能優化。本文將給小伙伴們分享一下接口優化
    的頭像 發表于 03-06 09:22 ?743次閱讀

    聊聊JVM如何優化

    進行優化。 1.JVM內存模型 針對JAVA8的模型進行討論,JVM的內存模型主要分為幾個關鍵區域:堆、方法區、程序計數器、虛擬機棧和本地方法棧。堆內存進一步細分為年輕代、老年代,年輕
    的頭像 發表于 08-05 17:49 ?725次閱讀
    <b class='flag-5'>聊聊</b>JVM如何<b class='flag-5'>優化</b>
    主站蜘蛛池模板: 五月亭亭六月丁香 | 日本特黄绿像大片免费看 | www.黄网站| 苍井优一级毛片免费观看 | 婷色 | 特黄一级视频 | 日本免费人成黄页网观看视频 | 午夜国产精品理论片久久影院 | 男人的天堂免费视频 | 久操操 | 手机看片福利1024 | 日日久| 一区二区三区伦理 | 全免费午夜一级毛片真人 | 亚洲欧美视频在线播放 | 五月激情综合网 | 天天色天天干天天射 | 四虎午夜影院 | 天天做人人爱夜夜爽2020毛片 | 午夜伦伦| 综合网天天操天天射 | 天天摸日日摸 | 黄色一级日本 | 精品国产柚木在线观看 | 影院成人区精品一区二区婷婷丽春院影视 | 欧美精品 在线播放 | 亚洲天堂视频在线观看免费 | 大尺度视频网站久久久久久久久 | 视频在线高清完整免费观看 | 成人黄色网址 | 日本三级黄视频 | 欧美在线91 | 5566在线观看 | 色噜噜狠狠大色综合 | 人人爽天天爽夜夜爽曰 | 午夜视频网站 | 511韩国理论片在线观看 | 国产真实偷乱视频在线观看 | 日韩成人免费观看 | 午夜五月天 | 人人爱爱 |