日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

系統(tǒng)性能測試及調(diào)優(yōu)

 WindySky 2016-05-24

原文地址:http://www./front/det-2-1.html

1系統(tǒng)性能定義

性能測試,主要是通過自動化的測試工具模擬多種正常、峰值以及異常負載條件來對系統(tǒng)的各項性能指標進行測試。系統(tǒng)性能主要包括兩個值:

吞吐量(Throughtput),即每秒鐘可以處理的請求數(shù),事務(wù)數(shù)。

系統(tǒng)延遲(Latency),也就是系統(tǒng)在處理一個請求或一個事務(wù)時的延遲。

它們兩者之間的關(guān)系:

Throughput越大,Latency會越差。請求量過大,系統(tǒng)繁忙,響應(yīng)速度自然低。

Latency越好,能支持的Throughput就會越高。因為Latency短說明處理速度快,于是單位時間內(nèi)就可以處理更多的請求。

2系統(tǒng)性能測試

要測試系統(tǒng)的性能,需要我們收集系統(tǒng)的Throughput和Latency這兩個值。

首先,需要定義Latency這個值,如對于網(wǎng)站首頁響應(yīng)時間必需是4秒以內(nèi)(根據(jù)不同的業(yè)務(wù)來定義)

其次,準備性能測試工具,一個工具用來制造高強度的Throughput(通常有Loadrunner、Jmeter等),另一個工具用來測量Latency。關(guān)于如何測量Latency,你可以在代碼中測量,但是這樣會影響程序的執(zhí)行,而且只能測試到程序內(nèi)部的Latency,真正的Latency是整個系統(tǒng)都算上,包括操作系統(tǒng)和網(wǎng)絡(luò)的延時,一般性能測試工具都有配套組件。

最后,開始性能測試。不斷地提升測試環(huán)境的Throughput,然后觀察系統(tǒng)的負載情況,如果系統(tǒng)頂?shù)米?,那就觀察Latency的值。這樣,就可以找到系統(tǒng)的最大負載,并且你可以知道系統(tǒng)的響應(yīng)延時是多少。

下面主要通過三個大的步驟來說明性能測試實施過程: 

前期準備

1、確定用戶、業(yè)務(wù)、系統(tǒng)需求(目標)

  • 確定實際業(yè)務(wù)需求

主要確定用戶的業(yè)務(wù)請求分布等:主要業(yè)務(wù)請求、平均日交易量、年交易量、峰值交易量等等。

  • 確定系統(tǒng)需求

主要工作是分析系統(tǒng)的性能需求、確定合理的性能目標。

  • 確定客戶的需求和期望

在需求分析文檔的支持下,對軟件系統(tǒng)上的用戶業(yè)務(wù)使用情況進行分析,提出我們所關(guān)注的性能測試需求,并告知業(yè)務(wù)人員。讓業(yè)務(wù)人員來判斷我們的性能需求是否滿足客戶的真實需求。

2、確定系統(tǒng)類別

分清系統(tǒng)類別是我們掌握什么樣技術(shù)的前提,掌握相應(yīng)技術(shù)做性能測試才可能成功。例如:系統(tǒng)類別是B/S結(jié)構(gòu),需要掌握HTTP協(xié)議,java,C#,html等技術(shù)?;蛘呤荂/S結(jié)構(gòu),可能要了解操作系統(tǒng),winsock,com等。

3、確定系統(tǒng)構(gòu)成

不同的系統(tǒng)構(gòu)成性能測試會得到不同的結(jié)果。

4、確定實際網(wǎng)絡(luò)帶寬

便于測試時對帶寬做模擬,盡可能真實的反饋帶寬使用情況。

5、確定測試服務(wù)器與測試機配置清單

了解性能測試硬件資源(包括所測服務(wù)器,測試機等),根據(jù)實際情況添加設(shè)備。

6、系統(tǒng)功能流程圖

便于測試人員分析系統(tǒng)哪些模塊易出現(xiàn)瓶頸,從而針對性做性能測試。

7、測試時間評估

根據(jù)測試時間,制定相應(yīng)的測試執(zhí)行策略。

在我的實際性能測試工作中,會把上面作為問題列表的形式打印出來,然后通過不斷溝通和分析去完善它,以便幫助我后期更好的制定性能測試策略。這樣的問題列表如:

  • 具體哪些業(yè)務(wù)需要做性能測試?
  • 從測試類型來看(列出性能測試類型、對應(yīng)的解釋及指標,方便調(diào)查對象參考),要對性能關(guān)鍵業(yè)務(wù)做以上一項或多項測試?
  • 采用什么系統(tǒng)部署環(huán)境?系統(tǒng)的版本和位數(shù)是多少?
  • ……

測試實施

1、根據(jù)前期準備制定編寫性能測試方案
應(yīng)該包括性能測試通過的標準、所測的對象(業(yè)務(wù)或場景)、測試環(huán)境說明、測試所用時間及資源,測試策略等。
2、設(shè)計性能測試用例
指導(dǎo)測試人員進行性能測試。
3、編寫性能測試腳本
測試腳本應(yīng)該具有可重復(fù)執(zhí)行性,可并發(fā)執(zhí)行性,能盡可能真實模擬單用戶業(yè)務(wù)使用場景。
4、模擬運行場景
用性能工具模擬用戶負載使用系統(tǒng)的場景。
5、配置運行場景
被測環(huán)境應(yīng)該在測試前做好備份;配置包括被測系統(tǒng)日志、中間件(MySQL、Apache等)使用情況、服務(wù)器資源使用情況的數(shù)據(jù)收據(jù);運行應(yīng)避免偶然性事件,所以一個測試場景應(yīng)該至少運行兩次及以上。

瓶頸分析和性能優(yōu)化

瓶頸分析難點在于理解收集到的數(shù)據(jù)反饋的真是含義,所以要求測試人員具備相應(yīng)的技術(shù)知識儲備(包括數(shù)據(jù)庫的知識、計算機原理知識、網(wǎng)絡(luò)基礎(chǔ)、各中間件性能計量含義等),這里先僅列舉下性能測試結(jié)果分析原則:

  • 把事實與推測分開,總是用實際的證據(jù)來證明你的推測;
  • 在沒有足夠證據(jù)前,不對程序進行優(yōu)化;
  • 優(yōu)先驗證簡單的假設(shè)(推測瓶頸);
  • 日志文件中沒有錯誤不代表真的沒有錯誤;
  • 從系統(tǒng)到應(yīng)用、從外到內(nèi)進行層層剝離,縮小范圍;
  • 范圍縮小后,再分割成多個單元,對每個單元進行輪番壓力測試,來證明或者否定是哪個單元引起的性能問題 。

瓶頸優(yōu)化應(yīng)該有難到易的進行優(yōu)化,下面為推薦(應(yīng)根據(jù)公司實際情況調(diào)整):

服務(wù)器硬件瓶頸->網(wǎng)絡(luò)瓶頸->服務(wù)器操作系統(tǒng)瓶頸->中間件瓶頸->應(yīng)用瓶頸

3定位性能瓶頸

3.1查看操作系統(tǒng)負載

系統(tǒng)有問題首要需要看的是操作系統(tǒng)報告。查看操作系統(tǒng)的CPU利用率,內(nèi)存使用率,操作系統(tǒng)的IO,還有網(wǎng)絡(luò)的IO,網(wǎng)絡(luò)鏈接數(shù)等。

  • 先看CPU利用率,如果CPU利用率不高,但是系統(tǒng)的Throughput和Latency上不去了,這說明程序并沒有忙于計算,而是忙做其它事,比如IO。(另外,CPU的利用率還要看內(nèi)核態(tài)的和用戶態(tài)的,內(nèi)核態(tài)的上去了,整個系統(tǒng)的性能就下來了。而對于多核CPU來說,CPU 0 是相當關(guān)鍵的,如果CPU 0的負載高,那么會影響其它核的性能,因為CPU各核間是需要有調(diào)度的,這靠CPU0完成)
  • 然后,我們可以查看一下IO大小,IO和CPU一般是反著來的,CPU利用率高則IO不大,IO大則CPU就小。關(guān)于IO,我們要看三個事,一個是磁盤文件IO,一個是驅(qū)動程序的IO(如:網(wǎng)卡),一個是內(nèi)存換頁率。這三個事都會影響系統(tǒng)性能。
  • 然后,查看一下網(wǎng)絡(luò)帶寬使用情況。
  • 如果CPU不高,IO不高,內(nèi)存使用不高,網(wǎng)絡(luò)帶寬使用不高。但是系統(tǒng)的性能上不去。這說明你的程序有問題,比如,你的程序被阻塞了??赡苁且驗榈饶莻€鎖,可能是因為等某個資源,或者是在切換上下文。

通過了解操作系統(tǒng)的性能,我們才知道性能的問題,比如:帶寬不夠,內(nèi)存不夠,TCP緩沖區(qū)不夠,等等,很多時候,不需要調(diào)整程序的,只需要調(diào)整一下硬件或操作系統(tǒng)的配置就可以了。

3.2使用profiler測試程序瓶頸

使用某個Profiler來查看一下我們程序的運行性能。如:Java的JProfiler。使用Profiler工具,可以讓你查看程序中各個模塊函數(shù)甚至指令的很多東西,如:運行的時間 ,調(diào)用的次數(shù),CPU的利用率,等等。

我們重點觀察運行時間最多,調(diào)用次數(shù)最多的那些函數(shù)和指令。這里注意一下,對于調(diào)用次數(shù)多但是時間很短的函數(shù),你可能只需要輕微優(yōu)化一下,你的性能就上去了。

因為Profiler會讓你的程序運行的性能變低對此,一般有兩個方法來定位系統(tǒng)瓶頸:

1)在你的代碼中自己做統(tǒng)計,使用微秒級的計時器和函數(shù)調(diào)用計算器,每隔10秒把統(tǒng)計log到文件中。

2)分段注釋你的代碼塊,讓一些函數(shù)空轉(zhuǎn),做Hard Code的Mock,然后再測試一下系統(tǒng)的Throughput和Latency是否有質(zhì)的變化,如果有,那么被注釋的函數(shù)就是性能瓶頸,再在這個函數(shù)體內(nèi)注釋代碼,直到找到最耗性能的語句。

查看匯編代碼經(jīng)常會給你一些意想不到的東西讓你知道為什么程序的性能是那樣。

對于性能測試,不同的Throughput會出現(xiàn)不同的測試結(jié)果,不同的測試數(shù)據(jù)也會有不同的測試結(jié)果。所以,用于性能測試的數(shù)據(jù)非常重要,性能測試中,我們需要測試觀察不同Throughput的結(jié)果。

4性能調(diào)優(yōu)(代碼技術(shù)細節(jié)層面)

一般來說,性能優(yōu)化也就是下面的幾個策略:

  • 用空間換時間。各種cache如CPU L1/L2/RAM到硬盤,都是用空間來換時間的策略。這樣策略基本上是把計算的過程一步一步的保存或緩存下來,這樣就不用每次用的時候都要再計算一遍,比如數(shù)據(jù)緩沖,CDN等。這樣的策略還表現(xiàn)為冗余數(shù)據(jù),比如數(shù)據(jù)鏡象,負載均衡什么的。
  • 用時間換空間。有時候,少量的空間可能性能會更好,比如網(wǎng)絡(luò)傳輸,如果有一些壓縮數(shù)據(jù)的算法(如 “Huffman 編碼壓縮算法” 和 “rsync 的核心算法”),這樣的算法其實很耗時,但是因為瓶頸在網(wǎng)絡(luò)傳輸,所以用時間來換空間反而能省時間。
  • 簡化代碼。最高效的程序就是不執(zhí)行任何代碼的程序,所以,代碼越少性能就越高。如:減少循環(huán)的層數(shù),減少遞歸,在循環(huán)中少聲明變量,少做分配和釋放內(nèi)存的操作,盡量把循環(huán)體內(nèi)的表達式抽到循環(huán)外,條件表達的中的多個條件判斷的次序,盡量在程序啟動時把一些東西準備好,注意函數(shù)調(diào)用的開銷(棧上的開銷),注意面向?qū)ο笳Z言中臨時對象的開銷,小心使用異常(不要用異常來檢查一些可接受可忽略并經(jīng)常發(fā)生的錯誤),…… 等等,這些東西需要我們非常了解編程語言和常用的庫。
  • 并行處理。如果CPU只有一個核,你要玩多進程,多線程,對于計算密集型的軟件會反而更慢(因為操作系統(tǒng)調(diào)度和切換開銷很大),CPU的核多了才能真正體現(xiàn)出多進程多線程的優(yōu)勢。并行處理需要我們的程序有Scalability,不能水平或垂直擴展的程序無法進行并行處理。從架構(gòu)上來說,這表再為——是否可以做到不改代碼只是加加機器就可以完成性能提升?

總之,根據(jù)28原則來說,20%的代碼耗了你80%的性能,找到那20%的代碼,你就可以優(yōu)化那80%的性能。 下面為一些最有價值的性能調(diào)優(yōu)的的方法,供參考。

4.1算法調(diào)優(yōu)

算法非常重要,好的算法會有更好的性能。下面為幾個算法調(diào)優(yōu)例子:

  • 一個是過濾算法,系統(tǒng)需要對收到的請求做過濾,我們把可以被filter in/out的東西配置在了一個文件中,原有的過濾算法是遍歷過濾配置,后來我們找到了一種方法可以對這個過濾配置進行排序,這樣就可以用二分折半的方法來過濾,系統(tǒng)性能增加了50%。
  • 一個是哈希算法。計算哈希算法的函數(shù)并不高效,一方面是計算太費時,另一方面是碰撞太高,碰撞高了就跟單向鏈表一個性能。我們知道,算法都是和需要處理的數(shù)據(jù)很有關(guān)系的,就算是被大家所嘲笑的“冒泡排序”在某些情況下(大多數(shù)數(shù)據(jù)是排好序的)其效率會高于所有的排序算法。哈希算法也一樣,廣為人知的哈希算法都是用英文字典做測試,但是我們的業(yè)務(wù)在數(shù)據(jù)有其特殊性,所以,對于還需要根據(jù)自己的數(shù)據(jù)來挑選適合的哈希算法。
  • 分而治之和預(yù)處理。以前有一個程序為了生成月報表,每次都需要計算很長的時間,有時候需要花將近一整天的時間。于是我們把我們找到了一種方法可以把這個算法發(fā)成增量式的,也就是說我每天都把當天的數(shù)據(jù)計算好了后和前一天的報表合并,這樣可以大大的節(jié)省計算時間,每天的數(shù)據(jù)計算量只需要20分鐘,但是如果我要算整個月的,系統(tǒng)則需要10個小時以上(SQL語句在大數(shù)據(jù)量面前性能成級數(shù)性下降)。這種分而治之的思路在大數(shù)據(jù)面前對性能有很幫助,就像merge排序一樣。SQL語句和數(shù)據(jù)庫的性能優(yōu)化也是這一策略,如:使用嵌套式的Select而不是笛卡爾積的Select,使用視圖,等等。

4.2代碼調(diào)優(yōu)

代碼上的調(diào)優(yōu)大致有下面這幾點:

  • 字符串操作。這是最費系統(tǒng)性能的事了,無論是strcpy, strcat還是strlen,最需要注意的是字符串匹配。所以,能用整型最好用整型。
  • 多線程調(diào)優(yōu)。有人說thread is evil,這個對于系統(tǒng)性能在某些時候是個問題。因為多線程瓶頸就在于互斥和同步的鎖上,以及線程上下文切換的成本,怎么樣的少用鎖或不用鎖是根本(比如:多版本并發(fā)控制(MVCC)在分布式系統(tǒng)中的應(yīng)用 中說的樂觀鎖可以解決性能問題),此外,還有讀寫鎖也可以解決大多數(shù)是讀操作的并發(fā)的性能問題。另外,線程不是越多越好,線程間的調(diào)度和上下文切換也是很夸張的事,盡可能的在一個線程里干,盡可能的不要同步線程。這會讓你有很多的性能。
  • 內(nèi)存分配。不要小看程序的內(nèi)存分配。malloc/realloc/calloc這樣的系統(tǒng)調(diào)用非常耗時,尤其是當內(nèi)存出現(xiàn)碎片的時候。池化技術(shù),如線程池,連接池等。池化技術(shù)對于一些短作業(yè)來說(如http服務(wù))相當?shù)挠行?。這項技術(shù)可以減少鏈接建立,線程創(chuàng)建的開銷,從而提高性能。
  • 異步操作。我們知道Unix下的文件操作是有block和non-block的方式的,像有些系統(tǒng)調(diào)用也是block式的,如:Socket下的select,Windows下的WaitforObject之類的,如果我們的程序是同步操作,那么會非常影響性能,我們可以改成異步的,但是改成異步的方式會讓你的程序變復(fù)雜。異步方式一般要通過隊列,要注意隊列的性能問題,另外,異步下的狀態(tài)通知通常是個問題,比如消息事件通知方式,有callback方式,等,這些方式同樣可能會影響你的性能。但是通常來說,異步操作會讓性能的吞吐率有很大提升(Throughput),但是會犧牲系統(tǒng)的響應(yīng)時間(latency)。這需要業(yè)務(wù)上支持。
  • 語言和代碼庫。我們要熟悉語言以及所使用的函數(shù)庫或類庫的性能。比如:STL中的很多容器分配了內(nèi)存后,那怕你刪除元素,內(nèi)存也不會回收,其會造成內(nèi)存泄露的假像,并可能造成內(nèi)存碎片問題。再如,STL某些容器的size()==0  和 empty()是不一樣的,因為,size()是O(n)復(fù)雜度,empty()是O(1)的復(fù)雜度,這個要小心。如Java中的JVM調(diào)優(yōu)需要使用的這些參數(shù):-Xms -Xmx -Xmn -XX:SurvivorRatio -XX:MaxTenuringThreshold,還需要注意JVM的GC,GC的威力大家都知道,尤其是full GC(還整理內(nèi)存碎片),他運行的時候,整個世界的時間都停止了。

4.3網(wǎng)絡(luò)調(diào)優(yōu)

下面只講一些概念上的東西。

1、TCP調(diào)優(yōu)

TCP鏈接是有很多開銷的,一個是會占用文件描述符,另一個是會開緩存,一般來說一個系統(tǒng)可以支持的TCP鏈接數(shù)是有限的,我們需要清楚地認識到TCP鏈接對系統(tǒng)的開銷是很大的。正是因為TCP是耗資源的,所以,很多攻擊都是讓你系統(tǒng)上出現(xiàn)大量的TCP鏈接,把你的系統(tǒng)資源耗盡。比如著名的SYNC Flood攻擊。

所以,我們要注意配置KeepAlive參數(shù),這個參數(shù)的意思是定義一個時間,如果鏈接上沒有數(shù)據(jù)傳輸,系統(tǒng)會在這個時間發(fā)一個包,如果沒有收到回應(yīng),那么TCP就認為鏈接斷了,然后就會把鏈接關(guān)閉,這樣可以回收系統(tǒng)資源開銷。(注:HTTP層上也有KeepAlive參數(shù))對于像HTTP這樣的短鏈接,設(shè)置一個1-2分鐘的keepalive非常重要。這可以在一定程度上防止DoS攻擊。有下面幾個參數(shù)(下面這些參數(shù)的值僅供參考):

net.ipv4.tcp_keepalive_probes = 5

net.ipv4.tcp_keepalive_intvl = 20

net.ipv4.tcp_fin_timeout = 30

對于TCP的TIME_WAIT這個狀態(tài),主動關(guān)閉的一方進入TIME_WAIT狀態(tài),TIME_WAIT狀態(tài)將持續(xù)2個MSL(Max Segment Lifetime),默認為4分鐘,TIME_WAIT狀態(tài)下的資源不能回收。有大量的TIME_WAIT鏈接的情況一般是在HTTP服務(wù)器上。對此,有兩個參數(shù)需要注意,

net.ipv4.tcp_tw_reuse=1

net.ipv4.tcp_tw_recycle=1

前者表示重用TIME_WAIT,后者表示回收TIME_WAIT的資源。

TCP還有一個重要的概念叫RWIN(TCP Receive Window Size),這個東西的意思是,我一個TCP鏈接在沒有向Sender發(fā)出ack時可以接收到的最大的數(shù)據(jù)包。為什么這個很重要?因為如果Sender沒有收到Receiver發(fā)過來ack,Sender就會停止發(fā)送數(shù)據(jù)并會等一段時間,如果超時,那么就會重傳。這就是為什么TCP鏈接是可靠鏈接的原因。重傳還不是最嚴重的,如果有丟包發(fā)生的話,TCP的帶寬使用率會馬上受到影響(會盲目減半),再丟包,再減半,然后如果不丟包了,就逐步恢復(fù)。相關(guān)參數(shù)如下:

net.core.wmem_default = 8388608

net.core.rmem_default = 8388608

net.core.rmem_max = 16777216

net.core.wmem_max = 16777216

一般來說,理論上的RWIN應(yīng)該設(shè)置成:吞吐量  * 回路時間。Sender端的buffer應(yīng)該和RWIN有一樣的大小,因為Sender端發(fā)送完數(shù)據(jù)后要等Receiver端確認,如果網(wǎng)絡(luò)延時很大,buffer過小了,確認的次數(shù)就會多,于是性能就不高,對網(wǎng)絡(luò)的利用率也就不高了。也就是說,對于延遲大的網(wǎng)絡(luò),我們需要大的buffer,這樣可以少一點ack,多一些數(shù)據(jù),對于響應(yīng)快一點的網(wǎng)絡(luò),可以少一些buffer。因為,如果有丟包(沒有收到ack),buffer過大可能會有問題,因為這會讓TCP重傳所有的數(shù)據(jù),反而影響網(wǎng)絡(luò)性能。所以,高性能的網(wǎng)絡(luò)重要的是要讓網(wǎng)絡(luò)丟包率非常非常地?。ɑ旧鲜怯迷贚AN里),如果網(wǎng)絡(luò)基本是可信的,這樣用大一點的buffer會有更好的網(wǎng)絡(luò)傳輸性能(來來回回太多太影響性能了)。

2、UDP調(diào)優(yōu)

說到UDP的調(diào)優(yōu), 就得說MTU——最大傳輸單元(其實這對TCP也一樣,因為這是鏈路層上的東西)。所謂最大傳輸單元,你可以想像成是公路上的公交車,假設(shè)一個公交車可以最多坐70人,帶寬就像是公路的車道數(shù)一樣,如果一條路上最多可以容下100輛公交車,那意味著我最多可以運送7000人,但是如果公交車坐不滿,比如平均每輛車只有20人,那么我只運送了2000人,于是我公路資源(帶寬資源)就被浪費了。 所以,我們對于一個UDP的包,我們要盡量地讓它大到MTU的最大尺寸再往網(wǎng)絡(luò)上傳,這樣可以最大化帶寬利用率。對于這個MTU,以太網(wǎng)是1500字節(jié),光纖是4352字節(jié),802.11無線網(wǎng)是7981。但是,當我們用TCP/UDP發(fā)包的時候,我們的有效負載Payload要低于這個值,因為IP協(xié)議會加上20個字節(jié),UDP會加上8個字節(jié)(TCP加的更多),所以,一般來說,你的一個UDP包的最大應(yīng)該是1500-8-20=1472,這是你的數(shù)據(jù)的大小。當然,如果你用光纖的話, 這個值就可以更大一些。(順便說一下,對于某些千光以態(tài)網(wǎng)網(wǎng)卡來說,在網(wǎng)卡上,網(wǎng)卡硬件如果發(fā)現(xiàn)你的包的大小超過了MTU,其會幫你做fragment,到了目標端又會幫你做重組,這就不需要你在程序中處理了)

用Socket編程的時候,你可以使用setsockopt() 設(shè)置 SO_SNDBUF/SO_RCVBUF 的大小,TTL和KeepAlive這些關(guān)鍵的設(shè)置,當然,還有很多,具體可以查看一下Socket的手冊。

最后UDP還有一個最大的好處是multi-cast多播,這個技術(shù)對于你需要在內(nèi)網(wǎng)里通知多臺結(jié)點時非常方便和高效。而且,多播這種技術(shù)對于機會的水平擴展(需要增加機器來偵聽多播信息)也很有利。

3、網(wǎng)卡調(diào)優(yōu)

對于網(wǎng)卡,也是可以調(diào)優(yōu)的,這對于千兆以及網(wǎng)網(wǎng)卡非常必要,在Linux下,我們可以用ifconfig查看網(wǎng)上的統(tǒng)計信息,如果我們看到overrun上有數(shù)據(jù),我們就可能需要調(diào)整一下txqueuelen的尺寸(一般默認為1000),我們可以調(diào)大一些,如:ifconfig eth0 txqueuelen 5000。Linux下還有一個命令叫:ethtool可以用于設(shè)置網(wǎng)卡的緩沖區(qū)大小。在Windows下,我們可以在網(wǎng)卡適配器中的高級選項卡中調(diào)整相關(guān)的參數(shù)(如:Receive Buffers, Transmit Buffer等,不同的網(wǎng)卡有不同的參數(shù))。把Buffer調(diào)大對于需要大數(shù)據(jù)量的網(wǎng)絡(luò)傳輸非常有效。

4、其它網(wǎng)絡(luò)性能

關(guān)于多路復(fù)用技術(shù),也就是用一個線程來管理所有的TCP鏈接,有三個系統(tǒng)調(diào)用要重點注意:一個是select,這個系統(tǒng)調(diào)用只支持上限1024個鏈接,第二個是poll,其可以突破1024的限制,但是select和poll本質(zhì)上是使用的輪詢機制,輪詢機制在鏈接多的時候性能很差,因主是O(n)的算法,所以,epoll出現(xiàn)了,epoll是操作系統(tǒng)內(nèi)核支持的,僅當在鏈接活躍時,操作系統(tǒng)才會callback,這是由操作系統(tǒng)通知觸發(fā)的,但其只有Linux Kernel 2.6以后才支持(準確說是2.5.44中引入的),當然,如果所有的鏈接都是活躍的,過多的使用epoll_ctl可能會比輪詢的方式還影響性能,不過影響的不大。

另外,關(guān)于一些和DNS Lookup的系統(tǒng)調(diào)用要小心,比如:gethostbyaddr/gethostbyname,這個函數(shù)可能會相當?shù)馁M時,因為其要到網(wǎng)絡(luò)上去找域名,因為DNS的遞歸查詢,會導(dǎo)致嚴重超時,而又不能通過設(shè)置什么參數(shù)來設(shè)置time out,對此你可以通過配置hosts文件來加快速度,或是自己在內(nèi)存中管理對應(yīng)表,在程序啟動時查好,而不要在運行時每次都查。另外,在多線程下面,gethostbyname會一個更嚴重的問題,就是如果有一個線程的gethostbyname發(fā)生阻塞,其它線程都會在gethostbyname處發(fā)生阻塞,這個比較變態(tài),要小心。(可以試試GNU的gethostbyname_r(),這個的性能要好一些) 這種到網(wǎng)上找信息的東西很多,比如,如果你的Linux使用了NIS,或是NFS,某些用戶或文件相關(guān)的系統(tǒng)調(diào)用就很慢,所以要小心。

4.4系統(tǒng)調(diào)優(yōu)

1、I/O模型

前面說到過select/poll/epoll這三個系統(tǒng)調(diào)用,我們都知道,Unix/Linux下把所有的設(shè)備都當成文件來進行I/O,所以,那三個操作更應(yīng)該算是I/O相關(guān)的系統(tǒng)調(diào)用。說到  I/O模型,這對于我們的I/O性能相當重要,我們知道,Unix/Linux經(jīng)典的I/O方式是:

第一種,同步阻塞式I/O。

第二種,同步無阻塞方式。其通過fctnl設(shè)置 O_NONBLOCK 來完成。

第三種,對于select/poll/epoll這三個是I/O不阻塞,但是在事件上阻塞,算是:I/O異步,事件同步的調(diào)用。

第四種,AIO方式。這種I/O 模型是一種處理與 I/O 并行的模型。I/O請求會立即返回,說明請求已經(jīng)成功發(fā)起了。在后臺完成I/O操作時,向應(yīng)用程序發(fā)起通知,通知有兩種方式:一種是產(chǎn)生一個信號,另一種是執(zhí)行一個基于線程的回調(diào)函數(shù)來完成這次 I/O 處理過程。

第四種因為沒有任何的阻塞,無論是I/O上,還是事件通知上,所以,其可以讓你充分地利用CPU,比起第二種同步無阻塞好處就是,第二種要你一遍一遍地去輪詢。Nginx之所以高效,是其使用了epoll和AIO的方式來進行I/O的。

再說一下Windows下的I/O模型:

a)一個是WriteFile系統(tǒng)調(diào)用,這個系統(tǒng)調(diào)用可以是同步阻塞的,也可以是同步無阻塞的,關(guān)于看文件是不是以O(shè)verlapped打開的。關(guān)于同步無阻塞,需要設(shè)置其最后一個參數(shù)Overlapped,微軟叫Overlapped I/O,你需要WaitForSingleObject才能知道有沒有寫完成。這個系統(tǒng)調(diào)用的性能可想而知。

b)另一個叫WriteFileEx的系統(tǒng)調(diào)用,其可以實現(xiàn)異步I/O,并可以讓你傳入一個callback函數(shù),等I/O結(jié)束后回調(diào)之,但是這個回調(diào)的過程Windows是把callback函數(shù)放到了APC(Asynchronous Procedure Calls)的隊列中,然后,只用當應(yīng)用程序當前線程成為可被通知狀態(tài)(Alterable)時,才會被回調(diào)。只有當你的線程使用了這幾個函數(shù)時WaitForSingleObjectExWaitForMultipleObjectsEx

MsgWaitForMultipleObjectsExSignalObjectAndWait 和 SleepEx,線程才會成為Alterable狀態(tài)??梢?,這個模型,還是有wait,所以性能也不高。

c)然后是IOCP – IO Completion Port,IOCP會把I/O的結(jié)果放在一個隊列中,但是,偵聽這個隊列的不是主線程,而是專門來干這個事的一個或多個線程去干(老的平臺要你自己創(chuàng)建線程,新的平臺是你可以創(chuàng)建一個線程池)。IOCP是一個線程池模型。這個和Linux下的AIO模型比較相似,但是實現(xiàn)方式和使用方式完全不一樣。

當然,真正提高I/O性能方式是把和外設(shè)的I/O的次數(shù)降到最低,最好沒有,所以,對于讀來說,內(nèi)存cache通??梢詮馁|(zhì)上提升性能,因為內(nèi)存比外設(shè)快太多了。對于寫來說,cache住要寫的數(shù)據(jù),少寫幾次,但是cache帶來的問題就是實時性的問題,也就是latency會變大,我們需要在寫的次數(shù)上和響應(yīng)上做權(quán)衡。

2、多核CPU調(diào)優(yōu)

關(guān)于CPU的多核技術(shù), CPU0是很關(guān)鍵的,如果0號CPU被用得過多時,別的CPU性能也會下降,因為CPU0作用是有調(diào)整功能的,所以,我們不能任由操作系統(tǒng)負載均衡,因為我們自己更了解自己的程序,所以,我們可以手動的為其分配CPU核,而不會過多地占用CPU0,或是讓我們關(guān)鍵進程和一堆別的進程擠在一起。

對于Windows來說,我們可以通過“任務(wù)管理器”中的“進程”而中右鍵菜單中的“設(shè)置相關(guān)性……”(Set Affinity…)來設(shè)置并限制這個進程能被運行在哪些核上。

對于Linux來說,可以使用taskset命令來設(shè)置(你可以通過安裝schedutils來安裝這個命令:apt-get install schedutils)

多核CPU還有一個技術(shù)叫NUMA技術(shù)(Non-Uniform Memory Access)。傳統(tǒng)的多核運算是使用SMP(Symmetric Multi-Processor )模式,多個處理器共享一個集中的存儲器和I/O總線。于是就會出現(xiàn)一致存儲器訪問的問題,一致性通常意味著性能問題。NUMA模式下,處理器被劃分成多個node, 每個node有自己的本地存儲器空間。在Linux下,對NUMA調(diào)優(yōu)的命令是:numactl 。如下面的命令:(指定命令“myprogram arg1 arg2”運行在node 0 上,其內(nèi)存分配在node 0 和 1上)

numactl --cpubind=0 --membind=0,1 myprogram arg1 arg2

當然,上面這個命令并不好,因為內(nèi)存跨越了兩個node,這非常不好。最好的方式是只讓程序訪問和自己運行一樣的node,如:

$ numactl --membind 1 --cpunodebind 1 --localalloc myapplication

3、文件系統(tǒng)調(diào)優(yōu)

因為文件系統(tǒng)也是有cache的,所以,為了讓文件系統(tǒng)有最大的性能:首要的事情就是分配足夠大的內(nèi)存,這個非常關(guān)鍵,在Linux下可以使用free命令來查看 free/used/buffers/cached,理想來說,buffers和cached應(yīng)該有40%左右;然后是一個快速的硬盤控制器,SCSI會好很多;最快的是Intel SSD 固態(tài)硬盤,速度超快,但是寫次數(shù)有限。

接下來,我們就可以調(diào)優(yōu)文件系統(tǒng)配置了,對于Linux的Ext3/4來說,幾乎在所有情況下都有所幫助的一個參數(shù)是關(guān)閉文件系統(tǒng)訪問時間,在/etc/fstab下看看你的文件系統(tǒng)有沒有noatime參數(shù)(一般來說應(yīng)該有),還有一個是dealloc,它可以讓系統(tǒng)在最后時刻決定寫入文件發(fā)生時使用哪個塊,可優(yōu)化這個寫入程序。還要注意一下三種日志模式:data=journal、data=ordered和data=writeback。默認設(shè)置data=ordered提供性能和防護之間的最佳平衡。

當然,對于這些來說,ext4的默認設(shè)置基本上是最佳優(yōu)化了。

這里介紹一個Linux下的查看I/O的命令—— iotop,可以讓你看到各進程的磁盤讀寫的負載情況。

4.5數(shù)據(jù)庫調(diào)優(yōu)

1、數(shù)據(jù)庫引擎調(diào)優(yōu)

數(shù)據(jù)庫的鎖的方式。這個非常地重要。并發(fā)情況下,鎖是非常影響性能的。各種隔離級別,行鎖,表鎖,頁鎖,讀寫鎖,事務(wù)鎖,以及各種寫優(yōu)先還是讀優(yōu)先機制。性能最高的是不要鎖,所以,分庫分表,冗余數(shù)據(jù),減少一致性事務(wù)處理,可以有效地提高性能。NoSQL就是犧牲了一致性和事務(wù)處理,并冗余數(shù)據(jù),從而達到了分布式和高性能。

數(shù)據(jù)庫的存儲機制。不但要搞清楚各種類型字段是怎么存儲的,更重要的是數(shù)據(jù)庫的數(shù)據(jù)存儲方式,是怎么分區(qū)的,是怎么管理的,比如Oracle的數(shù)據(jù)文件,表空間,段,等等。了解清楚這個機制可以減輕很多的I/O負載。比如:MySQL下使用show engines;可以看到各種存儲引擎的支持。不同的存儲引擎有不同的側(cè)重點,針對不同的業(yè)務(wù)或數(shù)據(jù)庫設(shè)計會讓你有不同的性能。

數(shù)據(jù)庫的分布式策略。最簡單的就是復(fù)制或鏡像,需要了解分布式的一致性算法,或是主主同步,主從同步。通過了解這種技術(shù)的機理可以做到數(shù)據(jù)庫級別的水平擴展。

2、SQL語句優(yōu)化

關(guān)于SQL語句的優(yōu)化,首先也是要使用工具,比如:MySQL SQL Query Analyzer,Oracle SQL Performance Analyzer,或是微軟SQL Query Analyzer,基本上來說,所有的RMDB都會有這樣的工具,來讓你查看你的應(yīng)用中的SQL的性能問題。 還可以使用explain來看看SQL語句最終Execution Plan會是什么樣的。

還有一點很重要,數(shù)據(jù)庫的各種操作需要大量的內(nèi)存,所以服務(wù)器的內(nèi)存要夠,優(yōu)其應(yīng)對那些多表查詢的SQL語句,那是相當?shù)暮膬?nèi)存。

下面簡單說幾個會有性能問題的SQL:

1)全表檢索。比如:select * from user where lastname = “xxxx”,這樣的SQL語句基本上是全表查詢,線性復(fù)雜度O(n),記錄數(shù)越多,性能也越差(如:100條記錄的查找要50ms,一百萬條記錄需要5分鐘)。對于這種情況,我們可以有兩種方法提高性能:一種方法是分表,把記錄數(shù)降下來,另一種方法是建索引(為lastname建索引)。索引就像是key-value的數(shù)據(jù)結(jié)構(gòu)一樣,key就是where后面的字段,value就是物理行號,對索引的搜索復(fù)雜度是基本上是O(log(n)) ——用B-Tree實現(xiàn)索引(如:100條記錄的查找要50ms,一百萬條記錄需要100ms)。

2)索引。對于索引字段,最好不要在字段上做計算、類型轉(zhuǎn)換、函數(shù)、空值判斷、字段連接操作,這些操作都會破壞索引原本的性能。當然,索引一般都出現(xiàn)在Where或是Order by字句中,所以對Where和Order by子句中的字段最好不要進行計算操作,或是加上什么NOT之類的,或是使用什么函數(shù)。

3)多表查詢。關(guān)系型數(shù)據(jù)庫最多的操作就是多表查詢,多表查詢主要有三個關(guān)鍵字,EXISTS,IN和JOIN。基本來說,現(xiàn)代的數(shù)據(jù)引擎對SQL語句優(yōu)化得都挺好的,JOIN和IN/EXISTS在結(jié)果上有些不同,但性能基本上都差不多。有人說,EXISTS的性能要好于IN,IN的性能要好于JOIN,個人覺得,這個還要看你的數(shù)據(jù)、schema和SQL語句的復(fù)雜度,對于一般的簡單的情況來說,都差不多,所以千萬不要使用過多的嵌套,千萬不要讓你的SQL太復(fù)雜,寧可使用幾個簡單的SQL也不要使用一個巨大無比的嵌套N級的SQL。還有人說,如果兩個表的數(shù)據(jù)量差不多,Exists的性能可能會高于In,In可能會高于Join,如果這兩個表一大一小,那么子查詢中,Exists用大表,In則用小表。

4JOIN操作。有人說,Join表的順序會影響性能,只要Join的結(jié)果集是一樣,性能和join的次序無關(guān)。因為后臺的數(shù)據(jù)庫引擎會幫我們優(yōu)化的。Join有三種實現(xiàn)算法,嵌套循環(huán),排序歸并,和Hash式的Join。(MySQL只支持第一種)

嵌套循環(huán),就好像是我們常見的多重嵌套循環(huán)。注意,前面的索引說過,數(shù)據(jù)庫的索引查找算法用的是B-Tree,這是O(log(n))的算法,所以,整個算法復(fù)法度應(yīng)該是O(log(n)) * O(log(m)) 這樣的。

Hash式的Join,主要解決嵌套循環(huán)的O(log(n))的復(fù)雜,使用一個臨時的hash表來標記。

排序歸并,意思是兩個表按照查詢字段排好序,然后再合并。當然,索引字段一般是排好序的。

總之,具體要看什么樣的數(shù)據(jù),什么樣的SQL語句,你才知道用哪種方法最好。

5)部分結(jié)果集。我們知道MySQL里的Limit關(guān)鍵字,Oracle里的rownum,SQL Server里的Top都是在限制前幾條的返回結(jié)果。這給了我們數(shù)據(jù)庫引擎很多可以調(diào)優(yōu)的空間。一般來說,返回top n的記錄數(shù)據(jù)需要我們使用order by,注意在這里我們需要為order by的字段建立索引。有了被建索引的order by后,會讓我們的select語句的性能不會被記錄數(shù)的所影響。使用這個技術(shù),一般來說我們前臺會以分頁方式來顯現(xiàn)數(shù)據(jù),MySQL用的是OFFSET,SQL Server用的是FETCH NEXT,這種Fetch的方式其實并不好是線性復(fù)雜度,所以,如果我們能夠知道order by字段的第二頁的起始值,我們就可以在where語句里直接使用>=的表達式來select,這種技術(shù)叫seek,而不是fetch,seek的性能比fetch要高很多。

6)字符串。正如我前面所說的,字符串操作對性能上有非常大的噩夢,所以,能用數(shù)據(jù)的情況就用數(shù)字,比如:時間,工號,等。

7全文檢索。千萬不要用Like之類的東西來做全文檢索,如果要玩全文檢索,可以嘗試使用Sphinx

8)其它。

不要select *,而是明確指出各個字段,如果有多個表,一定要在字段名前加上表名,不要讓引擎去算。

不要用Having,因為其要遍歷所有的記錄。性能差得不能再差。

盡可能地使用UNION ALL  取代  UNION。

索引過多,insert和delete就會越慢。而update如果update多數(shù)索引,也會慢,但是如果只update一個,則只會影響一個索引表。

5性能調(diào)優(yōu)(業(yè)務(wù)和設(shè)計層面)

無論你怎么設(shè)計,你的系統(tǒng)一定要能容易地水平擴展。也就是說,你的整個數(shù)據(jù)流中,所有的環(huán)節(jié)都要能夠水平擴展。

5.1前端性能優(yōu)化技術(shù)

5.1.1前端負載均衡

通過DNS的負載均衡器(一般在路由器上根據(jù)路由的負載重定向)可以把用戶的訪問均勻地分散在多個Web服務(wù)器上。這樣可以減少Web服務(wù)器的請求負載。因為http的請求都是短作業(yè),所以,可以通過很簡單的負載均衡器來完成這一功能。最好是有CDN網(wǎng)絡(luò)讓用戶連接與其最近的服務(wù)器(CDN通常伴隨著分布式存儲)。對前端頁面也有些優(yōu)化要求:

  • 減少前端鏈接數(shù)
  • 減少網(wǎng)頁大小增加帶寬
  • 前端頁面靜態(tài)化

5.1.2優(yōu)化查詢

很多人查詢都是在查一樣的,完全可以用反向代理合并這些并發(fā)的相同的查詢。這樣的技術(shù)主要用查詢結(jié)果緩存來實現(xiàn),第一次查詢走數(shù)據(jù)庫獲得數(shù)據(jù),并把數(shù)據(jù)放到緩存,后面的查詢統(tǒng)統(tǒng)直接訪問高速緩存。為每個查詢作Hash,使用NoSQL的技術(shù)可以完成這個優(yōu)化。(這個技術(shù)也可以用做靜態(tài)頁面)

5.1.3緩存的問題

緩存可以用來緩存動態(tài)頁面,也可以用來緩存查詢的數(shù)據(jù)。緩存通常有那么幾個問題:

1)緩存的更新。也叫緩存和數(shù)據(jù)庫的同步。有這么幾種方法,一是緩存time out,讓緩存失效,重查,二是,由后端通知更新,一量后端發(fā)生變化,通知前端更新。前者實現(xiàn)起來比較簡單,但實時性不高,后者實現(xiàn)起來比較復(fù)雜 ,但實時性高。

2)緩存的換頁。內(nèi)存可能不夠,所以,需要把一些不活躍的數(shù)據(jù)換出內(nèi)存,這個和操作系統(tǒng)的內(nèi)存換頁和交換內(nèi)存很相似。FIFO、LRU、LFU都是比較經(jīng)典的換頁算法。

3)緩存的重建和持久化。緩存在內(nèi)存,系統(tǒng)總要維護,所以,緩存就會丟失,如果緩存沒了,就需要重建,如果數(shù)據(jù)量很大,緩存重建的過程會很慢,這會影響生產(chǎn)環(huán)境,所以,緩存的持久化也是需要考慮的。

諸多強大的NoSQL都很好支持了上述三大緩存的問題。

5.2后端性能優(yōu)化技術(shù)

前面討論了前端性能的優(yōu)化技術(shù),于是前端可能就不是瓶頸問題了。那么性能問題就會到后端數(shù)據(jù)上來了。下面說幾個后端常見的性能優(yōu)化技術(shù)。

5.2.1數(shù)據(jù)冗余

關(guān)于數(shù)據(jù)冗余,也就是說,把我們的數(shù)據(jù)庫的數(shù)據(jù)冗余處理,也就是減少表連接這樣的開銷比較大的操作,但這樣會犧牲數(shù)據(jù)的一致性。風(fēng)險比較大。很多人把NoSQL用做數(shù)據(jù),快是快了,因為數(shù)據(jù)冗余了,但這對數(shù)據(jù)一致性有大的風(fēng)險。這需要根據(jù)不同的業(yè)務(wù)進行分析和處理。(注意:用關(guān)系型數(shù)據(jù)庫很容易移植到NoSQL上,但是反過來從NoSQL到關(guān)系型就難了)

5.2.2數(shù)據(jù)鏡像

幾乎所有主流的數(shù)據(jù)庫都支持鏡像,也就是replication。數(shù)據(jù)庫的鏡像帶來的好處就是可以做負載均衡。把一臺數(shù)據(jù)庫的負載均分到多臺上,同時又保證了數(shù)據(jù)一致性(如Oracle的SCN)。最重要的是,這樣還可以有高可用性,一臺廢了,還有另一臺在服務(wù)。

數(shù)據(jù)鏡像的數(shù)據(jù)一致性可能是個復(fù)雜的問題,所以我們要在單條數(shù)據(jù)上進行數(shù)據(jù)分區(qū),也就是說,把一個暢銷商品的庫存均分到不同的服務(wù)器上,如,一個暢銷商品有1萬的庫存,我們可以設(shè)置10臺服務(wù)器,每臺服務(wù)器上有1000個庫存,這就好像B2C的倉庫一樣。

5.2.3數(shù)據(jù)分區(qū)

數(shù)據(jù)鏡像不能解決的一個問題就是數(shù)據(jù)表里的記錄太多,導(dǎo)致數(shù)據(jù)庫操作太慢。所以,把數(shù)據(jù)分區(qū)。數(shù)據(jù)分區(qū)有很多種做法,一般來說有下面這幾種:

1)把數(shù)據(jù)把某種邏輯來分類。比如火車訂票系統(tǒng)可按各種車型分,可以按始發(fā)站分,可以按目的地分……,反正就是把一張表拆成多張有一樣的字段但是不同種類的表,這樣,這些表就可以存在不同的機器上以達到分擔負載的目的。

2)把數(shù)據(jù)按字段分。比如把一些不經(jīng)常改的數(shù)據(jù)放在一個表里,經(jīng)常改的數(shù)據(jù)放在另外多個表里。把一張表變?yōu)?對1的關(guān)系,這樣,你可以減少表的字段個數(shù),同樣可以提升一定的性能。另外,字段多會造成一條記錄的存儲會被放到不同的頁表里,這對于讀寫性能都有問題。但這樣一來會有很多復(fù)雜的控制。

3)平均分表。因為第一種方法是并不一定平均分均,可能某個種類的數(shù)據(jù)還是很多。所以,也有采用平均分配的方式,通過主鍵ID的范圍來分表。

4)同一數(shù)據(jù)分區(qū)。也就是把同一商品的庫存值分到不同的服務(wù)器上,比如有10000個庫存,可以分到10臺服務(wù)器上,一臺上有1000個庫存。然后負載均衡。

這三種分區(qū)都有好有壞。最常用的還是第一種。數(shù)據(jù)一旦分區(qū),你就需要有一個或是多個調(diào)度來讓你的前端程序知道去哪里找數(shù)據(jù)。

5.2.4后端系統(tǒng)負載均衡

前面說了數(shù)據(jù)分區(qū),數(shù)據(jù)分區(qū)可以在一定程度上減輕負載,但是無法減輕熱銷商品的負載。這就需要使用數(shù)據(jù)鏡像來減輕負載。使用數(shù)據(jù)鏡像,必然要使用負載均衡,在后端,我們可能很難使用像路由器上的負載均衡器,因為那是均衡流量的,因為流量并不代表服務(wù)器的繁忙程度。因此,我們需要一個任務(wù)分配系統(tǒng),其還能監(jiān)控各個服務(wù)器的負載情況。

任務(wù)分配服務(wù)器有一些難點:

負載情況比較復(fù)雜。什么叫忙?是CPU高?還是磁盤I/O高?還是內(nèi)存使用高?還是并發(fā)高?還是內(nèi)存換頁率高?你可能需要全部都要考慮。這些信息要發(fā)送給那個任務(wù)分配器上,由任務(wù)分配器挑選一臺負載最輕的服務(wù)器來處理。

任務(wù)分配服務(wù)器上需要對任務(wù)隊列,不能丟任務(wù),所以還需要持久化。并且可以以批量的方式把任務(wù)分配給計算服務(wù)器。

任務(wù)分配服務(wù)器死了怎么辦?這里需要一些如Live-Standby或是failover等高可用性的技術(shù)。我們還需要注意那些持久化了的任務(wù)的隊列如何轉(zhuǎn)移到別的服務(wù)器上的問題。

有很多系統(tǒng)都用靜態(tài)的方式來分配,有的用hash,有的就簡單地輪流分析。這些都不夠好,一個是不能完美地負載均衡,另一個靜態(tài)的方法的致命缺陷是,如果有一臺計算服務(wù)器死機了,或是我們需要加入新的服務(wù)器,對于我們的分配器來說,都需要知道的。另外,還要重算哈希(一致性hash可以部分解決這個問題)。

還有一種方法是使用搶占式的方式進行負載均衡,由下游的計算服務(wù)器去任務(wù)服務(wù)器上拿任務(wù)。讓這些計算服務(wù)器自己決定自己是否要任務(wù)。這樣的好處是可以簡化系統(tǒng)的復(fù)雜度,而且還可以任意實時地減少或增加計算服務(wù)器。但是唯一不好的就是,如果有一些任務(wù)只能在某種服務(wù)器上處理,這可能會引入一些復(fù)雜度。不過總體來說,這種方法可能是比較好的負載均衡。

5.2.5異步、 throttle 和 批量處理

異步、throttle(節(jié)流閥) 和批量處理都需要對并發(fā)請求數(shù)做隊列處理的。

異步在業(yè)務(wù)上一般來說就是收集請求,然后延時處理。在技術(shù)上就是可以把各個處理程序做成并行的,也就可以水平擴展了。但是異步的技術(shù)問題大概有這些,a)被調(diào)用方的結(jié)果返回,會涉及進程線程間通信的問題。b)如果程序需要回滾,回滾會有點復(fù)雜。c)異步通常都會伴隨多線程多進程,并發(fā)的控制也相對麻煩一些。d)很多異步系統(tǒng)都用消息機制,消息的丟失和亂序也會是比較復(fù)雜的問題。

throttle 技術(shù)其實并不提升性能,這個技術(shù)主要是防止系統(tǒng)被超過自己不能處理的流量給搞垮了,這其實是個保護機制。使用throttle技術(shù)一般來說是對于一些自己無法控制的系統(tǒng),比如,和你網(wǎng)站對接的銀行系統(tǒng)。

批量處理的技術(shù),是把一堆基本相同的請求批量處理。比如,大家同時購買同一個商品,沒有必要你買一個我就寫一次數(shù)據(jù)庫,完全可以收集到一定數(shù)量的請求,一次操作。批量處理的問題是流量低,所以,批量處理的系統(tǒng)一般都會設(shè)置上兩個閥值,一個是作業(yè)量,另一個是timeout,只要有一個條件滿足,就會開始提交處理。

所以,只要是異步,一般都會有throttle機制,一般都會有隊列來排隊,有隊列,就會有持久化,而系統(tǒng)一般都會使用批量的方式來處理。

但是從業(yè)務(wù)和用戶需求上來說可能還有一些值得我們?nèi)ド钊胨伎嫉牡胤剑?)隊列的DoS攻擊。2)對列的一致性3)隊列的等待時間。

 

說明:本文部分內(nèi)容來自  – CoolShell.cn 《性能調(diào)優(yōu)攻略》、《由12306.cn談?wù)劸W(wǎng)站性能技術(shù)》,結(jié)合自己有限的性能測試經(jīng)驗進行了部分補充、節(jié)選和整理。希望對這方面感興趣的朋友更好的系統(tǒng)性了解性能測試。

 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多