原文地址:http://www./front/det-2-1.html 1系統(tǒng)性能定義性能測(cè)試,主要是通過(guò)自動(dòng)化的測(cè)試工具模擬多種正常、峰值以及異常負(fù)載條件來(lái)對(duì)系統(tǒng)的各項(xiàng)性能指標(biāo)進(jìn)行測(cè)試。系統(tǒng)性能主要包括兩個(gè)值: 吞吐量(Throughtput),即每秒鐘可以處理的請(qǐng)求數(shù),事務(wù)數(shù)。 系統(tǒng)延遲(Latency),也就是系統(tǒng)在處理一個(gè)請(qǐng)求或一個(gè)事務(wù)時(shí)的延遲。 它們兩者之間的關(guān)系: Throughput越大,Latency會(huì)越差。請(qǐng)求量過(guò)大,系統(tǒng)繁忙,響應(yīng)速度自然低。 Latency越好,能支持的Throughput就會(huì)越高。因?yàn)長(zhǎng)atency短說(shuō)明處理速度快,于是單位時(shí)間內(nèi)就可以處理更多的請(qǐng)求。 2系統(tǒng)性能測(cè)試要測(cè)試系統(tǒng)的性能,需要我們收集系統(tǒng)的Throughput和Latency這兩個(gè)值。 首先,需要定義Latency這個(gè)值,如對(duì)于網(wǎng)站首頁(yè)響應(yīng)時(shí)間必需是4秒以內(nèi)(根據(jù)不同的業(yè)務(wù)來(lái)定義) 其次,準(zhǔn)備性能測(cè)試工具,一個(gè)工具用來(lái)制造高強(qiáng)度的Throughput(通常有Loadrunner、Jmeter等),另一個(gè)工具用來(lái)測(cè)量Latency。關(guān)于如何測(cè)量Latency,你可以在代碼中測(cè)量,但是這樣會(huì)影響程序的執(zhí)行,而且只能測(cè)試到程序內(nèi)部的Latency,真正的Latency是整個(gè)系統(tǒng)都算上,包括操作系統(tǒng)和網(wǎng)絡(luò)的延時(shí),一般性能測(cè)試工具都有配套組件。 最后,開(kāi)始性能測(cè)試。不斷地提升測(cè)試環(huán)境的Throughput,然后觀察系統(tǒng)的負(fù)載情況,如果系統(tǒng)頂?shù)米。蔷陀^察Latency的值。這樣,就可以找到系統(tǒng)的最大負(fù)載,并且你可以知道系統(tǒng)的響應(yīng)延時(shí)是多少。 下面主要通過(guò)三個(gè)大的步驟來(lái)說(shuō)明性能測(cè)試實(shí)施過(guò)程: 前期準(zhǔn)備 1、確定用戶、業(yè)務(wù)、系統(tǒng)需求(目標(biāo))
主要確定用戶的業(yè)務(wù)請(qǐng)求分布等:主要業(yè)務(wù)請(qǐng)求、平均日交易量、年交易量、峰值交易量等等。
主要工作是分析系統(tǒng)的性能需求、確定合理的性能目標(biāo)。
在需求分析文檔的支持下,對(duì)軟件系統(tǒng)上的用戶業(yè)務(wù)使用情況進(jìn)行分析,提出我們所關(guān)注的性能測(cè)試需求,并告知業(yè)務(wù)人員。讓業(yè)務(wù)人員來(lái)判斷我們的性能需求是否滿足客戶的真實(shí)需求。 2、確定系統(tǒng)類(lèi)別 分清系統(tǒng)類(lèi)別是我們掌握什么樣技術(shù)的前提,掌握相應(yīng)技術(shù)做性能測(cè)試才可能成功。例如:系統(tǒng)類(lèi)別是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)成性能測(cè)試會(huì)得到不同的結(jié)果。 4、確定實(shí)際網(wǎng)絡(luò)帶寬 便于測(cè)試時(shí)對(duì)帶寬做模擬,盡可能真實(shí)的反饋帶寬使用情況。 5、確定測(cè)試服務(wù)器與測(cè)試機(jī)配置清單 了解性能測(cè)試硬件資源(包括所測(cè)服務(wù)器,測(cè)試機(jī)等),根據(jù)實(shí)際情況添加設(shè)備。 6、系統(tǒng)功能流程圖 便于測(cè)試人員分析系統(tǒng)哪些模塊易出現(xiàn)瓶頸,從而針對(duì)性做性能測(cè)試。 7、測(cè)試時(shí)間評(píng)估 根據(jù)測(cè)試時(shí)間,制定相應(yīng)的測(cè)試執(zhí)行策略。 在我的實(shí)際性能測(cè)試工作中,會(huì)把上面作為問(wèn)題列表的形式打印出來(lái),然后通過(guò)不斷溝通和分析去完善它,以便幫助我后期更好的制定性能測(cè)試策略。這樣的問(wèn)題列表如:
測(cè)試實(shí)施 1、根據(jù)前期準(zhǔn)備制定編寫(xiě)性能測(cè)試方案 瓶頸分析和性能優(yōu)化 瓶頸分析難點(diǎn)在于理解收集到的數(shù)據(jù)反饋的真是含義,所以要求測(cè)試人員具備相應(yīng)的技術(shù)知識(shí)儲(chǔ)備(包括數(shù)據(jù)庫(kù)的知識(shí)、計(jì)算機(jī)原理知識(shí)、網(wǎng)絡(luò)基礎(chǔ)、各中間件性能計(jì)量含義等),這里先僅列舉下性能測(cè)試結(jié)果分析原則:
瓶頸優(yōu)化應(yīng)該有難到易的進(jìn)行優(yōu)化,下面為推薦(應(yīng)根據(jù)公司實(shí)際情況調(diào)整): 服務(wù)器硬件瓶頸->網(wǎng)絡(luò)瓶頸->服務(wù)器操作系統(tǒng)瓶頸->中間件瓶頸->應(yīng)用瓶頸 3定位性能瓶頸3.1查看操作系統(tǒng)負(fù)載系統(tǒng)有問(wèn)題首要需要看的是操作系統(tǒng)報(bào)告。查看操作系統(tǒng)的CPU利用率,內(nèi)存使用率,操作系統(tǒng)的IO,還有網(wǎng)絡(luò)的IO,網(wǎng)絡(luò)鏈接數(shù)等。
通過(guò)了解操作系統(tǒng)的性能,我們才知道性能的問(wèn)題,比如:帶寬不夠,內(nèi)存不夠,TCP緩沖區(qū)不夠,等等,很多時(shí)候,不需要調(diào)整程序的,只需要調(diào)整一下硬件或操作系統(tǒng)的配置就可以了。 3.2使用profiler測(cè)試程序瓶頸使用某個(gè)Profiler來(lái)查看一下我們程序的運(yùn)行性能。如:Java的JProfiler。使用Profiler工具,可以讓你查看程序中各個(gè)模塊函數(shù)甚至指令的很多東西,如:運(yùn)行的時(shí)間 ,調(diào)用的次數(shù),CPU的利用率,等等。 我們重點(diǎn)觀察運(yùn)行時(shí)間最多,調(diào)用次數(shù)最多的那些函數(shù)和指令。這里注意一下,對(duì)于調(diào)用次數(shù)多但是時(shí)間很短的函數(shù),你可能只需要輕微優(yōu)化一下,你的性能就上去了。 因?yàn)镻rofiler會(huì)讓你的程序運(yùn)行的性能變低對(duì)此,一般有兩個(gè)方法來(lái)定位系統(tǒng)瓶頸: 1)在你的代碼中自己做統(tǒng)計(jì),使用微秒級(jí)的計(jì)時(shí)器和函數(shù)調(diào)用計(jì)算器,每隔10秒把統(tǒng)計(jì)log到文件中。 2)分段注釋你的代碼塊,讓一些函數(shù)空轉(zhuǎn),做Hard Code的Mock,然后再測(cè)試一下系統(tǒng)的Throughput和Latency是否有質(zhì)的變化,如果有,那么被注釋的函數(shù)就是性能瓶頸,再在這個(gè)函數(shù)體內(nèi)注釋代碼,直到找到最耗性能的語(yǔ)句。 查看匯編代碼經(jīng)常會(huì)給你一些意想不到的東西讓你知道為什么程序的性能是那樣。 對(duì)于性能測(cè)試,不同的Throughput會(huì)出現(xiàn)不同的測(cè)試結(jié)果,不同的測(cè)試數(shù)據(jù)也會(huì)有不同的測(cè)試結(jié)果。所以,用于性能測(cè)試的數(shù)據(jù)非常重要,性能測(cè)試中,我們需要測(cè)試觀察不同Throughput的結(jié)果。 4性能調(diào)優(yōu)(代碼技術(shù)細(xì)節(jié)層面)一般來(lái)說(shuō),性能優(yōu)化也就是下面的幾個(gè)策略:
總之,根據(jù)2:8原則來(lái)說(shuō),20%的代碼耗了你80%的性能,找到那20%的代碼,你就可以優(yōu)化那80%的性能。 下面為一些最有價(jià)值的性能調(diào)優(yōu)的的方法,供參考。 4.1算法調(diào)優(yōu)算法非常重要,好的算法會(huì)有更好的性能。下面為幾個(gè)算法調(diào)優(yōu)例子:
4.2代碼調(diào)優(yōu)代碼上的調(diào)優(yōu)大致有下面這幾點(diǎn):
4.3網(wǎng)絡(luò)調(diào)優(yōu)下面只講一些概念上的東西。 1、TCP調(diào)優(yōu) TCP鏈接是有很多開(kāi)銷(xiāo)的,一個(gè)是會(huì)占用文件描述符,另一個(gè)是會(huì)開(kāi)緩存,一般來(lái)說(shuō)一個(gè)系統(tǒng)可以支持的TCP鏈接數(shù)是有限的,我們需要清楚地認(rèn)識(shí)到TCP鏈接對(duì)系統(tǒng)的開(kāi)銷(xiāo)是很大的。正是因?yàn)門(mén)CP是耗資源的,所以,很多攻擊都是讓你系統(tǒng)上出現(xiàn)大量的TCP鏈接,把你的系統(tǒng)資源耗盡。比如著名的SYNC Flood攻擊。 所以,我們要注意配置KeepAlive參數(shù),這個(gè)參數(shù)的意思是定義一個(gè)時(shí)間,如果鏈接上沒(méi)有數(shù)據(jù)傳輸,系統(tǒng)會(huì)在這個(gè)時(shí)間發(fā)一個(gè)包,如果沒(méi)有收到回應(yīng),那么TCP就認(rèn)為鏈接斷了,然后就會(huì)把鏈接關(guān)閉,這樣可以回收系統(tǒng)資源開(kāi)銷(xiāo)。(注:HTTP層上也有KeepAlive參數(shù))對(duì)于像HTTP這樣的短鏈接,設(shè)置一個(gè)1-2分鐘的keepalive非常重要。這可以在一定程度上防止DoS攻擊。有下面幾個(gè)參數(shù)(下面這些參數(shù)的值僅供參考): net.ipv4.tcp_keepalive_probes = 5 net.ipv4.tcp_keepalive_intvl = 20 net.ipv4.tcp_fin_timeout = 30 對(duì)于TCP的TIME_WAIT這個(gè)狀態(tài),主動(dòng)關(guān)閉的一方進(jìn)入TIME_WAIT狀態(tài),TIME_WAIT狀態(tài)將持續(xù)2個(gè)MSL(Max Segment Lifetime),默認(rèn)為4分鐘,TIME_WAIT狀態(tài)下的資源不能回收。有大量的TIME_WAIT鏈接的情況一般是在HTTP服務(wù)器上。對(duì)此,有兩個(gè)參數(shù)需要注意, net.ipv4.tcp_tw_reuse=1 net.ipv4.tcp_tw_recycle=1 前者表示重用TIME_WAIT,后者表示回收TIME_WAIT的資源。 TCP還有一個(gè)重要的概念叫RWIN(TCP Receive Window Size),這個(gè)東西的意思是,我一個(gè)TCP鏈接在沒(méi)有向Sender發(fā)出ack時(shí)可以接收到的最大的數(shù)據(jù)包。為什么這個(gè)很重要?因?yàn)槿绻鸖ender沒(méi)有收到Receiver發(fā)過(guò)來(lái)ack,Sender就會(huì)停止發(fā)送數(shù)據(jù)并會(huì)等一段時(shí)間,如果超時(shí),那么就會(huì)重傳。這就是為什么TCP鏈接是可靠鏈接的原因。重傳還不是最嚴(yán)重的,如果有丟包發(fā)生的話,TCP的帶寬使用率會(huì)馬上受到影響(會(huì)盲目減半),再丟包,再減半,然后如果不丟包了,就逐步恢復(fù)。相關(guān)參數(shù)如下: net.core.wmem_default = 8388608 net.core.rmem_default = 8388608 net.core.rmem_max = 16777216 net.core.wmem_max = 16777216 一般來(lái)說(shuō),理論上的RWIN應(yīng)該設(shè)置成:吞吐量 * 回路時(shí)間。Sender端的buffer應(yīng)該和RWIN有一樣的大小,因?yàn)镾ender端發(fā)送完數(shù)據(jù)后要等Receiver端確認(rèn),如果網(wǎng)絡(luò)延時(shí)很大,buffer過(guò)小了,確認(rèn)的次數(shù)就會(huì)多,于是性能就不高,對(duì)網(wǎng)絡(luò)的利用率也就不高了。也就是說(shuō),對(duì)于延遲大的網(wǎng)絡(luò),我們需要大的buffer,這樣可以少一點(diǎn)ack,多一些數(shù)據(jù),對(duì)于響應(yīng)快一點(diǎn)的網(wǎng)絡(luò),可以少一些buffer。因?yàn)椋绻衼G包(沒(méi)有收到ack),buffer過(guò)大可能會(huì)有問(wèn)題,因?yàn)檫@會(huì)讓TCP重傳所有的數(shù)據(jù),反而影響網(wǎng)絡(luò)性能。所以,高性能的網(wǎng)絡(luò)重要的是要讓網(wǎng)絡(luò)丟包率非常非常地小(基本上是用在LAN里),如果網(wǎng)絡(luò)基本是可信的,這樣用大一點(diǎn)的buffer會(huì)有更好的網(wǎng)絡(luò)傳輸性能(來(lái)來(lái)回回太多太影響性能了)。 2、UDP調(diào)優(yōu) 說(shuō)到UDP的調(diào)優(yōu), 就得說(shuō)MTU——最大傳輸單元(其實(shí)這對(duì)TCP也一樣,因?yàn)檫@是鏈路層上的東西)。所謂最大傳輸單元,你可以想像成是公路上的公交車(chē),假設(shè)一個(gè)公交車(chē)可以最多坐70人,帶寬就像是公路的車(chē)道數(shù)一樣,如果一條路上最多可以容下100輛公交車(chē),那意味著我最多可以運(yùn)送7000人,但是如果公交車(chē)坐不滿,比如平均每輛車(chē)只有20人,那么我只運(yùn)送了2000人,于是我公路資源(帶寬資源)就被浪費(fèi)了。 所以,我們對(duì)于一個(gè)UDP的包,我們要盡量地讓它大到MTU的最大尺寸再往網(wǎng)絡(luò)上傳,這樣可以最大化帶寬利用率。對(duì)于這個(gè)MTU,以太網(wǎng)是1500字節(jié),光纖是4352字節(jié),802.11無(wú)線網(wǎng)是7981。但是,當(dāng)我們用TCP/UDP發(fā)包的時(shí)候,我們的有效負(fù)載Payload要低于這個(gè)值,因?yàn)镮P協(xié)議會(huì)加上20個(gè)字節(jié),UDP會(huì)加上8個(gè)字節(jié)(TCP加的更多),所以,一般來(lái)說(shuō),你的一個(gè)UDP包的最大應(yīng)該是1500-8-20=1472,這是你的數(shù)據(jù)的大小。當(dāng)然,如果你用光纖的話, 這個(gè)值就可以更大一些。(順便說(shuō)一下,對(duì)于某些千光以態(tài)網(wǎng)網(wǎng)卡來(lái)說(shuō),在網(wǎng)卡上,網(wǎng)卡硬件如果發(fā)現(xiàn)你的包的大小超過(guò)了MTU,其會(huì)幫你做fragment,到了目標(biāo)端又會(huì)幫你做重組,這就不需要你在程序中處理了) 用Socket編程的時(shí)候,你可以使用setsockopt() 設(shè)置 SO_SNDBUF/SO_RCVBUF 的大小,TTL和KeepAlive這些關(guān)鍵的設(shè)置,當(dāng)然,還有很多,具體可以查看一下Socket的手冊(cè)。 最后UDP還有一個(gè)最大的好處是multi-cast多播,這個(gè)技術(shù)對(duì)于你需要在內(nèi)網(wǎng)里通知多臺(tái)結(jié)點(diǎn)時(shí)非常方便和高效。而且,多播這種技術(shù)對(duì)于機(jī)會(huì)的水平擴(kuò)展(需要增加機(jī)器來(lái)偵聽(tīng)多播信息)也很有利。 3、網(wǎng)卡調(diào)優(yōu) 對(duì)于網(wǎng)卡,也是可以調(diào)優(yōu)的,這對(duì)于千兆以及網(wǎng)網(wǎng)卡非常必要,在Linux下,我們可以用ifconfig查看網(wǎng)上的統(tǒng)計(jì)信息,如果我們看到overrun上有數(shù)據(jù),我們就可能需要調(diào)整一下txqueuelen的尺寸(一般默認(rèn)為1000),我們可以調(diào)大一些,如:ifconfig eth0 txqueuelen 5000。Linux下還有一個(gè)命令叫:ethtool可以用于設(shè)置網(wǎng)卡的緩沖區(qū)大小。在Windows下,我們可以在網(wǎng)卡適配器中的高級(jí)選項(xiàng)卡中調(diào)整相關(guān)的參數(shù)(如:Receive Buffers, Transmit Buffer等,不同的網(wǎng)卡有不同的參數(shù))。把Buffer調(diào)大對(duì)于需要大數(shù)據(jù)量的網(wǎng)絡(luò)傳輸非常有效。 4、其它網(wǎng)絡(luò)性能 關(guān)于多路復(fù)用技術(shù),也就是用一個(gè)線程來(lái)管理所有的TCP鏈接,有三個(gè)系統(tǒng)調(diào)用要重點(diǎn)注意:一個(gè)是select,這個(gè)系統(tǒng)調(diào)用只支持上限1024個(gè)鏈接,第二個(gè)是poll,其可以突破1024的限制,但是select和poll本質(zhì)上是使用的輪詢機(jī)制,輪詢機(jī)制在鏈接多的時(shí)候性能很差,因主是O(n)的算法,所以,epoll出現(xiàn)了,epoll是操作系統(tǒng)內(nèi)核支持的,僅當(dāng)在鏈接活躍時(shí),操作系統(tǒng)才會(huì)callback,這是由操作系統(tǒng)通知觸發(fā)的,但其只有Linux Kernel 2.6以后才支持(準(zhǔn)確說(shuō)是2.5.44中引入的),當(dāng)然,如果所有的鏈接都是活躍的,過(guò)多的使用epoll_ctl可能會(huì)比輪詢的方式還影響性能,不過(guò)影響的不大。 另外,關(guān)于一些和DNS Lookup的系統(tǒng)調(diào)用要小心,比如:gethostbyaddr/gethostbyname,這個(gè)函數(shù)可能會(huì)相當(dāng)?shù)馁M(fèi)時(shí),因?yàn)槠湟骄W(wǎng)絡(luò)上去找域名,因?yàn)镈NS的遞歸查詢,會(huì)導(dǎo)致嚴(yán)重超時(shí),而又不能通過(guò)設(shè)置什么參數(shù)來(lái)設(shè)置time out,對(duì)此你可以通過(guò)配置hosts文件來(lái)加快速度,或是自己在內(nèi)存中管理對(duì)應(yīng)表,在程序啟動(dòng)時(shí)查好,而不要在運(yùn)行時(shí)每次都查。另外,在多線程下面,gethostbyname會(huì)一個(gè)更嚴(yán)重的問(wèn)題,就是如果有一個(gè)線程的gethostbyname發(fā)生阻塞,其它線程都會(huì)在gethostbyname處發(fā)生阻塞,這個(gè)比較變態(tài),要小心。(可以試試GNU的gethostbyname_r(),這個(gè)的性能要好一些) 這種到網(wǎng)上找信息的東西很多,比如,如果你的Linux使用了NIS,或是NFS,某些用戶或文件相關(guān)的系統(tǒng)調(diào)用就很慢,所以要小心。 4.4系統(tǒng)調(diào)優(yōu)1、I/O模型 前面說(shuō)到過(guò)select/poll/epoll這三個(gè)系統(tǒng)調(diào)用,我們都知道,Unix/Linux下把所有的設(shè)備都當(dāng)成文件來(lái)進(jìn)行I/O,所以,那三個(gè)操作更應(yīng)該算是I/O相關(guān)的系統(tǒng)調(diào)用。說(shuō)到 I/O模型,這對(duì)于我們的I/O性能相當(dāng)重要,我們知道,Unix/Linux經(jīng)典的I/O方式是: 第一種,同步阻塞式I/O。 第二種,同步無(wú)阻塞方式。其通過(guò)fctnl設(shè)置 O_NONBLOCK 來(lái)完成。 第三種,對(duì)于select/poll/epoll這三個(gè)是I/O不阻塞,但是在事件上阻塞,算是:I/O異步,事件同步的調(diào)用。 第四種,AIO方式。這種I/O 模型是一種處理與 I/O 并行的模型。I/O請(qǐng)求會(huì)立即返回,說(shuō)明請(qǐng)求已經(jīng)成功發(fā)起了。在后臺(tái)完成I/O操作時(shí),向應(yīng)用程序發(fā)起通知,通知有兩種方式:一種是產(chǎn)生一個(gè)信號(hào),另一種是執(zhí)行一個(gè)基于線程的回調(diào)函數(shù)來(lái)完成這次 I/O 處理過(guò)程。 第四種因?yàn)闆](méi)有任何的阻塞,無(wú)論是I/O上,還是事件通知上,所以,其可以讓你充分地利用CPU,比起第二種同步無(wú)阻塞好處就是,第二種要你一遍一遍地去輪詢。Nginx之所以高效,是其使用了epoll和AIO的方式來(lái)進(jìn)行I/O的。 再說(shuō)一下Windows下的I/O模型: a)一個(gè)是WriteFile系統(tǒng)調(diào)用,這個(gè)系統(tǒng)調(diào)用可以是同步阻塞的,也可以是同步無(wú)阻塞的,關(guān)于看文件是不是以O(shè)verlapped打開(kāi)的。關(guān)于同步無(wú)阻塞,需要設(shè)置其最后一個(gè)參數(shù)Overlapped,微軟叫Overlapped I/O,你需要WaitForSingleObject才能知道有沒(méi)有寫(xiě)完成。這個(gè)系統(tǒng)調(diào)用的性能可想而知。 b)另一個(gè)叫WriteFileEx的系統(tǒng)調(diào)用,其可以實(shí)現(xiàn)異步I/O,并可以讓你傳入一個(gè)callback函數(shù),等I/O結(jié)束后回調(diào)之,但是這個(gè)回調(diào)的過(guò)程Windows是把callback函數(shù)放到了APC(Asynchronous Procedure Calls)的隊(duì)列中,然后,只用當(dāng)應(yīng)用程序當(dāng)前線程成為可被通知狀態(tài)(Alterable)時(shí),才會(huì)被回調(diào)。只有當(dāng)你的線程使用了這幾個(gè)函數(shù)時(shí)WaitForSingleObjectEx, WaitForMultipleObjectsEx, MsgWaitForMultipleObjectsEx, SignalObjectAndWait 和 SleepEx,線程才會(huì)成為Alterable狀態(tài)??梢?jiàn),這個(gè)模型,還是有wait,所以性能也不高。 c)然后是IOCP – IO Completion Port,IOCP會(huì)把I/O的結(jié)果放在一個(gè)隊(duì)列中,但是,偵聽(tīng)這個(gè)隊(duì)列的不是主線程,而是專(zhuān)門(mén)來(lái)干這個(gè)事的一個(gè)或多個(gè)線程去干(老的平臺(tái)要你自己創(chuàng)建線程,新的平臺(tái)是你可以創(chuàng)建一個(gè)線程池)。IOCP是一個(gè)線程池模型。這個(gè)和Linux下的AIO模型比較相似,但是實(shí)現(xiàn)方式和使用方式完全不一樣。 當(dāng)然,真正提高I/O性能方式是把和外設(shè)的I/O的次數(shù)降到最低,最好沒(méi)有,所以,對(duì)于讀來(lái)說(shuō),內(nèi)存cache通常可以從質(zhì)上提升性能,因?yàn)閮?nèi)存比外設(shè)快太多了。對(duì)于寫(xiě)來(lái)說(shuō),cache住要寫(xiě)的數(shù)據(jù),少寫(xiě)幾次,但是cache帶來(lái)的問(wèn)題就是實(shí)時(shí)性的問(wèn)題,也就是latency會(huì)變大,我們需要在寫(xiě)的次數(shù)上和響應(yīng)上做權(quán)衡。 2、多核CPU調(diào)優(yōu) 關(guān)于CPU的多核技術(shù), CPU0是很關(guān)鍵的,如果0號(hào)CPU被用得過(guò)多時(shí),別的CPU性能也會(huì)下降,因?yàn)镃PU0作用是有調(diào)整功能的,所以,我們不能任由操作系統(tǒng)負(fù)載均衡,因?yàn)槲覀冏约焊私庾约旱某绦?,所以,我們可以手?dòng)的為其分配CPU核,而不會(huì)過(guò)多地占用CPU0,或是讓我們關(guān)鍵進(jìn)程和一堆別的進(jìn)程擠在一起。 對(duì)于Windows來(lái)說(shuō),我們可以通過(guò)“任務(wù)管理器”中的“進(jìn)程”而中右鍵菜單中的“設(shè)置相關(guān)性……”(Set Affinity…)來(lái)設(shè)置并限制這個(gè)進(jìn)程能被運(yùn)行在哪些核上。 對(duì)于Linux來(lái)說(shuō),可以使用taskset命令來(lái)設(shè)置(你可以通過(guò)安裝schedutils來(lái)安裝這個(gè)命令:apt-get install schedutils) 多核CPU還有一個(gè)技術(shù)叫NUMA技術(shù)(Non-Uniform Memory Access)。傳統(tǒng)的多核運(yùn)算是使用SMP(Symmetric Multi-Processor )模式,多個(gè)處理器共享一個(gè)集中的存儲(chǔ)器和I/O總線。于是就會(huì)出現(xiàn)一致存儲(chǔ)器訪問(wèn)的問(wèn)題,一致性通常意味著性能問(wèn)題。NUMA模式下,處理器被劃分成多個(gè)node, 每個(gè)node有自己的本地存儲(chǔ)器空間。在Linux下,對(duì)NUMA調(diào)優(yōu)的命令是:numactl 。如下面的命令:(指定命令“myprogram arg1 arg2”運(yùn)行在node 0 上,其內(nèi)存分配在node 0 和 1上) numactl --cpubind=0 --membind=0,1 myprogram arg1 arg2 當(dāng)然,上面這個(gè)命令并不好,因?yàn)閮?nèi)存跨越了兩個(gè)node,這非常不好。最好的方式是只讓程序訪問(wèn)和自己運(yùn)行一樣的node,如: $ numactl --membind 1 --cpunodebind 1 --localalloc myapplication 3、文件系統(tǒng)調(diào)優(yōu) 因?yàn)槲募到y(tǒng)也是有cache的,所以,為了讓文件系統(tǒng)有最大的性能:首要的事情就是分配足夠大的內(nèi)存,這個(gè)非常關(guān)鍵,在Linux下可以使用free命令來(lái)查看 free/used/buffers/cached,理想來(lái)說(shuō),buffers和cached應(yīng)該有40%左右;然后是一個(gè)快速的硬盤(pán)控制器,SCSI會(huì)好很多;最快的是Intel SSD 固態(tài)硬盤(pán),速度超快,但是寫(xiě)次數(shù)有限。 接下來(lái),我們就可以調(diào)優(yōu)文件系統(tǒng)配置了,對(duì)于Linux的Ext3/4來(lái)說(shuō),幾乎在所有情況下都有所幫助的一個(gè)參數(shù)是關(guān)閉文件系統(tǒng)訪問(wèn)時(shí)間,在/etc/fstab下看看你的文件系統(tǒng)有沒(méi)有noatime參數(shù)(一般來(lái)說(shuō)應(yīng)該有),還有一個(gè)是dealloc,它可以讓系統(tǒng)在最后時(shí)刻決定寫(xiě)入文件發(fā)生時(shí)使用哪個(gè)塊,可優(yōu)化這個(gè)寫(xiě)入程序。還要注意一下三種日志模式:data=journal、data=ordered和data=writeback。默認(rèn)設(shè)置data=ordered提供性能和防護(hù)之間的最佳平衡。 當(dāng)然,對(duì)于這些來(lái)說(shuō),ext4的默認(rèn)設(shè)置基本上是最佳優(yōu)化了。 這里介紹一個(gè)Linux下的查看I/O的命令—— iotop,可以讓你看到各進(jìn)程的磁盤(pán)讀寫(xiě)的負(fù)載情況。 4.5數(shù)據(jù)庫(kù)調(diào)優(yōu)1、數(shù)據(jù)庫(kù)引擎調(diào)優(yōu) 數(shù)據(jù)庫(kù)的鎖的方式。這個(gè)非常地重要。并發(fā)情況下,鎖是非常影響性能的。各種隔離級(jí)別,行鎖,表鎖,頁(yè)鎖,讀寫(xiě)鎖,事務(wù)鎖,以及各種寫(xiě)優(yōu)先還是讀優(yōu)先機(jī)制。性能最高的是不要鎖,所以,分庫(kù)分表,冗余數(shù)據(jù),減少一致性事務(wù)處理,可以有效地提高性能。NoSQL就是犧牲了一致性和事務(wù)處理,并冗余數(shù)據(jù),從而達(dá)到了分布式和高性能。 數(shù)據(jù)庫(kù)的存儲(chǔ)機(jī)制。不但要搞清楚各種類(lèi)型字段是怎么存儲(chǔ)的,更重要的是數(shù)據(jù)庫(kù)的數(shù)據(jù)存儲(chǔ)方式,是怎么分區(qū)的,是怎么管理的,比如Oracle的數(shù)據(jù)文件,表空間,段,等等。了解清楚這個(gè)機(jī)制可以減輕很多的I/O負(fù)載。比如:MySQL下使用show engines;可以看到各種存儲(chǔ)引擎的支持。不同的存儲(chǔ)引擎有不同的側(cè)重點(diǎn),針對(duì)不同的業(yè)務(wù)或數(shù)據(jù)庫(kù)設(shè)計(jì)會(huì)讓你有不同的性能。 數(shù)據(jù)庫(kù)的分布式策略。最簡(jiǎn)單的就是復(fù)制或鏡像,需要了解分布式的一致性算法,或是主主同步,主從同步。通過(guò)了解這種技術(shù)的機(jī)理可以做到數(shù)據(jù)庫(kù)級(jí)別的水平擴(kuò)展。 2、SQL語(yǔ)句優(yōu)化 關(guān)于SQL語(yǔ)句的優(yōu)化,首先也是要使用工具,比如:MySQL SQL Query Analyzer,Oracle SQL Performance Analyzer,或是微軟SQL Query Analyzer,基本上來(lái)說(shuō),所有的RMDB都會(huì)有這樣的工具,來(lái)讓你查看你的應(yīng)用中的SQL的性能問(wèn)題。 還可以使用explain來(lái)看看SQL語(yǔ)句最終Execution Plan會(huì)是什么樣的。 還有一點(diǎn)很重要,數(shù)據(jù)庫(kù)的各種操作需要大量的內(nèi)存,所以服務(wù)器的內(nèi)存要夠,優(yōu)其應(yīng)對(duì)那些多表查詢的SQL語(yǔ)句,那是相當(dāng)?shù)暮膬?nèi)存。 下面簡(jiǎn)單說(shuō)幾個(gè)會(huì)有性能問(wèn)題的SQL: 1)全表檢索。比如:select * from user where lastname = “xxxx”,這樣的SQL語(yǔ)句基本上是全表查詢,線性復(fù)雜度O(n),記錄數(shù)越多,性能也越差(如:100條記錄的查找要50ms,一百萬(wàn)條記錄需要5分鐘)。對(duì)于這種情況,我們可以有兩種方法提高性能:一種方法是分表,把記錄數(shù)降下來(lái),另一種方法是建索引(為lastname建索引)。索引就像是key-value的數(shù)據(jù)結(jié)構(gòu)一樣,key就是where后面的字段,value就是物理行號(hào),對(duì)索引的搜索復(fù)雜度是基本上是O(log(n)) ——用B-Tree實(shí)現(xiàn)索引(如:100條記錄的查找要50ms,一百萬(wàn)條記錄需要100ms)。 2)索引。對(duì)于索引字段,最好不要在字段上做計(jì)算、類(lèi)型轉(zhuǎn)換、函數(shù)、空值判斷、字段連接操作,這些操作都會(huì)破壞索引原本的性能。當(dāng)然,索引一般都出現(xiàn)在Where或是Order by字句中,所以對(duì)Where和Order by子句中的字段最好不要進(jìn)行計(jì)算操作,或是加上什么NOT之類(lèi)的,或是使用什么函數(shù)。 3)多表查詢。關(guān)系型數(shù)據(jù)庫(kù)最多的操作就是多表查詢,多表查詢主要有三個(gè)關(guān)鍵字,EXISTS,IN和JOIN。基本來(lái)說(shuō),現(xiàn)代的數(shù)據(jù)引擎對(duì)SQL語(yǔ)句優(yōu)化得都挺好的,JOIN和IN/EXISTS在結(jié)果上有些不同,但性能基本上都差不多。有人說(shuō),EXISTS的性能要好于IN,IN的性能要好于JOIN,個(gè)人覺(jué)得,這個(gè)還要看你的數(shù)據(jù)、schema和SQL語(yǔ)句的復(fù)雜度,對(duì)于一般的簡(jiǎn)單的情況來(lái)說(shuō),都差不多,所以千萬(wàn)不要使用過(guò)多的嵌套,千萬(wàn)不要讓你的SQL太復(fù)雜,寧可使用幾個(gè)簡(jiǎn)單的SQL也不要使用一個(gè)巨大無(wú)比的嵌套N級(jí)的SQL。還有人說(shuō),如果兩個(gè)表的數(shù)據(jù)量差不多,Exists的性能可能會(huì)高于In,In可能會(huì)高于Join,如果這兩個(gè)表一大一小,那么子查詢中,Exists用大表,In則用小表。 4)JOIN操作。有人說(shuō),Join表的順序會(huì)影響性能,只要Join的結(jié)果集是一樣,性能和join的次序無(wú)關(guān)。因?yàn)楹笈_(tái)的數(shù)據(jù)庫(kù)引擎會(huì)幫我們優(yōu)化的。Join有三種實(shí)現(xiàn)算法,嵌套循環(huán),排序歸并,和Hash式的Join。(MySQL只支持第一種) 嵌套循環(huán),就好像是我們常見(jiàn)的多重嵌套循環(huán)。注意,前面的索引說(shuō)過(guò),數(shù)據(jù)庫(kù)的索引查找算法用的是B-Tree,這是O(log(n))的算法,所以,整個(gè)算法復(fù)法度應(yīng)該是O(log(n)) * O(log(m)) 這樣的。 Hash式的Join,主要解決嵌套循環(huán)的O(log(n))的復(fù)雜,使用一個(gè)臨時(shí)的hash表來(lái)標(biāo)記。 排序歸并,意思是兩個(gè)表按照查詢字段排好序,然后再合并。當(dāng)然,索引字段一般是排好序的。 總之,具體要看什么樣的數(shù)據(jù),什么樣的SQL語(yǔ)句,你才知道用哪種方法最好。 5)部分結(jié)果集。我們知道MySQL里的Limit關(guān)鍵字,Oracle里的rownum,SQL Server里的Top都是在限制前幾條的返回結(jié)果。這給了我們數(shù)據(jù)庫(kù)引擎很多可以調(diào)優(yōu)的空間。一般來(lái)說(shuō),返回top n的記錄數(shù)據(jù)需要我們使用order by,注意在這里我們需要為order by的字段建立索引。有了被建索引的order by后,會(huì)讓我們的select語(yǔ)句的性能不會(huì)被記錄數(shù)的所影響。使用這個(gè)技術(shù),一般來(lái)說(shuō)我們前臺(tái)會(huì)以分頁(yè)方式來(lái)顯現(xiàn)數(shù)據(jù),MySQL用的是OFFSET,SQL Server用的是FETCH NEXT,這種Fetch的方式其實(shí)并不好是線性復(fù)雜度,所以,如果我們能夠知道order by字段的第二頁(yè)的起始值,我們就可以在where語(yǔ)句里直接使用>=的表達(dá)式來(lái)select,這種技術(shù)叫seek,而不是fetch,seek的性能比f(wàn)etch要高很多。 6)字符串。正如我前面所說(shuō)的,字符串操作對(duì)性能上有非常大的噩夢(mèng),所以,能用數(shù)據(jù)的情況就用數(shù)字,比如:時(shí)間,工號(hào),等。 7)全文檢索。千萬(wàn)不要用Like之類(lèi)的東西來(lái)做全文檢索,如果要玩全文檢索,可以嘗試使用Sphinx。 8)其它。 不要select *,而是明確指出各個(gè)字段,如果有多個(gè)表,一定要在字段名前加上表名,不要讓引擎去算。 不要用Having,因?yàn)槠湟闅v所有的記錄。性能差得不能再差。 盡可能地使用UNION ALL 取代 UNION。 索引過(guò)多,insert和delete就會(huì)越慢。而update如果update多數(shù)索引,也會(huì)慢,但是如果只update一個(gè),則只會(huì)影響一個(gè)索引表。 5性能調(diào)優(yōu)(業(yè)務(wù)和設(shè)計(jì)層面)無(wú)論你怎么設(shè)計(jì),你的系統(tǒng)一定要能容易地水平擴(kuò)展。也就是說(shuō),你的整個(gè)數(shù)據(jù)流中,所有的環(huán)節(jié)都要能夠水平擴(kuò)展。 5.1前端性能優(yōu)化技術(shù)5.1.1前端負(fù)載均衡通過(guò)DNS的負(fù)載均衡器(一般在路由器上根據(jù)路由的負(fù)載重定向)可以把用戶的訪問(wèn)均勻地分散在多個(gè)Web服務(wù)器上。這樣可以減少Web服務(wù)器的請(qǐng)求負(fù)載。因?yàn)閔ttp的請(qǐng)求都是短作業(yè),所以,可以通過(guò)很簡(jiǎn)單的負(fù)載均衡器來(lái)完成這一功能。最好是有CDN網(wǎng)絡(luò)讓用戶連接與其最近的服務(wù)器(CDN通常伴隨著分布式存儲(chǔ))。對(duì)前端頁(yè)面也有些優(yōu)化要求:
5.1.2優(yōu)化查詢很多人查詢都是在查一樣的,完全可以用反向代理合并這些并發(fā)的相同的查詢。這樣的技術(shù)主要用查詢結(jié)果緩存來(lái)實(shí)現(xiàn),第一次查詢走數(shù)據(jù)庫(kù)獲得數(shù)據(jù),并把數(shù)據(jù)放到緩存,后面的查詢統(tǒng)統(tǒng)直接訪問(wèn)高速緩存。為每個(gè)查詢作Hash,使用NoSQL的技術(shù)可以完成這個(gè)優(yōu)化。(這個(gè)技術(shù)也可以用做靜態(tài)頁(yè)面) 5.1.3緩存的問(wèn)題緩存可以用來(lái)緩存動(dòng)態(tài)頁(yè)面,也可以用來(lái)緩存查詢的數(shù)據(jù)。緩存通常有那么幾個(gè)問(wèn)題: 1)緩存的更新。也叫緩存和數(shù)據(jù)庫(kù)的同步。有這么幾種方法,一是緩存time out,讓緩存失效,重查,二是,由后端通知更新,一量后端發(fā)生變化,通知前端更新。前者實(shí)現(xiàn)起來(lái)比較簡(jiǎn)單,但實(shí)時(shí)性不高,后者實(shí)現(xiàn)起來(lái)比較復(fù)雜 ,但實(shí)時(shí)性高。 2)緩存的換頁(yè)。內(nèi)存可能不夠,所以,需要把一些不活躍的數(shù)據(jù)換出內(nèi)存,這個(gè)和操作系統(tǒng)的內(nèi)存換頁(yè)和交換內(nèi)存很相似。FIFO、LRU、LFU都是比較經(jīng)典的換頁(yè)算法。 3)緩存的重建和持久化。緩存在內(nèi)存,系統(tǒng)總要維護(hù),所以,緩存就會(huì)丟失,如果緩存沒(méi)了,就需要重建,如果數(shù)據(jù)量很大,緩存重建的過(guò)程會(huì)很慢,這會(huì)影響生產(chǎn)環(huán)境,所以,緩存的持久化也是需要考慮的。 諸多強(qiáng)大的NoSQL都很好支持了上述三大緩存的問(wèn)題。 5.2后端性能優(yōu)化技術(shù)前面討論了前端性能的優(yōu)化技術(shù),于是前端可能就不是瓶頸問(wèn)題了。那么性能問(wèn)題就會(huì)到后端數(shù)據(jù)上來(lái)了。下面說(shuō)幾個(gè)后端常見(jiàn)的性能優(yōu)化技術(shù)。 5.2.1數(shù)據(jù)冗余關(guān)于數(shù)據(jù)冗余,也就是說(shuō),把我們的數(shù)據(jù)庫(kù)的數(shù)據(jù)冗余處理,也就是減少表連接這樣的開(kāi)銷(xiāo)比較大的操作,但這樣會(huì)犧牲數(shù)據(jù)的一致性。風(fēng)險(xiǎn)比較大。很多人把NoSQL用做數(shù)據(jù),快是快了,因?yàn)閿?shù)據(jù)冗余了,但這對(duì)數(shù)據(jù)一致性有大的風(fēng)險(xiǎn)。這需要根據(jù)不同的業(yè)務(wù)進(jìn)行分析和處理。(注意:用關(guān)系型數(shù)據(jù)庫(kù)很容易移植到NoSQL上,但是反過(guò)來(lái)從NoSQL到關(guān)系型就難了) 5.2.2數(shù)據(jù)鏡像幾乎所有主流的數(shù)據(jù)庫(kù)都支持鏡像,也就是replication。數(shù)據(jù)庫(kù)的鏡像帶來(lái)的好處就是可以做負(fù)載均衡。把一臺(tái)數(shù)據(jù)庫(kù)的負(fù)載均分到多臺(tái)上,同時(shí)又保證了數(shù)據(jù)一致性(如Oracle的SCN)。最重要的是,這樣還可以有高可用性,一臺(tái)廢了,還有另一臺(tái)在服務(wù)。 數(shù)據(jù)鏡像的數(shù)據(jù)一致性可能是個(gè)復(fù)雜的問(wèn)題,所以我們要在單條數(shù)據(jù)上進(jìn)行數(shù)據(jù)分區(qū),也就是說(shuō),把一個(gè)暢銷(xiāo)商品的庫(kù)存均分到不同的服務(wù)器上,如,一個(gè)暢銷(xiāo)商品有1萬(wàn)的庫(kù)存,我們可以設(shè)置10臺(tái)服務(wù)器,每臺(tái)服務(wù)器上有1000個(gè)庫(kù)存,這就好像B2C的倉(cāng)庫(kù)一樣。 5.2.3數(shù)據(jù)分區(qū)數(shù)據(jù)鏡像不能解決的一個(gè)問(wèn)題就是數(shù)據(jù)表里的記錄太多,導(dǎo)致數(shù)據(jù)庫(kù)操作太慢。所以,把數(shù)據(jù)分區(qū)。數(shù)據(jù)分區(qū)有很多種做法,一般來(lái)說(shuō)有下面這幾種: 1)把數(shù)據(jù)把某種邏輯來(lái)分類(lèi)。比如火車(chē)訂票系統(tǒng)可按各種車(chē)型分,可以按始發(fā)站分,可以按目的地分……,反正就是把一張表拆成多張有一樣的字段但是不同種類(lèi)的表,這樣,這些表就可以存在不同的機(jī)器上以達(dá)到分擔(dān)負(fù)載的目的。 2)把數(shù)據(jù)按字段分。比如把一些不經(jīng)常改的數(shù)據(jù)放在一個(gè)表里,經(jīng)常改的數(shù)據(jù)放在另外多個(gè)表里。把一張表變?yōu)?對(duì)1的關(guān)系,這樣,你可以減少表的字段個(gè)數(shù),同樣可以提升一定的性能。另外,字段多會(huì)造成一條記錄的存儲(chǔ)會(huì)被放到不同的頁(yè)表里,這對(duì)于讀寫(xiě)性能都有問(wèn)題。但這樣一來(lái)會(huì)有很多復(fù)雜的控制。 3)平均分表。因?yàn)榈谝环N方法是并不一定平均分均,可能某個(gè)種類(lèi)的數(shù)據(jù)還是很多。所以,也有采用平均分配的方式,通過(guò)主鍵ID的范圍來(lái)分表。 4)同一數(shù)據(jù)分區(qū)。也就是把同一商品的庫(kù)存值分到不同的服務(wù)器上,比如有10000個(gè)庫(kù)存,可以分到10臺(tái)服務(wù)器上,一臺(tái)上有1000個(gè)庫(kù)存。然后負(fù)載均衡。 這三種分區(qū)都有好有壞。最常用的還是第一種。數(shù)據(jù)一旦分區(qū),你就需要有一個(gè)或是多個(gè)調(diào)度來(lái)讓你的前端程序知道去哪里找數(shù)據(jù)。 5.2.4后端系統(tǒng)負(fù)載均衡前面說(shuō)了數(shù)據(jù)分區(qū),數(shù)據(jù)分區(qū)可以在一定程度上減輕負(fù)載,但是無(wú)法減輕熱銷(xiāo)商品的負(fù)載。這就需要使用數(shù)據(jù)鏡像來(lái)減輕負(fù)載。使用數(shù)據(jù)鏡像,必然要使用負(fù)載均衡,在后端,我們可能很難使用像路由器上的負(fù)載均衡器,因?yàn)槟鞘蔷饬髁康模驗(yàn)榱髁坎⒉淮矸?wù)器的繁忙程度。因此,我們需要一個(gè)任務(wù)分配系統(tǒng),其還能監(jiān)控各個(gè)服務(wù)器的負(fù)載情況。 任務(wù)分配服務(wù)器有一些難點(diǎn): 負(fù)載情況比較復(fù)雜。什么叫忙?是CPU高?還是磁盤(pán)I/O高?還是內(nèi)存使用高?還是并發(fā)高?還是內(nèi)存換頁(yè)率高?你可能需要全部都要考慮。這些信息要發(fā)送給那個(gè)任務(wù)分配器上,由任務(wù)分配器挑選一臺(tái)負(fù)載最輕的服務(wù)器來(lái)處理。 任務(wù)分配服務(wù)器上需要對(duì)任務(wù)隊(duì)列,不能丟任務(wù),所以還需要持久化。并且可以以批量的方式把任務(wù)分配給計(jì)算服務(wù)器。 任務(wù)分配服務(wù)器死了怎么辦?這里需要一些如Live-Standby或是failover等高可用性的技術(shù)。我們還需要注意那些持久化了的任務(wù)的隊(duì)列如何轉(zhuǎn)移到別的服務(wù)器上的問(wèn)題。 有很多系統(tǒng)都用靜態(tài)的方式來(lái)分配,有的用hash,有的就簡(jiǎn)單地輪流分析。這些都不夠好,一個(gè)是不能完美地負(fù)載均衡,另一個(gè)靜態(tài)的方法的致命缺陷是,如果有一臺(tái)計(jì)算服務(wù)器死機(jī)了,或是我們需要加入新的服務(wù)器,對(duì)于我們的分配器來(lái)說(shuō),都需要知道的。另外,還要重算哈希(一致性hash可以部分解決這個(gè)問(wèn)題)。 還有一種方法是使用搶占式的方式進(jìn)行負(fù)載均衡,由下游的計(jì)算服務(wù)器去任務(wù)服務(wù)器上拿任務(wù)。讓這些計(jì)算服務(wù)器自己決定自己是否要任務(wù)。這樣的好處是可以簡(jiǎn)化系統(tǒng)的復(fù)雜度,而且還可以任意實(shí)時(shí)地減少或增加計(jì)算服務(wù)器。但是唯一不好的就是,如果有一些任務(wù)只能在某種服務(wù)器上處理,這可能會(huì)引入一些復(fù)雜度。不過(guò)總體來(lái)說(shuō),這種方法可能是比較好的負(fù)載均衡。 5.2.5異步、 throttle 和 批量處理異步、throttle(節(jié)流閥) 和批量處理都需要對(duì)并發(fā)請(qǐng)求數(shù)做隊(duì)列處理的。 異步在業(yè)務(wù)上一般來(lái)說(shuō)就是收集請(qǐng)求,然后延時(shí)處理。在技術(shù)上就是可以把各個(gè)處理程序做成并行的,也就可以水平擴(kuò)展了。但是異步的技術(shù)問(wèn)題大概有這些,a)被調(diào)用方的結(jié)果返回,會(huì)涉及進(jìn)程線程間通信的問(wèn)題。b)如果程序需要回滾,回滾會(huì)有點(diǎn)復(fù)雜。c)異步通常都會(huì)伴隨多線程多進(jìn)程,并發(fā)的控制也相對(duì)麻煩一些。d)很多異步系統(tǒng)都用消息機(jī)制,消息的丟失和亂序也會(huì)是比較復(fù)雜的問(wèn)題。 throttle 技術(shù)其實(shí)并不提升性能,這個(gè)技術(shù)主要是防止系統(tǒng)被超過(guò)自己不能處理的流量給搞垮了,這其實(shí)是個(gè)保護(hù)機(jī)制。使用throttle技術(shù)一般來(lái)說(shuō)是對(duì)于一些自己無(wú)法控制的系統(tǒng),比如,和你網(wǎng)站對(duì)接的銀行系統(tǒng)。 批量處理的技術(shù),是把一堆基本相同的請(qǐng)求批量處理。比如,大家同時(shí)購(gòu)買(mǎi)同一個(gè)商品,沒(méi)有必要你買(mǎi)一個(gè)我就寫(xiě)一次數(shù)據(jù)庫(kù),完全可以收集到一定數(shù)量的請(qǐng)求,一次操作。批量處理的問(wèn)題是流量低,所以,批量處理的系統(tǒng)一般都會(huì)設(shè)置上兩個(gè)閥值,一個(gè)是作業(yè)量,另一個(gè)是timeout,只要有一個(gè)條件滿足,就會(huì)開(kāi)始提交處理。 所以,只要是異步,一般都會(huì)有throttle機(jī)制,一般都會(huì)有隊(duì)列來(lái)排隊(duì),有隊(duì)列,就會(huì)有持久化,而系統(tǒng)一般都會(huì)使用批量的方式來(lái)處理。 但是從業(yè)務(wù)和用戶需求上來(lái)說(shuō)可能還有一些值得我們?nèi)ド钊胨伎嫉牡胤剑?)隊(duì)列的DoS攻擊。2)對(duì)列的一致性3)隊(duì)列的等待時(shí)間。
說(shuō)明:本文部分內(nèi)容來(lái)自酷 殼 – CoolShell.cn 《性能調(diào)優(yōu)攻略》、《由12306.cn談?wù)劸W(wǎng)站性能技術(shù)》,結(jié)合自己有限的性能測(cè)試經(jīng)驗(yàn)進(jìn)行了部分補(bǔ)充、節(jié)選和整理。希望對(duì)這方面感興趣的朋友更好的系統(tǒng)性了解性能測(cè)試。
|
|
來(lái)自: WindySky > 《性能測(cè)試》