【面經(jīng)】面試官:做過性能優(yōu)化的工作嗎?你會從哪些方面入手做性能優(yōu)化呢?
作者個人研發(fā)的在高并發(fā)場景下,提供的簡單、穩(wěn)定、可擴展的延遲消息隊列框架,具有精準的定時任務和延遲隊列處理功能。自開源半年多以來,已成功為十幾家中小型企業(yè)提供了精準定時調(diào)度方案,經(jīng)受住了生產(chǎn)環(huán)境的考驗。為使更多童鞋受益,現(xiàn)給出開源框架地址:https://github.com/sunshinelyz/mykit-delay
寫在前面
隨著互聯(lián)網(wǎng)的高速發(fā)展,互聯(lián)網(wǎng)行業(yè)已經(jīng)從IT時代慢慢步入到DT時代。對于Java程序員的要求越來越高,只是單純的掌握CRUD不足以勝任互聯(lián)網(wǎng)公司的相關(guān)職位,大量招聘崗位顯示:如果是面試中高級的Java崗,基本上都需要懂性能優(yōu)化的相關(guān)知識。今天,我們就一起來聊聊一個經(jīng)典的面試題:做過性能優(yōu)化的工作嗎?你會從哪些方面入手做性能優(yōu)化呢?
問題分析
標題中問出了兩個問題,一個是有沒有做過性能優(yōu)化的工作,一個是從哪些方面入手做性能優(yōu)化。對于第一個問題,我們可以直接回答有或者沒有。相信小伙伴們都希望自己做過性能優(yōu)化的工作,如果是回答做過,那第二個問題,我們又該如何回答呢?
首先,對于第二個問題來說,問的是會從哪些方面入手。這個問題就沒有固定答案了。你可以按照你以往的經(jīng)驗來回答這個問題,但是,在回答這個問題之前,需要先好好梳理下你的思路,將你要表達的說清楚。
接下來,我們就一起來聊聊第二個問題:你會從哪些方面入手做性能優(yōu)化?
我們可以從性能優(yōu)化的幾個方面來進行回答。下面,我們就來聊聊性能優(yōu)化可以從哪些方面進行。
性能優(yōu)化有哪些方面?
這里,我結(jié)合平時工作中的總結(jié),將性能優(yōu)化總結(jié)為下面這張圖。
也就是說,我們可以從數(shù)據(jù)聚合優(yōu)化、資源沖突優(yōu)化、算法優(yōu)化、JVM優(yōu)化、復用優(yōu)化、計算優(yōu)化和快速實現(xiàn)等方面來進行回答。接下來,我們就針對每個點進行說明。
數(shù)據(jù)聚合優(yōu)化
數(shù)據(jù)聚合優(yōu)化主要針對的是對于數(shù)據(jù)的整合和傳輸?shù)膬?yōu)化。比如:我們從數(shù)據(jù)庫中查詢出的數(shù)據(jù),經(jīng)過程序的聚合處理后再返回給客戶端,而不用客戶端調(diào)用多次接口來分別獲取數(shù)據(jù)。
再比如:我們在項目中使用的Nginx,一般都會開啟GZIP壓縮,使傳輸?shù)臄?shù)據(jù)更加緊湊,同時,使傳輸?shù)臄?shù)據(jù)量更小。
細心的小伙伴會發(fā)現(xiàn),我們對于數(shù)據(jù)聚合的優(yōu)化,主要是使傳輸?shù)臄?shù)據(jù)量更小。所以,我們在使用SQL語句查詢數(shù)據(jù)庫中的數(shù)據(jù)時,盡量查詢那些需要的字段,對于不需要的字段就直接忽略不查詢了,避免在SQL語句中出現(xiàn)select *
資源沖突優(yōu)化
在我們平時的工作中,尤其是在高并發(fā)的場景下,經(jīng)常會出現(xiàn)鎖沖突的問題,鎖沖突是資源沖突的一個典型場景。
關(guān)于鎖我們可以聯(lián)想到數(shù)據(jù)庫的行鎖、表鎖、Java中的synchronized和Lock等。如果對應到操作系統(tǒng)級別,則會有CPU命令級別的鎖,JVM指令級別的鎖,操作系統(tǒng)的內(nèi)部鎖等。
這里,小伙伴們需要注意一點:只有在并發(fā)的場景下,才會出現(xiàn)資源沖突的問題。也就是說:在同一時刻,只能有一個請求獲取到請求資源,解決沖突的方式就是加鎖。
算法優(yōu)化
在一個大型的互聯(lián)網(wǎng)項目中,往往涉及到分布式和微服務等技術(shù),其中,也會使用到大量的數(shù)據(jù)結(jié)構(gòu)和算法,對于算法的優(yōu)化能夠顯著的提高系統(tǒng)的性能。一個好的實現(xiàn),相比于一個拙劣的實現(xiàn)來說,在系統(tǒng)性能的提升上存在著巨大的差異。
比如,作為 List 的實現(xiàn),LinkedList 和 ArrayList 在隨機訪問的性能上,差了好幾個數(shù)量級;又比如,CopyOnWriteList 采用寫時復制的方式,可以顯著降低讀多寫少場景下的鎖沖突。而什么時候使用同步,什么時候是線程安全的,也對我們的編碼能力有較高的要求。
所以,我們需要在平時工作過程中,多多積累數(shù)據(jù)結(jié)構(gòu)和算法的相關(guān)知識。
JVM優(yōu)化
JVM調(diào)優(yōu),不用說,這是每個Java工程師必須要掌握的標準技能。所有的Java程序最終都是運行在JVM中的,對JVM進行優(yōu)化也能夠提升Java程序的性能。但是,需要注意的是:如果在優(yōu)化JVM時,參數(shù)設(shè)置不當,可能會造成內(nèi)存溢出等嚴重的問題。
目前被廣泛使用的垃圾回收器是 G1,通過很少的參數(shù)配置,內(nèi)存即可高效回收。CMS 垃圾回收器已經(jīng)在 Java 14 中被移除,由于它的 GC 時間不可控,有條件應該盡量避免使用。
復用優(yōu)化
復用優(yōu)化,這個看名字就知道,說白了就是可以重復利用。估計很多小伙伴都有這樣的經(jīng)驗,在寫代碼的時候,可以將很多重復的代碼抽象出來,做成公共的方法。這樣,就不用每次都去寫重復的邏輯代碼了。這是代碼層面的復用。
如果是數(shù)據(jù)層面的話,我們可以使用緩沖和緩存來復用數(shù)據(jù)。
這里,小伙伴們需要注意一個知識點:緩沖主要針對的是寫操作,緩存主要針對的是讀操作。
另一個復用優(yōu)化的典型場景就是池化技術(shù),比如:數(shù)據(jù)庫連接池、線程池等。
計算優(yōu)化
對于計算優(yōu)化來說,我們可以從以下幾個小的方面來闡述。
并行計算
不難理解,就是多個計算同時進行。這里,又可以將并行計算分為:多機并行計算、多進程并行計算和多線程并行計算。
多機并行計算: 將一個大的計算任務,拆分成N個小的計算任務,分發(fā)到不同的機器進行處理。典型的場景就是Hadoop的MapReduce極端。
多進程計算: 比如,Nginx采用的NIO模型,采用的是進程調(diào)度的策略,由Master進程調(diào)度Worker進程,Worker進行來處理具體的請求。
多線程計算:對于多線程計算來說,也是我們平時接觸最多的一種計算方式,我們可以使用多線程技術(shù),將復雜的邏輯計算拆分成一個個小的計算任務,分發(fā)到不同的線程中去執(zhí)行。
同步變異步
同步和異步的區(qū)別就是:同步需要等待返回結(jié)果,異步不需要等待返回結(jié)果。如果我們在業(yè)務程序中,不需要等待返回結(jié)果數(shù)據(jù),則我們可以將同步調(diào)用優(yōu)化為異步調(diào)用,從而提升我們系統(tǒng)的性能。
懶加載
最典型的場景就是Spring中的懶加載,只有第一次獲取bean的時候,才會創(chuàng)建bean實例。
快速實現(xiàn)
對于快速實現(xiàn)來說,不僅包含我們需要利用相關(guān)的程序框架迅速開發(fā)出我們想要的業(yè)務,也需要我們在進行技術(shù)選型時,盡量使用一些性能優(yōu)良的組件。比如,在進行網(wǎng)絡(luò)開發(fā)時,盡量選擇Netty,結(jié)合輕量級的數(shù)據(jù)傳輸,就不要使用WebService等技術(shù)了。
很多公司喜歡使用適配器模式,在一些現(xiàn)有的開源組件之上,再抽象一層自己的組件,這樣就能夠做到切換底層組件的時候,對上層應用無感。
本文轉(zhuǎn)載自微信公眾號「冰河技術(shù)」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系冰河技術(shù)公眾號。