自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Linux內(nèi)核性能調(diào)優(yōu):讓系統(tǒng)飛起來(lái)的秘籍

系統(tǒng) Linux
Linux 內(nèi)核性能調(diào)優(yōu)絕非小事,它直接關(guān)系到系統(tǒng)的穩(wěn)定性、可靠性以及業(yè)務(wù)的正常運(yùn)轉(zhuǎn)。通過(guò)對(duì)內(nèi)核參數(shù)進(jìn)行合理調(diào)整、優(yōu)化系統(tǒng)資源分配、采用高效的調(diào)度算法等手段,可以顯著提升 Linux 內(nèi)核的性能,讓系統(tǒng)在面對(duì)各種復(fù)雜工作負(fù)載時(shí)都能游刃有余。

在當(dāng)今數(shù)字化時(shí)代,Linux 系統(tǒng)憑借其強(qiáng)大的穩(wěn)定性、開(kāi)放性和靈活性,廣泛應(yīng)用于服務(wù)器、云計(jì)算、大數(shù)據(jù)等諸多領(lǐng)域。然而,隨著業(yè)務(wù)量的不斷增長(zhǎng)和應(yīng)用場(chǎng)景的日益復(fù)雜,Linux 內(nèi)核的性能面臨著巨大挑戰(zhàn)。哪怕是微小的性能瓶頸,都可能像滾雪球一樣,在高負(fù)載運(yùn)行時(shí)被無(wú)限放大,進(jìn)而引發(fā)一系列嚴(yán)重問(wèn)題。

想象一下,一個(gè)電商網(wǎng)站在購(gòu)物高峰期,由于 Linux 內(nèi)核性能不佳,導(dǎo)致服務(wù)器響應(yīng)遲緩。用戶點(diǎn)擊商品詳情,頁(yè)面卻遲遲無(wú)法加載;提交訂單后,長(zhǎng)時(shí)間得不到反饋。這不僅會(huì)讓用戶體驗(yàn)大打折扣,還可能導(dǎo)致大量潛在客戶流失,給企業(yè)帶來(lái)不可估量的經(jīng)濟(jì)損失。再比如,一個(gè)實(shí)時(shí)數(shù)據(jù)分析系統(tǒng),因?yàn)閮?nèi)核性能問(wèn)題,無(wú)法及時(shí)處理海量數(shù)據(jù),使得分析結(jié)果嚴(yán)重滯后,企業(yè)決策層基于這些滯后數(shù)據(jù)做出的決策,很可能與市場(chǎng)實(shí)際情況脫節(jié),進(jìn)而影響企業(yè)的戰(zhàn)略布局和發(fā)展方向。

由此可見(jiàn),Linux 內(nèi)核性能調(diào)優(yōu)絕非小事,它直接關(guān)系到系統(tǒng)的穩(wěn)定性、可靠性以及業(yè)務(wù)的正常運(yùn)轉(zhuǎn)。通過(guò)對(duì)內(nèi)核參數(shù)進(jìn)行合理調(diào)整、優(yōu)化系統(tǒng)資源分配、采用高效的調(diào)度算法等手段,可以顯著提升 Linux 內(nèi)核的性能,讓系統(tǒng)在面對(duì)各種復(fù)雜工作負(fù)載時(shí)都能游刃有余。接下來(lái),就讓我們一同深入探索 Linux 內(nèi)核性能調(diào)優(yōu)的精彩世界。

一、系統(tǒng)性能指標(biāo)大揭秘

在深入探討 Linux 內(nèi)核性能調(diào)優(yōu)方法之前,我們首先要明確衡量系統(tǒng)性能的關(guān)鍵指標(biāo)。就如同評(píng)價(jià)一輛汽車的性能,我們會(huì)關(guān)注它的速度、油耗、操控性等指標(biāo)一樣,對(duì)于 Linux 系統(tǒng),吞吐量、系統(tǒng)延遲、CPU 使用率、內(nèi)存使用率和磁盤 I/O 等指標(biāo),能幫助我們?nèi)媪私庀到y(tǒng)的運(yùn)行狀態(tài)。

1.1吞吐量:數(shù)據(jù)處理的速度擔(dān)當(dāng)

吞吐量,是指在單位時(shí)間內(nèi)系統(tǒng)成功處理的數(shù)據(jù)量或請(qǐng)求數(shù) ,它直觀地反映了系統(tǒng)的數(shù)據(jù)處理能力。以一個(gè)電商網(wǎng)站為例,假設(shè)在促銷活動(dòng)期間,該網(wǎng)站每秒能夠處理 1000 個(gè)商品查詢請(qǐng)求和 200 個(gè)訂單提交請(qǐng)求,這些請(qǐng)求處理的數(shù)量就是網(wǎng)站系統(tǒng)的吞吐量體現(xiàn)。如果網(wǎng)站的吞吐量較低,在高并發(fā)的情況下,大量請(qǐng)求就會(huì)堆積,導(dǎo)致系統(tǒng)響應(yīng)緩慢甚至崩潰。就像一條狹窄的公路,車流量稍大就會(huì)造成交通堵塞。提高系統(tǒng)吞吐量,能夠讓系統(tǒng)在單位時(shí)間內(nèi)處理更多的任務(wù),滿足業(yè)務(wù)增長(zhǎng)的需求。

1.2系統(tǒng)延遲:影響用戶體驗(yàn)的關(guān)鍵

系統(tǒng)延遲,指的是從請(qǐng)求發(fā)出到收到響應(yīng)所經(jīng)歷的時(shí)間。還是以電商網(wǎng)站為例,當(dāng)用戶點(diǎn)擊商品詳情頁(yè)時(shí),頁(yè)面如果能在 1 秒內(nèi)加載完成,用戶幾乎察覺(jué)不到延遲,體驗(yàn)流暢;但如果加載時(shí)間長(zhǎng)達(dá) 5 秒甚至更久,用戶就會(huì)感到不耐煩,可能會(huì)離開(kāi)網(wǎng)站。低延遲對(duì)于提升用戶體驗(yàn)至關(guān)重要,尤其在對(duì)實(shí)時(shí)性要求極高的場(chǎng)景,如在線游戲、金融交易等。在在線游戲中,玩家的每一個(gè)操作都需要及時(shí)反饋到游戲畫面中,如果系統(tǒng)延遲過(guò)高,玩家發(fā)出的攻擊指令可能要數(shù)秒后才會(huì)生效,這會(huì)嚴(yán)重影響游戲的公平性和趣味性。

一般來(lái)說(shuō),一個(gè)系統(tǒng)的性能受到這兩個(gè)條件的約束,缺一不可。比如,我的系統(tǒng)可以頂?shù)米∫话偃f(wàn)的并發(fā),但是系統(tǒng)的延遲是2分鐘以上,那么,這個(gè)一百萬(wàn)的負(fù)載毫無(wú)意義。系統(tǒng)延遲很短,但是吞吐量很低,同樣沒(méi)有意義。所以,一個(gè)好的系統(tǒng)的性能測(cè)試必然受到這兩個(gè)條件的同時(shí)作用。

有經(jīng)驗(yàn)的朋友一定知道,這兩個(gè)東西的一些關(guān)系:

  • Throughput越大,Latency會(huì)越差。因?yàn)檎?qǐng)求量過(guò)大,系統(tǒng)太繁忙,所以響應(yīng)速度自然會(huì)低。
  • Latency越好,能支持的Throughput就會(huì)越高。因?yàn)長(zhǎng)atency短說(shuō)明處理速度快,于是就可以處理更多的請(qǐng)求。

二、定位性能瓶頸的實(shí)用方法

2.1系統(tǒng)性能測(cè)試

經(jīng)過(guò)上述的說(shuō)明,我們知道要測(cè)試系統(tǒng)的性能,需要我們收集系統(tǒng)的Throughput和Latency這兩個(gè)值。

  • 首先,需要定義Latency這個(gè)值,比如說(shuō),對(duì)于網(wǎng)站系統(tǒng)響應(yīng)時(shí)間必需是5秒以內(nèi)(對(duì)于某些實(shí)時(shí)系統(tǒng)可能需要定義的更短,比如5ms以內(nèi),這個(gè)更根據(jù)不同的業(yè)務(wù)來(lái)定義)
  • 其次,開(kāi)發(fā)性能測(cè)試工具,一個(gè)工具用來(lái)制造高強(qiáng)度的Throughput,另一個(gè)工具用來(lái)測(cè)量Latency。對(duì)于第一個(gè)工具,你可以參考一下“十個(gè)免費(fèi)的Web壓力測(cè)試工具”,關(guān)于如何測(cè)量Latency,你可以在代碼中測(cè)量,但是這樣會(huì)影響程序的執(zhí)行,而且只能測(cè)試到程序內(nèi)部的Latency,真正的Latency是整個(gè)系統(tǒng)都算上,包括操作系統(tǒng)和網(wǎng)絡(luò)的延時(shí),你可以使用Wireshark來(lái)抓網(wǎng)絡(luò)包來(lái)測(cè)量。這兩個(gè)工具具體怎么做,這個(gè)還請(qǐng)大家自己思考去了。
  • 最后,開(kāi)始性能測(cè)試。你需要不斷地提升測(cè)試的Throughput,然后觀察系統(tǒng)的負(fù)載情況,如果系統(tǒng)頂?shù)米?,那就觀察Latency的值。這樣,你就可以找到系統(tǒng)的最大負(fù)載,并且你可以知道系統(tǒng)的響應(yīng)延時(shí)是多少。

再多說(shuō)一些,

  • 關(guān)于Latency,如果吞吐量很少,這個(gè)值估計(jì)會(huì)非常穩(wěn)定,當(dāng)吞吐量越來(lái)越大時(shí),系統(tǒng)的Latency會(huì)出現(xiàn)非常劇烈的抖動(dòng),所以,我們?cè)跍y(cè)量Latency的時(shí)候,我們需要注意到Latency的分布,也就是說(shuō),有百分之幾的在我們?cè)试S的范圍,有百分之幾的超出了,有百分之幾的完全不可接受。也許,平均下來(lái)的Latency達(dá)標(biāo)了,但是其中僅有50%的達(dá)到了我們可接受的范圍。那也沒(méi)有意義。
  • 關(guān)于性能測(cè)試,我們還需要定義一個(gè)時(shí)間段。比如:在某個(gè)吞吐量上持續(xù)15分鐘。因?yàn)楫?dāng)負(fù)載到達(dá)的時(shí)候,系統(tǒng)會(huì)變得不穩(wěn)定,當(dāng)過(guò)了一兩分鐘后,系統(tǒng)才會(huì)穩(wěn)定。另外,也有可能是,你的系統(tǒng)在這個(gè)負(fù)載下前幾分鐘還表現(xiàn)正常,然后就不穩(wěn)定了,甚至垮了。所以,需要這么一段時(shí)間。這個(gè)值,我們叫做峰值極限。
  • 性能測(cè)試還需要做Soak Test,也就是在某個(gè)吞吐量下,系統(tǒng)可以持續(xù)跑一周甚至更長(zhǎng)。這個(gè)值,我們叫做系統(tǒng)的正常運(yùn)行的負(fù)載極限。

性能測(cè)試有很多很復(fù)要的東西,比如:burst test等。這里不能一一詳述,這里只說(shuō)了一些和性能調(diào)優(yōu)相關(guān)的東西。總之,性能測(cè)試是一細(xì)活和累活。

有了上面的鋪墊,我們就可以測(cè)試到到系統(tǒng)的性能了,再調(diào)優(yōu)之前,我們先來(lái)說(shuō)說(shuō)如何找到性能的瓶頸。我見(jiàn)過(guò)很多朋友會(huì)覺(jué)得這很容易,但是仔細(xì)一問(wèn),其實(shí)他們并沒(méi)有一個(gè)比較系統(tǒng)的方法。

2.2查看操作系統(tǒng)負(fù)載

在排查 Linux 內(nèi)核性能問(wèn)題時(shí),查看操作系統(tǒng)負(fù)載是關(guān)鍵的第一步。通過(guò)這一操作,我們能夠了解系統(tǒng)當(dāng)前的工作壓力,進(jìn)而找出可能存在的性能瓶頸。

利用 top 命令,我們可以實(shí)時(shí)查看系統(tǒng)的整體運(yùn)行狀態(tài)。在命令行中輸入 “top”,隨即會(huì)出現(xiàn)一個(gè)動(dòng)態(tài)更新的界面,展示諸多重要信息。最上方的一行詳細(xì)呈現(xiàn)了 CPU 的使用情況,其中包括用戶空間進(jìn)程使用的 CPU 時(shí)間百分比(us)、內(nèi)核空間進(jìn)程使用的 CPU 時(shí)間百分比(sy)、被調(diào)整優(yōu)先級(jí)的用戶進(jìn)程使用的 CPU 時(shí)間(ni)、空閑的 CPU 時(shí)間百分比(id)、等待 I/O 操作完成的 CPU 時(shí)間百分比(wa)、硬件中斷使用的 CPU 時(shí)間百分比(hi)、軟件中斷使用的 CPU 時(shí)間百分比(si)以及虛擬機(jī)管理程序等待其他虛擬 CPU 運(yùn)行的時(shí)間百分比(st)。舉例來(lái)說(shuō),如果發(fā)現(xiàn) us 值較高,那就意味著用戶空間的進(jìn)程消耗了大量 CPU 資源,此時(shí)我們就需要深入檢查這些進(jìn)程,判斷是否存在異常或低效的代碼。

而 htop 命令則提供了更為直觀和豐富的信息展示。它以可視化的方式呈現(xiàn) CPU 的使用情況,不同顏色的條形圖分別代表不同類型的 CPU 負(fù)載,如綠色表示用戶進(jìn)程使用的 CPU,紅色表示內(nèi)核進(jìn)程使用的 CPU 等。同時(shí),它還能清晰地顯示每個(gè)進(jìn)程的詳細(xì)信息,包括進(jìn)程 ID、用戶、優(yōu)先級(jí)、內(nèi)存使用量等。當(dāng)我們懷疑某個(gè)進(jìn)程對(duì)系統(tǒng)性能產(chǎn)生較大影響時(shí),使用 htop 能夠更方便地定位和分析該進(jìn)程。

SystemTap 是一款強(qiáng)大的動(dòng)態(tài)內(nèi)核和用戶空間追蹤工具。它允許我們編寫腳本,對(duì)系統(tǒng)運(yùn)行時(shí)的各種事件進(jìn)行捕獲和分析。假設(shè)我們想要了解某個(gè)特定進(jìn)程在執(zhí)行過(guò)程中對(duì)系統(tǒng)資源的占用情況,就可以編寫一個(gè) SystemTap 腳本,專門針對(duì)該進(jìn)程進(jìn)行監(jiān)控。通過(guò)腳本,我們能夠獲取該進(jìn)程的 CPU 利用率、內(nèi)存訪問(wèn)頻率等詳細(xì)信息,從而精準(zhǔn)定位問(wèn)題所在。

LatencyTOP 則專注于檢測(cè)系統(tǒng)中的延遲問(wèn)題。在運(yùn)行 LatencyTOP 后,它會(huì)分析系統(tǒng)中各個(gè)進(jìn)程的延遲情況,并將延遲較高的進(jìn)程凸顯出來(lái)。例如,若 LatencyTOP 報(bào)告某個(gè)驅(qū)動(dòng)程序進(jìn)程的延遲過(guò)高,這可能表明該驅(qū)動(dòng)程序存在性能缺陷,需要進(jìn)一步優(yōu)化或更新。

首先,當(dāng)我們系統(tǒng)有問(wèn)題的時(shí)候,我們不要急于去調(diào)查我們代碼,這個(gè)毫無(wú)意義。我們首要需要看的是操作系統(tǒng)的報(bào)告。看看操作系統(tǒng)的CPU利用率,看看內(nèi)存使用率,看看操作系統(tǒng)的IO,還有網(wǎng)絡(luò)的IO,網(wǎng)絡(luò)鏈接數(shù),等等。Windows下的perfmon是一個(gè)很不錯(cuò)的工具,Linux下也有很多相關(guān)的命令和工具,比如:SystemTap,LatencyTOP,vmstat, sar, iostat, top, tcpdump等等 。通過(guò)觀察這些數(shù)據(jù),我們就可以知道我們的軟件的性能基本上出在哪里。比如:

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

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

2.3使用Profiler測(cè)試

接下來(lái),我們需要使用性能檢測(cè)工具,也就是使用某個(gè)Profiler來(lái)差看一下我們程序的運(yùn)行性能。如:Java的JProfiler/TPTP/CodePro Profiler,GNU的gprof,IBM的PurifyPlus,Intel的VTune,AMD的CodeAnalyst,還有Linux下的OProfile/perf,后面兩個(gè)可以讓你對(duì)你的代碼優(yōu)化到CPU的微指令級(jí)別,如果你關(guān)心CPU的L1/L2的緩存調(diào)優(yōu),那么你需要考慮一下使用VTune。使用這些Profiler工具,可以讓你程序中各個(gè)模塊函數(shù)甚至指令的很多東西,如:運(yùn)行的時(shí)間 ,調(diào)用的次數(shù),CPU的利用率,等等。這些東西對(duì)我們來(lái)說(shuō)非常有用。

我們重點(diǎn)觀察運(yùn)行時(shí)間最多,調(diào)用次數(shù)最多的那些函數(shù)和指令。這里注意一下,對(duì)于調(diào)用次數(shù)多但是時(shí)間很短的函數(shù),你可能只需要輕微優(yōu)化一下,你的性能就上去了(比如:某函數(shù)一秒種被調(diào)用100萬(wàn)次,你想想如果你讓這個(gè)函數(shù)提高0.01毫秒的時(shí)間 ,這會(huì)給你帶來(lái)多大的性能)

使用Profiler有個(gè)問(wèn)題我們需要注意一下,因?yàn)镻rofiler會(huì)讓你的程序運(yùn)行的性能變低,像PurifyPlus這樣的工具會(huì)在你的代碼中插入很多代碼,會(huì)導(dǎo)致你的程序運(yùn)行效率變低,從而沒(méi)發(fā)測(cè)試出在高吞吐量下的系統(tǒng)的性能,對(duì)此,一般有兩個(gè)方法來(lái)定位系統(tǒng)瓶頸:

  • 在你的代碼中自己做統(tǒng)計(jì),使用微秒級(jí)的計(jì)時(shí)器和函數(shù)調(diào)用計(jì)算器,每隔10秒把統(tǒng)計(jì)log到文件中。
  • 分段注釋你的代碼塊,讓一些函數(shù)空轉(zhuǎn),做Hard Code的Mock,然后再測(cè)試一下系統(tǒng)的Throughput和Latency是否有質(zhì)的變化,如果有,那么被注釋的函數(shù)就是性能瓶頸,再在這個(gè)函數(shù)體內(nèi)注釋代碼,直到找到最耗性能的語(yǔ)句。

最后再說(shuō)一點(diǎn),對(duì)于性能測(cè)試,不同的Throughput會(huì)出現(xiàn)不同的測(cè)試結(jié)果,不同的測(cè)試數(shù)據(jù)也會(huì)有不同的測(cè)試結(jié)果。所以,用于性能測(cè)試的數(shù)據(jù)非常重要,性能測(cè)試中,我們需要觀測(cè)試不同Throughput的結(jié)果。

2.4剖析 IO 情況

IO 操作在系統(tǒng)性能中扮演著舉足輕重的角色,對(duì)其進(jìn)行深入剖析,能幫助我們發(fā)現(xiàn)許多潛在的性能問(wèn)題。

在磁盤文件 IO 方面,iostat 命令是我們的得力助手。通過(guò)執(zhí)行 “iostat -d -x 1”(其中 “-d” 表示僅顯示磁盤相關(guān)信息,“-x” 表示顯示更詳細(xì)的信息,“1” 表示每隔 1 秒輸出一次數(shù)據(jù)),我們可以獲取到每個(gè)磁盤設(shè)備的詳細(xì)統(tǒng)計(jì)信息。其中,“r/s” 代表每秒完成的讀次數(shù),“w/s” 代表每秒完成的寫次數(shù),“rkB/s” 表示每秒讀數(shù)據(jù)量,“wkB/s” 表示每秒寫數(shù)據(jù)量,“% util” 則表示設(shè)備的繁忙程度。當(dāng) “% util” 接近 100% 時(shí),說(shuō)明磁盤 I/O 系統(tǒng)已經(jīng)滿負(fù)荷運(yùn)轉(zhuǎn),很可能成為系統(tǒng)性能的瓶頸。比如,在一個(gè)數(shù)據(jù)存儲(chǔ)服務(wù)器中,如果發(fā)現(xiàn)某個(gè)磁盤的 “% util” 長(zhǎng)期保持在 95% 以上,那么就需要考慮對(duì)該磁盤進(jìn)行優(yōu)化,如更換為更高性能的磁盤,或者對(duì)數(shù)據(jù)存儲(chǔ)方式進(jìn)行調(diào)整。

iotop 命令能夠讓我們清晰地看到哪些進(jìn)程正在大量占用磁盤 I/O 資源。執(zhí)行 “iotop” 后,會(huì)列出各個(gè)進(jìn)程的 I/O 使用情況,包括讀速率、寫速率等。當(dāng)我們發(fā)現(xiàn)某個(gè)進(jìn)程的 I/O 讀寫速率異常高時(shí),就需要進(jìn)一步分析該進(jìn)程的業(yè)務(wù)邏輯,看是否存在不合理的 I/O 操作。例如,某個(gè)備份進(jìn)程在進(jìn)行數(shù)據(jù)備份時(shí),采用了頻繁的小文件讀寫方式,這可能會(huì)導(dǎo)致磁盤 I/O 性能下降,此時(shí)可以考慮優(yōu)化備份策略,采用大文件讀寫或者批量操作的方式。

驅(qū)動(dòng)程序 IO 對(duì)系統(tǒng)性能的影響也不容小覷。如果驅(qū)動(dòng)程序存在問(wèn)題,可能會(huì)導(dǎo)致設(shè)備與系統(tǒng)之間的數(shù)據(jù)傳輸效率低下。以網(wǎng)絡(luò)驅(qū)動(dòng)程序?yàn)槔?,若?qū)動(dòng)程序版本過(guò)舊,可能無(wú)法充分發(fā)揮網(wǎng)卡的性能,導(dǎo)致網(wǎng)絡(luò)傳輸速度受限。在這種情況下,及時(shí)更新驅(qū)動(dòng)程序往往能顯著提升系統(tǒng)性能。

內(nèi)存換頁(yè)率也是衡量系統(tǒng)性能的重要指標(biāo)。vmstat 命令可以幫助我們查看內(nèi)存換頁(yè)情況。在輸出結(jié)果中,“si” 表示從磁盤交換到內(nèi)存的交換頁(yè)數(shù)量,“so” 表示從內(nèi)存交換到磁盤的交換頁(yè)數(shù)量。如果 “si” 和 “so” 的值較大,說(shuō)明系統(tǒng)頻繁進(jìn)行內(nèi)存換頁(yè)操作,這會(huì)嚴(yán)重影響系統(tǒng)性能。通常,這可能是由于內(nèi)存不足導(dǎo)致的。比如,在一個(gè)運(yùn)行多個(gè)大型應(yīng)用程序的服務(wù)器上,如果發(fā)現(xiàn)內(nèi)存換頁(yè)率過(guò)高,就需要考慮增加物理內(nèi)存,或者對(duì)應(yīng)用程序的內(nèi)存使用進(jìn)行優(yōu)化。

2.5洞察網(wǎng)絡(luò)帶寬使用

在網(wǎng)絡(luò)環(huán)境中,了解網(wǎng)絡(luò)帶寬的使用情況對(duì)于定位性能瓶頸至關(guān)重要。

iftop 是一款出色的實(shí)時(shí)流量監(jiān)控工具。通過(guò)執(zhí)行 “iftop -i eth0”(其中 “-i” 指定要監(jiān)測(cè)的網(wǎng)卡,“eth0” 是常見(jiàn)的網(wǎng)卡名稱),我們可以直觀地看到指定網(wǎng)卡的實(shí)時(shí)流量情況。在 iftop 的界面中,會(huì)清晰地顯示出各個(gè) IP 地址之間的流量傳輸情況,包括發(fā)送流量(TX)、接收流量(RX)以及總流量(TOTAL)。同時(shí),還能看到不同時(shí)間段的平均流量,如過(guò)去 2 秒、10 秒、40 秒的平均流量。這有助于我們快速發(fā)現(xiàn)哪些 IP 地址之間的流量過(guò)大,從而判斷是否存在網(wǎng)絡(luò)瓶頸。例如,在一個(gè)企業(yè)網(wǎng)絡(luò)中,如果發(fā)現(xiàn)某個(gè) IP 地址與外部服務(wù)器之間的流量持續(xù)超過(guò)網(wǎng)絡(luò)帶寬的 80%,那么就需要進(jìn)一步檢查該 IP 地址對(duì)應(yīng)的業(yè)務(wù),看是否存在數(shù)據(jù)傳輸異常的情況。

iptraf 同樣是一款功能強(qiáng)大的網(wǎng)絡(luò)流量監(jiān)測(cè)工具。它不僅可以實(shí)時(shí)監(jiān)測(cè)網(wǎng)絡(luò)接口的流量,還能提供詳細(xì)的網(wǎng)絡(luò)連接信息,如 TCP 連接、UDP 連接等。通過(guò) “iptraf -g” 命令,我們可以進(jìn)入圖形化界面,方便地查看各個(gè)網(wǎng)絡(luò)接口的流量統(tǒng)計(jì)信息。此外,iptraf 還支持按協(xié)議類型查看流量,這對(duì)于分析網(wǎng)絡(luò)中不同協(xié)議的使用情況非常有幫助。比如,在一個(gè)以 HTTP 協(xié)議為主的網(wǎng)絡(luò)環(huán)境中,如果發(fā)現(xiàn) HTTP 流量占比過(guò)高,導(dǎo)致其他業(yè)務(wù)的網(wǎng)絡(luò)帶寬受到擠壓,那么就可以考慮對(duì) HTTP 業(yè)務(wù)進(jìn)行優(yōu)化,如采用緩存技術(shù)、優(yōu)化頁(yè)面加載方式等,以減少網(wǎng)絡(luò)帶寬的占用。

三、性能調(diào)優(yōu)的方法

下面這些東西是我所經(jīng)歷過(guò)的一些問(wèn)題,也許并不全,也許并不對(duì),大家可以補(bǔ)充指正,我純屬拋磚引玉。一般來(lái)說(shuō),性能優(yōu)化也就是下面的幾個(gè)策略:

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

從架構(gòu)上來(lái)說(shuō),這表再為——是否可以做到不改代碼只是加加機(jī)器就可以完成性能提升?

總之,根據(jù)2:8原則來(lái)說(shuō),20%的代碼耗了你80%的性能,找到那20%的代碼,你就可以優(yōu)化那80%的性能。下面的一些東西都是我的一些經(jīng)驗(yàn),我只例舉了一些最有價(jià)值的性能調(diào)優(yōu)的的方法,供你參考,也歡迎補(bǔ)充。

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

算法非常重要,好的算法會(huì)有更好的性能。舉幾個(gè)我經(jīng)歷過(guò)的項(xiàng)目的例子,大家可以感覺(jué)一下。

  • 一個(gè)是過(guò)濾算法,系統(tǒng)需要對(duì)收到的請(qǐng)求做過(guò)濾,我們把可以被filter in/out的東西配置在了一個(gè)文件中,原有的過(guò)濾算法是遍歷過(guò)濾配置,后來(lái),我們找到了一種方法可以對(duì)這個(gè)過(guò)濾配置進(jìn)行排序,這樣就可以用二分折半的方法來(lái)過(guò)濾,系統(tǒng)性能增加了50%。
  • 一個(gè)是哈希算法。計(jì)算哈希算法的函數(shù)并不高效,一方面是計(jì)算太費(fèi)時(shí),另一方面是碰撞太高,碰撞高了就跟單向鏈表一個(gè)性能(可參看Hash Collision DoS 問(wèn)題)。我們知道,算法都是和需要處理的數(shù)據(jù)很有關(guān)系的,就算是被大家所嘲笑的“冒泡排序”在某些情況下(大多數(shù)數(shù)據(jù)是排好序的)其效率會(huì)高于所有的排序算法。哈希算法也一樣,廣為人知的哈希算法都是用英文字典做測(cè)試,但是我們的業(yè)務(wù)在數(shù)據(jù)有其特殊性,所以,對(duì)于還需要根據(jù)自己的數(shù)據(jù)來(lái)挑選適合的哈希算法。對(duì)于我以前的一個(gè)項(xiàng)目,公司內(nèi)某牛人給我發(fā)來(lái)了一個(gè)哈希算法,結(jié)果讓我們的系統(tǒng)性能上升了150%。(關(guān)于各種哈希算法,你一定要看看StackExchange上的這篇關(guān)于各種hash算法的文章 )

分而治之和預(yù)處理。以前有一個(gè)程序?yàn)榱松稍聢?bào)表,每次都需要計(jì)算很長(zhǎng)的時(shí)間,有時(shí)候需要花將近一整天的時(shí)間。于是我們把我們找到了一種方法可以把這個(gè)算法發(fā)成增量式的,也就是說(shuō)我每天都把當(dāng)天的數(shù)據(jù)計(jì)算好了后和前一天的報(bào)表合并,這樣可以大大的節(jié)省計(jì)算時(shí)間,每天的數(shù)據(jù)計(jì)算量只需要20分鐘,但是如果我要算整個(gè)月的,系統(tǒng)則需要10個(gè)小時(shí)以上(SQL語(yǔ)句在大數(shù)據(jù)量面前性能成級(jí)數(shù)性下降)。這種分而治之的思路在大數(shù)據(jù)面前對(duì)性能有很幫助,就像merge排序一樣。SQL語(yǔ)句和數(shù)據(jù)庫(kù)的性能優(yōu)化也是這一策略,如:使用嵌套式的Select而不是笛卡爾積的Select,使用視圖,等等。

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

從我的經(jīng)驗(yàn)上來(lái)說(shuō),代碼上的調(diào)優(yōu)有下面這幾點(diǎn):

字符串操作。這是最費(fèi)系統(tǒng)性能的事了,無(wú)論是strcpy, strcat還是strlen,最需要注意的是字符串子串匹配。所以,能用整型最好用整型。舉幾個(gè)例子,第一個(gè)例子是N年前做銀行的時(shí)候,我的同事喜歡把日期存成字符串(如:2012-05-29 08:30:02),我勒個(gè)去,一個(gè)select where between語(yǔ)句相當(dāng)耗時(shí)。另一個(gè)例子是,我以前有個(gè)同事把一些狀態(tài)碼用字符串來(lái)處理,他的理由是,這樣可以在界面上直接顯示,后來(lái)性能調(diào)優(yōu)的時(shí)候,我把這些狀態(tài)碼全改成整型,然后用位操作查狀態(tài),因?yàn)橛幸粋€(gè)每秒鐘被調(diào)用了150K次的函數(shù)里面有三處需要檢查狀態(tài),經(jīng)過(guò)改善以后,整個(gè)系統(tǒng)的性能上升了30%左右。還有一個(gè)例子是,我以前從事的某個(gè)產(chǎn)品編程規(guī)范中有一條是要在每個(gè)函數(shù)中把函數(shù)名定義出來(lái),如:const char fname[]=”functionName()”, 這是為了好打日志,但是為什么不聲明成 static類型的呢?

多線程調(diào)優(yōu)。有人說(shuō),thread is evil,這個(gè)對(duì)于系統(tǒng)性能在某些時(shí)候是個(gè)問(wèn)題。因?yàn)槎嗑€程瓶頸就在于互斥和同步的鎖上,以及線程上下文切換的成本,怎么樣的少用鎖或不用鎖是根本(比如:多版本并發(fā)控制(MVCC)在分布式系統(tǒng)中的應(yīng)用 中說(shuō)的樂(lè)觀鎖可以解決性能問(wèn)題),此外,還有讀寫鎖也可以解決大多數(shù)是讀操作的并發(fā)的性能問(wèn)題。這里多說(shuō)一點(diǎn)在C++中,我們可能會(huì)使用線程安全的智能指針AutoPtr或是別的一些容器,只要是線程安全的,其不管三七二十一都要上鎖,上鎖是個(gè)成本很高的操作,使用AutoPtr會(huì)讓我們的系統(tǒng)性能下降得很快,如果你可以保證不會(huì)有線程并發(fā)問(wèn)題,那么你應(yīng)該不要用AutoPtr。

我記得我上次我們同事去掉智能指針的引用計(jì)數(shù),讓系統(tǒng)性能提升了50%以上。對(duì)于Java對(duì)象的引用計(jì)數(shù),如果我猜的沒(méi)錯(cuò)的話,到處都是鎖,所以,Java的性能問(wèn)題一直是個(gè)問(wèn)題。另外,線程不是越多越好,線程間的調(diào)度和上下文切換也是很夸張的事,盡可能的在一個(gè)線程里干,盡可能的不要同步線程。這會(huì)讓你有很多的性能。

內(nèi)存分配。不要小看程序的內(nèi)存分配。malloc/realloc/calloc這樣的系統(tǒng)調(diào)非常耗時(shí),尤其是當(dāng)內(nèi)存出現(xiàn)碎片的時(shí)候。我以前的公司出過(guò)這樣一個(gè)問(wèn)題——在用戶的站點(diǎn)上,我們的程序有一天不響應(yīng)了,用GDB跟進(jìn)去一看,系統(tǒng)hang在了malloc操作上,20秒都沒(méi)有返回,重啟一些系統(tǒng)就好了。這就是內(nèi)存碎片的問(wèn)題。這就是為什么很多人抱怨STL有嚴(yán)重的內(nèi)存碎片的問(wèn)題,因?yàn)樘嗟男?nèi)存的分配釋放了。有很多人會(huì)以為用內(nèi)存池可以解決這個(gè)問(wèn)題,但是實(shí)際上他們只是重新發(fā)明了Runtime-C或操作系統(tǒng)的內(nèi)存管理機(jī)制,完全于事無(wú)補(bǔ)。

當(dāng)然解決內(nèi)存碎片的問(wèn)題還是通過(guò)內(nèi)存池,具體來(lái)說(shuō)是一系列不同尺寸的內(nèi)存池(這個(gè)留給大家自己去思考)。當(dāng)然,少進(jìn)行動(dòng)態(tài)內(nèi)存分配是最好的。說(shuō)到內(nèi)存池就需要說(shuō)一下池化技術(shù)。比如線程池,連接池等。池化技術(shù)對(duì)于一些短作業(yè)來(lái)說(shuō)(如http服務(wù)) 相當(dāng)相當(dāng)?shù)挠行?。這項(xiàng)技術(shù)可以減少鏈接建立,線程創(chuàng)建的開(kāi)銷,從而提高性能。

異步操作。我們知道Unix下的文件操作是有block和non-block的方式的,像有些系統(tǒng)調(diào)用也是block式的,如:Socket下的select,Windows下的WaitforObject之類的,如果我們的程序是同步操作,那么會(huì)非常影響性能,我們可以改成異步的,但是改成異步的方式會(huì)讓你的程序變復(fù)雜。異步方式一般要通過(guò)隊(duì)列,要注間隊(duì)列的性能問(wèn)題,另外,異步下的狀態(tài)通知通常是個(gè)問(wèn)題,比如消息事件通知方式,有callback方式,等,這些方式同樣可能會(huì)影響你的性能。但是通常來(lái)說(shuō),異步操作會(huì)讓性能的吞吐率有很大提升(Throughput),但是會(huì)犧牲系統(tǒng)的響應(yīng)時(shí)間(latency)。這需要業(yè)務(wù)上支持。

語(yǔ)言和代碼庫(kù)。我們要熟悉語(yǔ)言以及所使用的函數(shù)庫(kù)或類庫(kù)的性能。比如:STL中的很多容器分配了內(nèi)存后,那怕你刪除元素,內(nèi)存也不會(huì)回收,其會(huì)造成內(nèi)存泄露的假像,并可能造成內(nèi)存碎片問(wèn)題。再如,STL某些容器的size()==0 和 empty()是不一樣的,因?yàn)椋瑂ize()是O(n)復(fù)雜度,empty()是O(1)的復(fù)雜度,這個(gè)要小心。Java中的JVM調(diào)優(yōu)需要使用的這些參數(shù):-Xms -Xmx -Xmn -XX:SurvivorRatio -XX:MaxTenuringThreshold,還需要注意JVM的GC,GC的霸氣大家都知道,尤其是full GC(還整理內(nèi)存碎片),他就像“恐龍?zhí)丶?jí)克賽號(hào)”一樣,他運(yùn)行的時(shí)候,整個(gè)世界的時(shí)間都停止了。

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

關(guān)于網(wǎng)絡(luò)調(diào)優(yōu),尤其是TCP Tuning(你可以以這兩個(gè)關(guān)鍵詞在網(wǎng)上找到很多文章),這里面有很多很多東西可以說(shuō)??纯碙inux下TCP/IP的那么多參數(shù)就知道了(順便說(shuō)一下,你也許不喜歡Linux,但是你不能否認(rèn)Linux給我們了很多可以進(jìn)行內(nèi)核調(diào)優(yōu)的權(quán)力)。

⑴TCP調(diào)優(yōu)

我們知道TCP鏈接是有很多開(kāi)銷的,一個(gè)是會(huì)占用文件描述符,另一個(gè)是會(huì)開(kāi)緩存,一般來(lái)說(shuō)一個(gè)系統(tǒng)可以支持的TCP鏈接數(shù)是有限的,我們需要清楚地認(rèn)識(shí)到TCP鏈接對(duì)系統(tǒng)的開(kāi)銷是很大的。正是因?yà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)銷。(注: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

傳所有的數(shù)據(jù),反而影響網(wǎng)絡(luò)性能。(當(dāng)然,網(wǎng)絡(luò)差的情況下,就別玩什么高性能了) 所以,高性能的網(wǎng)絡(luò)重要的是要讓網(wǎng)絡(luò)丟包率非常非常地?。ɑ旧鲜怯迷贚AN里),如果網(wǎng)絡(luò)基本是可信的,這樣用大一點(diǎn)的buffer會(huì)有更好的網(wǎng)絡(luò)傳輸性能(來(lái)來(lái)回回太多太影響性能了)。

另外,我們想一想,如果網(wǎng)絡(luò)質(zhì)量非常好,基本不丟包,而業(yè)務(wù)上我們不怕偶爾丟幾個(gè)包,如果是這樣的話,那么,我們?yōu)槭裁床挥盟俣雀斓腢DP呢?你想過(guò)這個(gè)問(wèn)題了嗎?

⑵UDP調(diào)優(yōu)

說(shuō)到UDP的調(diào)優(yōu),有一些事我想重點(diǎn)說(shuō)一樣,那就是MTU——最大傳輸單元(其實(shí)這對(duì)TCP也一樣,因?yàn)檫@是鏈路層上的東西)。所謂最大傳輸單元,你可以想像成是公路上的公交車,假設(shè)一個(gè)公交車可以最多坐70人,帶寬就像是公路的車道數(shù)一樣,如果一條路上最多可以容下100輛公交車,那意味著我最多可以運(yùn)送7000人,但是如果公交車坐不滿,比如平均每輛車只有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ì)于某些NB的千光以態(tài)網(wǎng)網(wǎng)卡來(lái)說(shuō),在網(wǎng)卡上,網(wǎng)卡硬件如果發(fā)現(xiàn)你的包的大小超過(guò)了MTU,其會(huì)幫你做fragment,到了目標(biāo)端又會(huì)幫你做重組,這就不需要你在程序中處理了)

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

最后說(shuō)一點(diǎn),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)多播信息)也很有利。

⑶網(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ò)傳輸非常有效。

⑷其它網(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)用就很慢,所以要小心。

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

⑴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方式是(關(guān)于Linux下的I/O模型,大家可以讀一下這篇文章《使用異步I/O大大提高性能》):

  • 第一種,同步阻塞式I/O,這個(gè)不說(shuō)了。
  • 第二種,同步無(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)有寫完成。這個(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ì)列的不是主線程,而是專門來(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ì)于寫來(lái)說(shuō),cache住要寫的數(shù)據(jù),少寫幾次,但是cache帶來(lái)的問(wèn)題就是實(shí)時(shí)性的問(wèn)題,也就是latency會(huì)變大,我們需要在寫的次數(shù)上和相應(yīng)上做權(quán)衡。

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

關(guān)于CPU的多核技術(shù),我們知道,CPU0是很關(guān)鍵的,如果0號(hào)CPU被用得過(guò)狠的話,別的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ǔ)器空間。關(guān)于NUMA的一些技術(shù)細(xì)節(jié),你可以查看一下這篇文章《Linux 的 NUMA 技術(shù)》,在Linux下,對(duì)NUMA調(diào)優(yōu)的命令是:numactl 。如下面的命令:(指定命令“myprogram arg1 arg2”運(yùn)行在node 0 上,其內(nèi)存分配在node 0 和 1上)

1

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

當(dāng)然,上面這個(gè)命令并不好,因?yàn)閮?nèi)存跨越了兩個(gè)node,這非常不好。最好的方式是只讓程序訪問(wèn)和自己運(yùn)行一樣的node,如:

1

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

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

關(guān)于文件系統(tǒng),因?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è)快速的硬盤控制器,SCSI會(huì)好很多。最快的是Intel SSD 固態(tài)硬盤,速度超快,但是寫次數(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í)刻決定寫入文件發(fā)生時(shí)使用哪個(gè)塊,可優(yōu)化這個(gè)寫入程序。還要注間一下三種日志模式: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)程的磁盤讀寫的負(fù)載情況。

其它還有一些關(guān)于NFS、XFS的調(diào)優(yōu),大家可以上google搜索一些相關(guān)優(yōu)化的文章看看。關(guān)于各文件系統(tǒng),大家可以看一下這篇文章——《Linux日志文件系統(tǒng)及性能分析》

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

數(shù)據(jù)庫(kù)調(diào)優(yōu)并不是我的強(qiáng)項(xiàng),我就僅用我非常有限的知識(shí)說(shuō)上一些吧。注意,下面的這些東西并不一定正確,因?yàn)樵诓煌臉I(yè)務(wù)場(chǎng)景,不同的數(shù)據(jù)庫(kù)設(shè)計(jì)下可能會(huì)得到完全相反的結(jié)論,所以,我僅在這里做一些一般性的說(shuō)明,具體問(wèn)題還要具體分析。

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

我對(duì)數(shù)據(jù)庫(kù)引擎不是熟,但是有幾個(gè)事情我覺(jué)得是一定要去了解的。

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

數(shù)據(jù)庫(kù)的存儲(chǔ)機(jī)制。不但要搞清楚各種類型字段是怎么存儲(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ò)展。

⑵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)存。

下面我根據(jù)我有限的數(shù)據(jù)庫(kù)SQL的知識(shí)說(shuō)幾個(gè)會(huì)有性能問(wèn)題的SQL:

全表檢索。比如: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)。

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

多表查詢。關(guān)系型數(shù)據(jù)庫(kù)最多的操作就是多表查詢,多表查詢主要有三個(gè)關(guān)鍵字,EXISTS,IN和JOIN(關(guān)于各種join,可以參看圖解SQL的Join一文)。基本來(lái)說(shuō),現(xiàn)代的數(shù)據(jù)引擎對(duì)SQL語(yǔ)句優(yōu)化得都挺好的,JOIN和IN/EXISTS在結(jié)果上有些不同,但性能基本上都差不多。有人說(shuō),EXISTS的性能要好于IN,IN的性能要好于JOIN,我各人覺(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則用小表。這個(gè),我沒(méi)有驗(yàn)證過(guò),放在這里讓大家討論吧。另,有一篇關(guān)于SQL Server的文章大家可以看看《IN vs JOIN vs EXISTS》

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ǔ)句,你才知道用哪種方法是最好的。

部分結(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要高很多。

  • 字符串。正如我前面所說(shuō)的,字符串操作對(duì)性能上有非常大的惡夢(mèng),所以,能用數(shù)據(jù)的情況就用數(shù)字,比如:時(shí)間,工號(hào),等。
  • 全文檢索。千萬(wàn)不要用Like之類的東西來(lái)做全文檢索,如果要玩全文檢索,可以嘗試使用Sphinx。
  • 其它。
  • 不要select *,而是明確指出各個(gè)字段,如果有多個(gè)表,一定要在字段名前加上表名,不要讓引擎去算。
  • 不要用Having,因?yàn)槠湟闅v所有的記錄。性能差得不能再差。
  • 盡可能地使用UNION ALL 取代 UNION。
  • 索引過(guò)多,insert和delete就會(huì)越慢。而update如果update多數(shù)索引,也會(huì)慢,但是如果只update一個(gè),則只會(huì)影響一個(gè)索引表。
  • 等等。

四、內(nèi)核性能調(diào)優(yōu)實(shí)戰(zhàn)技巧

4.1內(nèi)存相關(guān)參數(shù)調(diào)整

在 Linux 系統(tǒng)中,內(nèi)存管理對(duì)于系統(tǒng)性能起著舉足輕重的作用。合理調(diào)整內(nèi)存相關(guān)參數(shù),能夠顯著提升系統(tǒng)的運(yùn)行效率和穩(wěn)定性。

vm.swappiness 是一個(gè)關(guān)鍵的內(nèi)存參數(shù),它主要用于控制系統(tǒng)在內(nèi)存不足時(shí)將頁(yè)面交換到磁盤交換空間(swap)的傾向程度 。該參數(shù)的取值范圍是 0 - 100,默認(rèn)值為 60。當(dāng) vm.swappiness 的值設(shè)置得較高時(shí),比如接近 100,系統(tǒng)會(huì)更頻繁地使用磁盤交換空間。這在物理內(nèi)存不足的情況下,雖然能暫時(shí)滿足系統(tǒng)對(duì)內(nèi)存的需求,但由于磁盤 I/O 操作的速度遠(yuǎn)遠(yuǎn)慢于內(nèi)存訪問(wèn)速度,會(huì)導(dǎo)致系統(tǒng)性能大幅下降。相反,如果將 vm.swappiness 的值設(shè)置得較低,如 10 或 20,系統(tǒng)則會(huì)盡量避免使用交換空間,優(yōu)先使用物理內(nèi)存。這對(duì)于那些對(duì)性能要求較高、內(nèi)存使用頻繁的應(yīng)用場(chǎng)景來(lái)說(shuō)非常重要。

例如,在一個(gè)運(yùn)行著數(shù)據(jù)庫(kù)服務(wù)器的 Linux 系統(tǒng)中,如果數(shù)據(jù)庫(kù)操作頻繁且對(duì)響應(yīng)速度要求極高,將 vm.swappiness 設(shè)置為 10,可以減少磁盤交換操作,提高數(shù)據(jù)庫(kù)的讀寫性能,從而提升整個(gè)系統(tǒng)的響應(yīng)速度。調(diào)整 vm.swappiness 參數(shù)的方法很簡(jiǎn)單,我們可以通過(guò)修改 /etc/sysctl.conf 文件來(lái)實(shí)現(xiàn)。在該文件中添加或修改 “vm.swappiness = [想要的值]” 這一行,然后執(zhí)行 “sysctl -p” 命令使配置生效。

vm.overcommit_memory 參數(shù)則控制系統(tǒng)是否允許超額分配內(nèi)存 。它有三個(gè)可選值:0、1 和 2。當(dāng)取值為 0 時(shí),這是系統(tǒng)的默認(rèn)設(shè)置,內(nèi)核會(huì)嘗試估算當(dāng)前系統(tǒng)剩余的可用內(nèi)存,只有在估算認(rèn)為內(nèi)存分配請(qǐng)求不會(huì)導(dǎo)致系統(tǒng)內(nèi)存不足時(shí),才會(huì)允許分配內(nèi)存。當(dāng)取值為 1 時(shí),內(nèi)核會(huì)允許超量使用內(nèi)存,直到物理內(nèi)存被耗盡為止。這種設(shè)置適用于那些對(duì)內(nèi)存需求有明確預(yù)估,且在內(nèi)存使用上比較保守的應(yīng)用場(chǎng)景。比如在一些科學(xué)計(jì)算任務(wù)中,應(yīng)用程序能夠準(zhǔn)確控制自身的內(nèi)存使用量,設(shè)置為 1 可以充分利用系統(tǒng)內(nèi)存資源,提高計(jì)算效率。

當(dāng)取值為 2 時(shí),內(nèi)核會(huì)采用一種嚴(yán)格的內(nèi)存分配算法,確保系統(tǒng)的整個(gè)內(nèi)存地址空間(包括物理內(nèi)存和交換空間)不會(huì)超過(guò) “swap + 50% 的 RAM 值”。這是一種非常保守的設(shè)置,能有效防止系統(tǒng)因內(nèi)存過(guò)度分配而崩潰。調(diào)整 vm.overcommit_memory 參數(shù)同樣可以通過(guò)修改 /etc/sysctl.conf 文件來(lái)完成。在文件中添加或修改 “vm.overcommit_memory = [想要的值]”,然后執(zhí)行 “sysctl -p” 命令使更改生效。

4.2網(wǎng)絡(luò)相關(guān)參數(shù)調(diào)整

在當(dāng)今網(wǎng)絡(luò)互聯(lián)的時(shí)代,網(wǎng)絡(luò)性能的優(yōu)劣直接影響著系統(tǒng)的整體表現(xiàn)。通過(guò)合理調(diào)整網(wǎng)絡(luò)相關(guān)的內(nèi)核參數(shù),能夠有效提升網(wǎng)絡(luò)的吞吐量、降低延遲,確保系統(tǒng)在網(wǎng)絡(luò)通信方面的高效穩(wěn)定。

net.core.somaxconn 參數(shù)定義了 TCP 連接的最大排隊(duì)數(shù)量 ,也就是當(dāng)服務(wù)器在監(jiān)聽(tīng)某個(gè)端口時(shí),處于等待狀態(tài)的最大 TCP 連接請(qǐng)求數(shù)。其默認(rèn)值通常為 128,在一些高并發(fā)的網(wǎng)絡(luò)應(yīng)用場(chǎng)景中,這個(gè)值可能顯得過(guò)小。比如在一個(gè)大型的電商網(wǎng)站服務(wù)器上,在促銷活動(dòng)期間,大量用戶同時(shí)訪問(wèn)服務(wù)器,發(fā)起海量的 TCP 連接請(qǐng)求。如果 net.core.somaxconn 的值仍然保持默認(rèn)的 128,那么當(dāng)?shù)却B接的請(qǐng)求數(shù)超過(guò)這個(gè)值時(shí),后續(xù)的連接請(qǐng)求就可能會(huì)被丟棄,導(dǎo)致用戶無(wú)法正常訪問(wèn)網(wǎng)站,嚴(yán)重影響用戶體驗(yàn)和業(yè)務(wù)的正常開(kāi)展。

為了應(yīng)對(duì)這種高并發(fā)的情況,我們可以根據(jù)服務(wù)器的實(shí)際性能和預(yù)估的并發(fā)連接數(shù),將 net.core.somaxconn 的值適當(dāng)增大,比如設(shè)置為 1024 或更高。這樣可以讓服務(wù)器能夠容納更多的等待連接請(qǐng)求,避免因連接隊(duì)列溢出而造成的連接失敗問(wèn)題。要調(diào)整 net.core.somaxconn 參數(shù),可以編輯 /etc/sysctl.conf 文件,添加或修改 “net.core.somaxconn = [想要的值]” 這一行,之后執(zhí)行 “sysctl -p” 命令使新的配置生效。

net.ipv4.tcp_syncookies 是一個(gè)用于應(yīng)對(duì) SYN 洪水攻擊的重要參數(shù) 。SYN 洪水攻擊是一種常見(jiàn)的網(wǎng)絡(luò)攻擊方式,攻擊者通過(guò)向目標(biāo)服務(wù)器發(fā)送大量偽造的 SYN 請(qǐng)求,耗盡服務(wù)器的連接資源,從而使服務(wù)器無(wú)法正常處理合法的連接請(qǐng)求。當(dāng) net.ipv4.tcp_syncookies 設(shè)置為 1 時(shí),系統(tǒng)啟用 syncookies 機(jī)制。在這種機(jī)制下,當(dāng)服務(wù)器接收到 SYN 請(qǐng)求時(shí),如果發(fā)現(xiàn) SYN 隊(duì)列已滿,它不會(huì)直接丟棄該請(qǐng)求,而是根據(jù)接收到的 SYN 包中的信息計(jì)算出一個(gè)特殊的 cookie 值,并將其作為 SYN + ACK 包的序列號(hào)發(fā)送給客戶端。

客戶端在收到 SYN + ACK 包后,會(huì)將這個(gè) cookie 值包含在 ACK 包中回傳給服務(wù)器。服務(wù)器通過(guò)驗(yàn)證這個(gè) cookie 值,來(lái)確認(rèn)該連接請(qǐng)求的合法性,從而在不占用過(guò)多系統(tǒng)資源的情況下,有效地抵御 SYN 洪水攻擊。而當(dāng) net.ipv4.tcp_syncookies 設(shè)置為 0 時(shí),系統(tǒng)則不啟用 syncookies 機(jī)制。對(duì)于那些面臨較高網(wǎng)絡(luò)安全風(fēng)險(xiǎn),尤其是可能遭受 SYN 洪水攻擊的服務(wù)器來(lái)說(shuō),將 net.ipv4.tcp_syncookies 設(shè)置為 1 是一個(gè)非常必要的安全措施。與前面的參數(shù)調(diào)整方法類似,我們可以通過(guò)修改 /etc/sysctl.conf 文件,添加或修改 “net.ipv4.tcp_syncookies = 1” 這一行,并執(zhí)行 “sysctl -p” 命令來(lái)使設(shè)置生效。

4.3文件系統(tǒng)相關(guān)參數(shù)調(diào)整

文件系統(tǒng)是 Linux 系統(tǒng)中數(shù)據(jù)存儲(chǔ)和管理的核心部分,其性能的好壞直接關(guān)系到系統(tǒng)對(duì)文件的讀寫效率,進(jìn)而影響整個(gè)系統(tǒng)的運(yùn)行速度。通過(guò)優(yōu)化文件系統(tǒng)相關(guān)的內(nèi)核參數(shù),可以顯著提升文件系統(tǒng)的性能,滿足不同應(yīng)用場(chǎng)景下對(duì)文件操作的高效需求。

fs.file - max 參數(shù)用于指定系統(tǒng)中所有進(jìn)程總共能夠打開(kāi)的最大文件句柄數(shù)量 。文件句柄是系統(tǒng)用于標(biāo)識(shí)和管理打開(kāi)文件的一種資源,每個(gè)進(jìn)程在進(jìn)行文件操作時(shí),都需要獲取相應(yīng)的文件句柄。在一些大規(guī)模的數(shù)據(jù)處理應(yīng)用場(chǎng)景中,例如一個(gè)數(shù)據(jù)倉(cāng)庫(kù)系統(tǒng),可能需要同時(shí)處理大量的文件,包括讀取數(shù)據(jù)文件進(jìn)行分析、寫入結(jié)果文件等操作。如果 fs.file - max 的值設(shè)置得過(guò)低,當(dāng)進(jìn)程打開(kāi)的文件句柄數(shù)量達(dá)到這個(gè)上限時(shí),后續(xù)的文件打開(kāi)操作就會(huì)失敗,導(dǎo)致應(yīng)用程序無(wú)法正常運(yùn)行。

為了確保這類應(yīng)用能夠順利進(jìn)行,我們需要根據(jù)實(shí)際的業(yè)務(wù)需求和系統(tǒng)資源情況,合理地增大 fs.file - max 的值。例如,如果系統(tǒng)的內(nèi)存資源充足,且預(yù)計(jì)在高峰時(shí)期需要同時(shí)打開(kāi)數(shù)萬(wàn)個(gè)文件句柄,那么可以將 fs.file - max 設(shè)置為一個(gè)較大的值,如 1048576。調(diào)整 fs.file - max 參數(shù)的方式是在 /etc/sysctl.conf 文件中添加或修改 “fs.file - max = [想要的值]” 這一行,然后執(zhí)行 “sysctl -p” 命令,使新的配置生效,讓系統(tǒng)能夠支持更多的文件句柄打開(kāi)操作。

fs.aio - max - nr 參數(shù)主要控制著系統(tǒng)中允許的并發(fā)異步 I/O 請(qǐng)求的最大數(shù)量 。異步 I/O 是一種高效的文件 I/O 操作方式,它允許應(yīng)用程序在發(fā)起 I/O 請(qǐng)求后,無(wú)需等待 I/O 操作完成,就可以繼續(xù)執(zhí)行其他任務(wù),從而提高系統(tǒng)的并發(fā)處理能力和整體性能。在一些對(duì) I/O 操作性能要求極高的場(chǎng)景中,如數(shù)據(jù)庫(kù)的讀寫操作、大數(shù)據(jù)的實(shí)時(shí)處理等,大量的并發(fā)異步 I/O 請(qǐng)求能夠充分利用系統(tǒng)資源,加快數(shù)據(jù)的傳輸速度。如果 fs.aio - max - nr 的值設(shè)置得過(guò)小,那么系統(tǒng)能夠同時(shí)處理的異步 I/O 請(qǐng)求數(shù)量就會(huì)受到限制,無(wú)法充分發(fā)揮異步 I/O 的優(yōu)勢(shì)。

例如,在一個(gè)高性能的數(shù)據(jù)庫(kù)服務(wù)器中,可能需要同時(shí)處理成千上萬(wàn)的并發(fā)異步 I/O 請(qǐng)求來(lái)滿足大量用戶的讀寫需求。此時(shí),將 fs.aio - max - nr 設(shè)置為一個(gè)較大的值,如 102400,能夠確保系統(tǒng)有足夠的能力處理這些并發(fā)請(qǐng)求,提高數(shù)據(jù)庫(kù)的響應(yīng)速度和吞吐量。要調(diào)整 fs.aio - max - nr 參數(shù),同樣需要編輯 /etc/sysctl.conf 文件,在其中添加或修改 “fs.aio - max - nr = [想要的值]”,之后執(zhí)行 “sysctl -p” 命令,使系統(tǒng)按照新的配置來(lái)管理并發(fā)異步 I/O 請(qǐng)求。

五、調(diào)優(yōu)案例深度剖析

5.1案例背景介紹

某在線教育平臺(tái),隨著業(yè)務(wù)的迅猛發(fā)展,用戶數(shù)量呈現(xiàn)爆發(fā)式增長(zhǎng)。原本運(yùn)行流暢的系統(tǒng),在高并發(fā)的訪問(wèn)壓力下,逐漸暴露出性能問(wèn)題。用戶反饋在觀看課程視頻時(shí),經(jīng)常出現(xiàn)卡頓現(xiàn)象,視頻加載緩慢,甚至有時(shí)會(huì)出現(xiàn)長(zhǎng)時(shí)間無(wú)法加載的情況。在進(jìn)行課程互動(dòng),如提交作業(yè)、參與討論等操作時(shí),響應(yīng)時(shí)間也明顯變長(zhǎng),嚴(yán)重影響了用戶的學(xué)習(xí)體驗(yàn)。

該平臺(tái)的服務(wù)器基于 Linux 系統(tǒng)搭建,采用了常見(jiàn)的 LAMP 架構(gòu)(Linux + Apache + MySQL + PHP)。面對(duì)日益嚴(yán)峻的性能挑戰(zhàn),平臺(tái)的技術(shù)團(tuán)隊(duì)決定深入排查問(wèn)題,并對(duì) Linux 內(nèi)核進(jìn)行性能調(diào)優(yōu),以提升系統(tǒng)的整體性能和穩(wěn)定性。

5.2問(wèn)題排查過(guò)程

技術(shù)團(tuán)隊(duì)首先對(duì)系統(tǒng)的運(yùn)行日志進(jìn)行了詳細(xì)分析。通過(guò)查看 Apache 服務(wù)器的日志,發(fā)現(xiàn)大量的請(qǐng)求超時(shí)記錄,這表明服務(wù)器在處理用戶請(qǐng)求時(shí)遇到了困難,無(wú)法及時(shí)響應(yīng)。同時(shí),MySQL 數(shù)據(jù)庫(kù)的日志中也出現(xiàn)了一些慢查詢記錄,這意味著數(shù)據(jù)庫(kù)的查詢性能可能受到了影響。

為了進(jìn)一步確定性能瓶頸所在,團(tuán)隊(duì)使用了 top 命令來(lái)實(shí)時(shí)監(jiān)控系統(tǒng)的資源使用情況。結(jié)果發(fā)現(xiàn),CPU 的使用率長(zhǎng)時(shí)間保持在高位,尤其是在用戶訪問(wèn)高峰期,幾乎達(dá)到了 100%。通過(guò)分析 top 命令的輸出,發(fā)現(xiàn)一些與視頻處理和數(shù)據(jù)庫(kù)查詢相關(guān)的進(jìn)程占用了大量的 CPU 資源。

接著,團(tuán)隊(duì)使用 iostat 命令來(lái)檢查磁盤 I/O 情況。從輸出結(jié)果可以看出,磁盤的讀寫速度較慢,尤其是在讀取視頻文件時(shí),磁盤的繁忙程度(% util)接近 100%,這表明磁盤 I/O 可能成為了系統(tǒng)性能的瓶頸。

在網(wǎng)絡(luò)方面,團(tuán)隊(duì)使用 iftop 命令來(lái)監(jiān)控網(wǎng)絡(luò)帶寬的使用情況。發(fā)現(xiàn)網(wǎng)絡(luò)帶寬在高并發(fā)情況下被大量占用,尤其是視頻傳輸所占用的帶寬較大,導(dǎo)致其他業(yè)務(wù)的網(wǎng)絡(luò)請(qǐng)求受到影響。

5.3調(diào)優(yōu)措施實(shí)施

針對(duì)排查出的問(wèn)題,技術(shù)團(tuán)隊(duì)采取了一系列針對(duì)性的調(diào)優(yōu)措施。

在 CPU 方面,對(duì)一些與視頻處理相關(guān)的進(jìn)程進(jìn)行了優(yōu)化,通過(guò)調(diào)整算法和代碼邏輯,減少了不必要的計(jì)算量。同時(shí),啟用了 CPU 的多核特性,將一些任務(wù)分配到不同的核心上并行處理,提高了 CPU 的利用率。

對(duì)于磁盤 I/O 問(wèn)題,將存儲(chǔ)視頻文件的磁盤更換為更高性能的固態(tài)硬盤(SSD),顯著提升了磁盤的讀寫速度。此外,對(duì)數(shù)據(jù)庫(kù)的查詢語(yǔ)句進(jìn)行了優(yōu)化,減少了不必要的磁盤訪問(wèn),并添加了適當(dāng)?shù)乃饕?,加快了?shù)據(jù)的檢索速度。

在網(wǎng)絡(luò)方面,對(duì)視頻傳輸進(jìn)行了優(yōu)化,采用了流媒體技術(shù),實(shí)現(xiàn)了視頻的分段傳輸和緩存,減少了網(wǎng)絡(luò)帶寬的占用。同時(shí),調(diào)整了網(wǎng)絡(luò)相關(guān)的內(nèi)核參數(shù),如增大了 net.core.somaxconn 的值,以提高服務(wù)器能夠處理的并發(fā)連接數(shù)。

5.4調(diào)優(yōu)效果展示

經(jīng)過(guò)一系列的調(diào)優(yōu)措施實(shí)施后,系統(tǒng)的性能得到了顯著提升。視頻加載速度明顯加快,卡頓現(xiàn)象幾乎消失,用戶在觀看課程視頻時(shí)能夠享受到流暢的體驗(yàn)。在課程互動(dòng)方面,提交作業(yè)、參與討論等操作的響應(yīng)時(shí)間大幅縮短,用戶能夠及時(shí)得到反饋。

從性能指標(biāo)上看,系統(tǒng)的吞吐量得到了顯著提高,在相同的時(shí)間內(nèi)能夠處理更多的用戶請(qǐng)求。系統(tǒng)延遲也明顯降低,平均響應(yīng)時(shí)間從原來(lái)的數(shù)秒縮短到了 1 秒以內(nèi)。CPU 的使用率在高并發(fā)情況下也能夠保持在合理范圍內(nèi),不再出現(xiàn)長(zhǎng)時(shí)間滿載的情況。磁盤 I/O 的性能得到了極大改善,磁盤的繁忙程度(% util)始終保持在較低水平。網(wǎng)絡(luò)帶寬的使用更加合理,各業(yè)務(wù)之間的網(wǎng)絡(luò)請(qǐng)求能夠得到有效的保障。

通過(guò)這次 Linux 內(nèi)核性能調(diào)優(yōu),該在線教育平臺(tái)成功應(yīng)對(duì)了業(yè)務(wù)量增長(zhǎng)帶來(lái)的挑戰(zhàn),為用戶提供了更加優(yōu)質(zhì)的服務(wù),同時(shí)也為平臺(tái)的持續(xù)發(fā)展奠定了堅(jiān)實(shí)的基礎(chǔ)。

責(zé)任編輯:武曉燕 來(lái)源: 深度Linux
相關(guān)推薦

2019-11-05 10:35:57

SpringBoot調(diào)優(yōu)Java

2021-01-04 15:11:57

開(kāi)發(fā) IDEA代碼

2020-09-29 07:54:05

Express 飛起

2011-04-13 10:51:58

MATLAB

2025-04-15 00:00:00

2024-06-12 12:28:23

2021-07-13 07:52:03

SQL面試COUNT(*)

2024-11-27 09:46:34

2025-03-28 03:20:00

MySQL數(shù)據(jù)庫(kù)搜索

2011-02-25 08:39:11

QFabric數(shù)據(jù)中心Juniper

2013-01-07 09:34:43

CodeLoveBAT

2022-10-09 18:14:31

訂單系統(tǒng)分庫(kù)分表

2011-03-18 11:21:48

2016-01-19 17:03:59

數(shù)據(jù)中心網(wǎng)絡(luò)華為

2019-03-25 08:05:35

Elasticsear優(yōu)化集群

2023-03-01 23:59:23

Java開(kāi)發(fā)

2011-09-27 13:25:05

Web

2024-11-25 18:00:00

C#代碼編程

2016-05-11 09:18:21

AWS云數(shù)據(jù)倉(cāng)庫(kù)Redshift

2023-11-10 18:03:04

業(yè)務(wù)場(chǎng)景SQL
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)