看過其它人作的優化。我發現有兩個最基本的優化技術老是被人所忽略。 注意,這兩個技術並非避免時機不成熟的優化。並非把冒泡排序變成快速排序(算法優化)。也不是語言或是編譯器的優化。也不是把 i*4寫成i<<2 的優化。 這兩個技術是:php
使用這兩個技術的人將會成功地寫出運行快的代碼,不會使用這兩個技術的人則不行。下面讓我爲你細細道來。html
咱們知道,程序運行時的90%的時間是用在了10%的代碼上。我發現這並不許確。一次又一次地,我發現,幾乎全部的程序會在1%的代碼上花了99%的運行時間。可是,是哪一個1%?一個好的Profiler能夠告訴你這個答案。就算咱們須要使用100個小時在這1%的代碼上進行優化,也比使用100個小時在其它99%的代碼上優化產生的效益要高得多得多。 問題是什麼?人們不用profiler?不是。我工做過的一個地方使用了一個華麗而奢侈的Profiler,可是自從購買這個Profiler後,它的包裝3年來仍是那麼的暫新。爲何人們不用?我真的不知道。有一次,我和個人同事去了一個負載過大的交易所,我同事堅持說他知道哪裏是瓶頸,畢竟,他是一個頗有經驗的專家。最終,我把個人Profiler在他的項目上運行了一下,咱們發現那個瓶頸徹底在一個意想不到的地方。 就像是賽車同樣。團隊是贏在傳感器和日誌上,這些東西提供了全部的一切。你能夠調整一下賽車手的褲子以讓其在比勝過程中更舒服,可是這不會讓你贏得比賽,也不會讓你更有競爭力。若是你不知道你的速度上不去是由於引擎、排氣裝置、空體動力學、輪胎氣壓,或是賽車手,那麼你將沒法獲勝。編程爲何會不一樣呢?只要沒有測量,你就永遠沒法進步。 這個世界上有太多可使用的Profiler了。隨便找一個你就能夠看到你的函數的調用層次,調用的次數,之前每條代碼的時間分解表(甚至能夠到彙編級)。我看過太多的程序員迴避使用Profiler,而是把時間花在那些無用的,錯誤的方向上的「優化」,而被其競爭對手所羞辱。(譯者陳皓注:使用Profiler時,重點須要關注:1)花時間多的函數以優化其算法,2)調用次數巨多的函數——若是一個函數每秒被調用300K次,你只須要優化出0.001毫秒,那也是至關大的優化。這就是做者所謂的1%的代碼佔用了99%的CPU時間)node
幾年前,我有一個同事,Mary Bailey,她在華盛頓大學教矯正代數(remedial algebra),有一次,她在黑板上寫下: x + 3 = 5
而後問他的學生「求解x」,而後學生們不知道答案。因而她寫下: __ + 3 = 5
而後,再問學生「填空」,全部的學生均可以回答了。未知數x就像是一個有魔法的字母讓你們都在想「x意味着代數,而我沒有學過代數,因此我就不知道這個怎麼作」。 彙編程序就是編程世界的代數。若是某人問我「inline函數是否被編譯器展開了?」或是問我「若是我寫下i*4,編譯器會把其優化爲左移位操做嗎?」。這個時候,我都會建議他們看看編譯器的彙編碼。這樣的回答是否是很粗暴和無用?一般,在我這樣回答了提問者後,提問都一般都會說,對不起,我不知道什麼是彙編!甚至C++的專家都會這麼回答。 彙編語言是最簡單的編程語言了(就算是和C++相比也是這樣的),如:mysql
ADD ESI,x
linux
就是(C風格的代碼)ios
ESI += x;
git
而:程序員
CALL foo
web
則是:算法
foo();
細節由於CPU的種類而不一樣,但這就是其如何工做的。有時候,咱們甚至都不須要細節,只須要看看彙編碼的長啥樣,而後和源代碼比一比,你就能夠知道彙編代碼不少不少了。 那麼,這又如何幫助代碼優化?舉個例子,我幾年前認識一個程序員認爲他應該去發現一個新的更快的算法。他有一個benchmark來證實這個算法,而且其寫了一篇很是漂亮的文章關於他的這個算法。可是,有人看了一下其原來算法以及新算法的彙編,發現了他的改進版本的算法容許其編譯器把兩個除法操做變成了一個。這和算法真的沒有什麼關係。咱們知道除法操做是一個很昂貴的操做,而且在其算法中,這倆個除法操做還在一個內嵌循環中,因此,他的改進版的算法固然要快一些。但,只須要在原來的算法上作一點點小的改動——使用一個除法操做,那麼其原來的算法將會和新的同樣快。而他的新發現什麼也不是。 下一個例子,一個D用戶張貼了一個 benchmark 來顯示 dmd (Digital Mars D 編譯器)在整型算法上的很糟糕,而ldc (LLVM D 編譯器) 就好不少了。對於這樣的結果,其至關的有意見。我迅速地看了一下彙編,發現兩個編譯器編譯出來至關的一致,並無什麼明顯的東西要對2:1這麼大的不一樣而負責。可是咱們看到有一個對long型整數的除法,這個除法調用了運行庫。而這個庫成爲消耗時間的殺手,其它全部的加減法都沒有速度上的影響。出乎意料地,benchmark 和算法代碼生成一點關係也沒有,徹底就是long型整數的除法的問題。這暴露了在dmd的運行庫中的long型除法的實現不好。修正後就能夠提升速度。因此,這和編譯器沒有什麼關係,可是若是不看彙編,你將沒法發現這一切。 查看彙編代碼常常會給你一些意想不到的東西讓你知道爲何程序的性能是那樣。一些意想不到的函數調用,預料不到的自傲,以及不該該存在的東西,等等其實全部的一切。但也不須要成爲一個彙編代碼的黑客才能乾的事。
若是你以爲須要程序有更好的執行速度,那麼,最基本的方法就是使用一個profiler和願意去查看一下其彙編代碼以找到程序的瓶頸。只有找到了程序的瓶頸,此時纔是真正在思考如何去改進的時候,好比思考一個更好的算法,使用更快的語言優化,等等。 常規的作法是制勝法寶是挑選一個最佳的算法而不是進行微優化。雖然這種作法是無可異議的,可是有兩件事情是學校沒有教給你而須要你重點注意的。第一個也是最重要的,若是你優化的算法沒沒有參與到你程序性能中的算法,那麼你優化他只是在浪費時間和精力,而且還轉移了你的注意力讓你錯過了應該要去優化的部分。第二點,算法的性能總和處理的數據密切相關的,就算是冒泡排序有那麼多的笑柄,可是若是其處理的數據基本是排好序的,只有其中幾個數據是未排序的,那麼冒泡排序也是全部排序算法裏性能最好的。因此,擔憂沒有使用好的算法而不去測量,只會浪費時間,不管是你的仍是計算機的。 就好像賽車零件的訂購速底是不會讓你更靠進冠軍(就算是你正確安裝零件也不會),沒有Profiler,你不會知道問題在哪裏,不去看彙編,你可能知道問題所在,但你每每不知道爲何
今天,想從一些技術細節上談談性能優化,主要是一些代碼級別的技術和方法。本文的東西是個人一些經驗和知識,並不必定全對,但願你們指正和補充。
在開始這篇文章以前,你們能夠移步去看一下酷殼之前發表的《代碼優化概要》,這篇文章基本上告訴你——要進行優化,先得找到性能瓶頸! 可是在講如何定位系統性能瓶勁以前,請讓我講一下系統性能的定義和測試,由於沒有這兩件事,後面的定位和優化無從談起。
讓咱們先來講說如何什麼是系統性能。這個定義很是關鍵,若是咱們不清楚什麼是系統性能,那麼咱們將沒法定位之。我見過不少朋友會以爲這很容易,可是仔細一問,其實他們並無一個比較系統的方法,因此,在這裏我想告訴你們如何系統地來定位性能。 整體來講,系統性能就是兩個事:
通常來講,一個系統的性能受到這兩個條件的約束,缺一不可。好比,個人系統能夠頂得住一百萬的併發,可是系統的延遲是2分鐘以上,那麼,這個一百萬的負載毫無心義。系統延遲很短,可是吞吐量很低,一樣沒有意義。因此,一個好的系統的性能測試必然受到這兩個條件的同時做用。 有經驗的朋友必定知道,這兩個東西的一些關係:
通過上述的說明,咱們知道要測試系統的性能,須要咱們收集系統的Throughput和Latency這兩個值。
再多說一些,
性能測試有不少很復要的東西,好比:burst test等。 這裏不能一一詳述,這裏只說了一些和性能調優相關的東西。總之,性能測試是一細活和累活。
有了上面的鋪墊,咱們就能夠測試到到系統的性能了,再調優以前,咱們先來講說如何找到性能的瓶頸。我見過不少朋友會以爲這很容易,可是仔細一問,其實他們並無一個比較系統的方法。
3.1)查看操做系統負載
首先,當咱們系統有問題的時候,咱們不要急於去調查咱們代碼,這個毫無心義。咱們首要須要看的是操做系統的報告。看看操做系統的CPU利用率,看看內存使用率,看看操做系統的IO,還有網絡的IO,網絡連接數,等等。Windows下的perfmon是一個很不錯的工具,Linux下也有不少相關的命令和工具,好比:SystemTap,LatencyTOP,vmstat, sar, iostat, top, tcpdump等等 。經過觀察這些數據,咱們就能夠知道咱們的軟件的性能基本上出在哪裏。好比:
1)先看CPU利用率,若是CPU利用率不高,可是系統的Throughput和Latency上不去了,這說明咱們的程序並無忙於計算,而是忙於別的一些事,好比IO。(另外,CPU的利用率還要看內核態的和用戶態的,內核態的一上去了,整個系統的性能就下來了。而對於多核CPU來講,CPU 0 是至關關鍵的,若是CPU 0的負載高,那麼會影響其它核的性能,由於CPU各核間是須要有調度的,這靠CPU0完成)
2)而後,咱們能夠看一下IO大不大,IO和CPU通常是反着來的,CPU利用率高則IO不大,IO大則CPU就小。關於IO,咱們要看三個事,一個是磁盤文件IO,一個是驅動程序的IO(如:網卡),一個是內存換頁率。這三個事都會影響系統性能。
3)而後,查看一下網絡帶寬使用狀況,在Linux下,你可使用iftop, iptraf, ntop, tcpdump這些命令來查看。或是用Wireshark來查看。
4)若是CPU不高,IO不高,內存使用不高,網絡帶寬使用不高。可是系統的性能上不去。這說明你的程序有問題,好比,你的程序被阻塞了。多是由於等那個鎖,多是由於等某個資源,或者是在切換上下文。
經過了解操做系統的性能,咱們才知道性能的問題,好比:帶寬不夠,內存不夠,TCP緩衝區不夠,等等,不少時候,不須要調整程序的,只須要調整一下硬件或操做系統的配置就能夠了。
3.2)使用Profiler測試
接下來,咱們須要使用性能檢測工具,也就是使用某個Profiler來差看一下咱們程序的運行性能。如:Java的JProfiler/TPTP/CodePro Profiler,GNU的gprof,IBM的PurifyPlus,Intel的VTune,AMD的CodeAnalyst,還有Linux下的OProfile/perf,後面兩個可讓你對你的代碼優化到CPU的微指令級別,若是你關心CPU的L1/L2的緩存調優,那麼你須要考慮一下使用VTune。 使用這些Profiler工具,可讓你程序中各個模塊函數甚至指令的不少東西,如:運行的時間 ,調用的次數,CPU的利用率,等等。這些東西對咱們來講很是有用。
咱們重點觀察運行時間最多,調用次數最多的那些函數和指令。這裏注意一下,對於調用次數多可是時間很短的函數,你可能只須要輕微優化一下,你的性能就上去了(好比:某函數一秒種被調用100萬次,你想一想若是你讓這個函數提升0.01毫秒的時間 ,這會給你帶來多大的性能)
使用Profiler有個問題咱們須要注意一下,由於Profiler會讓你的程序運行的性能變低,像PurifyPlus這樣的工具會在你的代碼中插入不少代碼,會致使你的程序運行效率變低,從而沒發測試出在高吞吐量下的系統的性能,對此,通常有兩個方法來定位系統瓶頸:
1)在你的代碼中本身作統計,使用微秒級的計時器和函數調用計算器,每隔10秒把統計log到文件中。
2)分段註釋你的代碼塊,讓一些函數空轉,作Hard Code的Mock,而後再測試一下系統的Throughput和Latency是否有質的變化,若是有,那麼被註釋的函數就是性能瓶頸,再在這個函數體內註釋代碼,直到找到最耗性能的語句。
最後再說一點,對於性能測試,不一樣的Throughput會出現不一樣的測試結果,不一樣的測試數據也會有不一樣的測試結果。因此,用於性能測試的數據很是重要,性能測試中,咱們須要觀測試不一樣Throughput的結果。
下面這些東西是我所經歷過的一些問題,也許並不全,也許並不對,你們能夠補充指正,我純屬拋磚引玉。關於系統架構方面的性能調優,你們可移步看一下《由12306.cn談談網站性能技術》,關於Web方面的一些性能調優的東西,你們能夠看看《Web開發中須要瞭解的東西》一文中的性能一章。我在這裏就再也不說設計和架構上的東西了。
通常來講,性能優化也就是下面的幾個策略:
總之,根據2:8原則來講,20%的代碼耗了你80%的性能,找到那20%的代碼,你就能夠優化那80%的性能。 下面的一些東西都是個人一些經驗,我只例舉了一些最有價值的性能調優的的方法,供你參考,也歡迎補充。
4.1)算法調優。算法很是重要,好的算法會有更好的性能。舉幾個我經歷過的項目的例子,你們能夠感受一下。
4.2)代碼調優。從個人經驗上來講,代碼上的調優有下面這幾點:
4.3)網絡調優
關於網絡調優,尤爲是TCP Tuning(你能夠以這兩個關鍵詞在網上找到不少文章),這裏面有不少不少東西能夠說。看看Linux下TCP/IP的那麼多參數就知道了(順便說一下,你也許不喜歡Linux,可是你不可否認Linux給咱們了不少能夠進行內核調優的權力)。強烈建議你們看看《TCP/IP 詳解 卷1:協議》這本書。我在這裏只講一些概念上的東西。
A) TCP調優
咱們知道TCP連接是有不少開銷的,一個是會佔用文件描述符,另外一個是會開緩存,通常來講一個系統能夠支持的TCP連接數是有限的,咱們須要清楚地認識到TCP連接對系統的開銷是很大的。正是由於TCP是耗資源的,因此,不少攻擊都是讓你係統上出現大量的TCP連接,把你的系統資源耗盡。好比著名的SYNC Flood攻擊。
因此,咱們要注意配置KeepAlive參數,這個參數的意思是定義一個時間,若是連接上沒有數據傳輸,系統會在這個時間發一個包,若是沒有收到迴應,那麼TCP就認爲連接斷了,而後就會把連接關閉,這樣能夠回收系統資源開銷。(注:HTTP層上也有KeepAlive參數)對於像HTTP這樣的短連接,設置一個1-2分鐘的keepalive很是重要。這能夠在必定程度上防止DoS攻擊。有下面幾個參數(下面這些參數的值僅供參考):
1 2 3 |
|
對於TCP的TIME_WAIT這個狀態,主動關閉的一方進入TIME_WAIT狀態,TIME_WAIT狀態將持續2個MSL(Max Segment Lifetime),默認爲4分鐘,TIME_WAIT狀態下的資源不能回收。有大量的TIME_WAIT連接的狀況通常是在HTTP服務器上。對此,有兩個參數須要注意,
1 2 |
|
前者表示重用TIME_WAIT,後者表示回收TIME_WAIT的資源。
TCP還有一個重要的概念叫RWIN(TCP Receive Window Size),這個東西的意思是,我一個TCP連接在沒有向Sender發出ack時能夠接收到的最大的數據包。爲何這個很重要?由於若是Sender沒有收到Receiver發過來ack,Sender就會中止發送數據並會等一段時間,若是超時,那麼就會重傳。這就是爲何TCP連接是可靠連接的緣由。重傳還不是最嚴重的,若是有丟包發生的話,TCP的帶寬使用率會立刻受到影響(會盲目減半),再丟包,再減半,而後若是不丟包了,就逐步恢復。相關參數以下:
1 2 3 4 |
|
通常來講,理論上的RWIN應該設置成:吞吐量 * 迴路時間。Sender端的buffer應該和RWIN有同樣的大小,由於Sender端發送完數據後要等Receiver端確認,若是網絡延時很大,buffer太小了,確認的次數就會多,因而性能就不高,對網絡的利用率也就不高了。也就是說,對於延遲大的網絡,咱們須要大的buffer,這樣能夠少一點ack,多一些數據,對於響應快一點的網絡,能夠少一些buffer。由於,若是有丟包(沒有收到ack),buffer過大可能會有問題,由於這會讓TCP重傳全部的數據,反而影響網絡性能。(固然,網絡差的狀況下,就別玩什麼高性能了) 因此,高性能的網絡重要的是要讓網絡丟包率很是很是地小(基本上是用在LAN裏),若是網絡基本是可信的,這樣用大一點的buffer會有更好的網絡傳輸性能(來來回回太多太影響性能了)。
另外,咱們想想,若是網絡質量很是好,基本不丟包,而業務上咱們不怕偶爾丟幾個包,若是是這樣的話,那麼,咱們爲何不用速度更快的UDP呢?你想過這個問題了嗎?
B)UDP調優
說到UDP的調優,有一些事我想重點說同樣,那就是MTU——最大傳輸單元(其實這對TCP也同樣,由於這是鏈路層上的東西)。所謂最大傳輸單元,你能夠想像成是公路上的公交車,假設一個公交車能夠最多坐70人,帶寬就像是公路的車道數同樣,若是一條路上最多能夠容下100輛公交車,那意味着我最多能夠運送7000人,可是若是公交車坐不滿,好比平均每輛車只有20人,那麼我只運送了2000人,因而我公路資源(帶寬資源)就被浪費了。 因此,咱們對於一個UDP的包,咱們要儘可能地讓他大到MTU的最大尺寸再往網絡上傳,這樣能夠最大化帶寬利用率。對於這個MTU,以太網是1500字節,光纖是4352字節,802.11無線網是7981。可是,當咱們用TCP/UDP發包的時候,咱們的有效負載Payload要低於這個值,由於IP協議會加上20個字節,UDP會加上8個字節(TCP加的更多),因此,通常來講,你的一個UDP包的最大應該是1500-8-20=1472,這是你的數據的大小。固然,若是你用光纖的話, 這個值就能夠更大一些。(順便說一下,對於某些NB的千光以態網網卡來講,在網卡上,網卡硬件若是發現你的包的大小超過了MTU,其會幫你作fragment,到了目標端又會幫你作重組,這就不須要你在程序中處理了)
再多說一下,使用Socket編程的時候,你可使用setsockopt() 設置 SO_SNDBUF/SO_RCVBUF 的大小,TTL和KeepAlive這些關鍵的設置,固然,還有不少,具體你能夠查看一下Socket的手冊。
最後說一點,UDP還有一個最大的好處是multi-cast多播,這個技術對於你須要在內網裏通知多臺結點時很是方便和高效。並且,多播這種技術對於機會的水平擴展(須要增長機器來偵聽多播信息)也頗有利。
C)網卡調優
對於網卡,咱們也是能夠調優的,這對於千兆以及網網卡很是必要,在Linux下,咱們能夠用ifconfig查看網上的統計信息,若是咱們看到overrun上有數據,咱們就可能須要調整一下txqueuelen的尺寸(通常默認爲1000),咱們能夠調大一些,如:ifconfig eth0 txqueuelen 5000。Linux下還有一個命令叫:ethtool能夠用於設置網卡的緩衝區大小。在Windows下,咱們能夠在網卡適配器中的高級選項卡中調整相關的參數(如:Receive Buffers, Transmit Buffer等,不一樣的網卡有不一樣的參數)。把Buffer調大對於須要大數據量的網絡傳輸很是有效。
D)其它網絡性能
關於多路複用技術,也就是用一個線程來管理全部的TCP連接,有三個系統調用要重點注意:一個是select,這個系統調用只支持上限1024個連接,第二個是poll,其能夠突破1024的限制,可是select和poll本質上是使用的輪詢機制,輪詢機制在連接多的時候性能不好,因主是O(n)的算法,因此,epoll出現了,epoll是操做系統內核支持的,僅當在連接活躍時,操做系統纔會callback,這是由操做系統通知觸發的,但其只有Linux Kernel 2.6之後才支持(準確說是2.5.44中引入的),固然,若是全部的連接都是活躍的,過多的使用epoll_ctl可能會比輪詢的方式還影響性能,不過影響的不大。
另外,關於一些和DNS Lookup的系統調用要當心,好比:gethostbyaddr/gethostbyname,這個函數可能會至關的費時,由於其要到網絡上去找域名,由於DNS的遞歸查詢,會致使嚴重超時,而又不能經過設置什麼參數來設置time out,對此你能夠經過配置hosts文件來加快速度,或是本身在內存中管理對應表,在程序啓動時查好,而不要在運行時每次都查。另外,在多線程下面,gethostbyname會一個更嚴重的問題,就是若是有一個線程的gethostbyname發生阻塞,其它線程都會在gethostbyname處發生阻塞,這個比較變態,要當心。(你能夠試試GNU的gethostbyname_r(),這個的性能要好一些) 這種到網上找信息的東西不少,好比,若是你的Linux使用了NIS,或是NFS,某些用戶或文件相關的系統調用就很慢,因此要當心。
4.4)系統調優
A)I/O模型
前面說到過select/poll/epoll這三個系統調用,咱們都知道,Unix/Linux下把全部的設備都當成文件來進行I/O,因此,那三個操做更應該算是I/O相關的系統調用。說到 I/O模型,這對於咱們的I/O性能至關重要,咱們知道,Unix/Linux經典的I/O方式是(關於Linux下的I/O模型,你們能夠讀一下這篇文章《使用異步I/O大大提升性能》):
第一種,同步阻塞式I/O,這個不說了。
第二種,同步無阻塞方式。其經過fctnl設置 O_NONBLOCK 來完成。
第三種,對於select/poll/epoll這三個是I/O不阻塞,可是在事件上阻塞,算是:I/O異步,事件同步的調用。
第四種,AIO方式。這種I/O 模型是一種處理與 I/O 並行的模型。I/O請求會當即返回,說明請求已經成功發起了。在後臺完成I/O操做時,嚮應用程序發起通知,通知有兩種方式:一種是產生一個信號,另外一種是執行一個基於線程的回調函數來完成此次 I/O 處理過程。
第四種由於沒有任何的阻塞,不管是I/O上,仍是事件通知上,因此,其可讓你充分地利用CPU,比起第二種同步無阻塞好處就是,第二種要你一遍一遍地去輪詢。Nginx之所因此高效,是其使用了epoll和AIO的方式來進行I/O的。
再說一下Windows下的I/O模型,
a)一個是WriteFile系統調用,這個系統調用能夠是同步阻塞的,也能夠是同步無阻塞的,關於看文件是否是以Overlapped打開的。關於同步無阻塞,須要設置其最後一個參數Overlapped,微軟叫Overlapped I/O,你須要WaitForSingleObject才能知道有沒有寫完成。這個系統調用的性能可想而知。
b)另外一個叫WriteFileEx的系統調用,其能夠實現異步I/O,並可讓你傳入一個callback函數,等I/O結束後回調之, 可是這個回調的過程Windows是把callback函數放到了APC(Asynchronous Procedure Calls)的隊列中,而後,只用當應用程序當前線程成爲可被通知狀態(Alterable)時,纔會被回調。只有當你的線程使用了這幾個函數時WaitForSingleObjectEx, WaitForMultipleObjectsEx, MsgWaitForMultipleObjectsEx, SignalObjectAndWait 和 SleepEx,線程纔會成爲Alterable狀態。可見,這個模型,仍是有wait,因此性能也不高。
c)而後是IOCP – IO Completion Port,IOCP會把I/O的結果放在一個隊列中,可是,偵聽這個隊列的不是主線程,而是專門來幹這個事的一個或多個線程去幹(老的平臺要你本身建立線程,新的平臺是你能夠建立一個線程池)。IOCP是一個線程池模型。這個和Linux下的AIO模型比較類似,可是實現方式和使用方式徹底不同。
固然,真正提升I/O性能方式是把和外設的I/O的次數降到最低,最好沒有,因此,對於讀來講,內存cache一般能夠從質上提高性能,由於內存比外設快太多了。對於寫來講,cache住要寫的數據,少寫幾回,可是cache帶來的問題就是實時性的問題,也就是latency會變大,咱們須要在寫的次數上和相應上作權衡。
B)多核CPU調優
關於CPU的多核技術,咱們知道,CPU0是很關鍵的,若是0號CPU被用得過狠的話,別的CPU性能也會降低,由於CPU0是有調整功能的,因此,咱們不能任由操做系統負載均衡,由於咱們本身更瞭解本身的程序,因此,咱們能夠手動地爲其分配CPU核,而不會過多地佔用CPU0,或是讓咱們關鍵進程和一堆別的進程擠在一塊兒。
多核CPU還有一個技術叫NUMA技術(Non-Uniform Memory Access)。傳統的多核運算是使用SMP(Symmetric Multi-Processor )模式,多個處理器共享一個集中的存儲器和I/O總線。因而就會出現一致存儲器訪問的問題,一致性一般意味着性能問題。NUMA模式下,處理器被劃分紅多個node, 每一個node有本身的本地存儲器空間。關於NUMA的一些技術細節,你能夠查看一下這篇文章《Linux 的 NUMA 技術》,在Linux下,對NUMA調優的命令是:numactl 。以下面的命令:(指定命令「myprogram arg1 arg2」運行在node 0 上,其內存分配在node 0 和 1上)
1 |
|
固然,上面這個命令並很差,由於內存跨越了兩個node,這很是很差。最好的方式是隻讓程序訪問和本身運行同樣的node,如:
1 |
|
C)文件系統調優
關於文件系統,由於文件系統也是有cache的,因此,爲了讓文件系統有最大的性能。首要的事情就是分配足夠大的內存,這個很是關鍵,在Linux下可使用free命令來查看 free/used/buffers/cached,理想來講,buffers和cached應該有40%左右。而後是一個快速的硬盤控制器,SCSI會好不少。最快的是Intel SSD 固態硬盤,速度超快,可是寫次數有限。
接下來,咱們就能夠調優文件系統配置了,對於Linux的Ext3/4來講,幾乎在全部狀況下都有所幫助的一個參數是關閉文件系統訪問時間,在/etc/fstab下看看你的文件系統 有沒有noatime參數(通常來講應該有),還有一個是dealloc,它可讓系統在最後時刻決定寫入文件發生時使用哪一個塊,可優化這個寫入程序。還要注間一下三種日誌模式:data=journal、data=ordered和data=writeback。默認設置data=ordered提供性能和防禦之間的最佳平衡。
固然,對於這些來講,ext4的默認設置基本上是最佳優化了。
這裏介紹一個Linux下的查看I/O的命令—— iotop,可讓你看到各進程的磁盤讀寫的負載狀況。
其它還有一些關於NFS、XFS的調優,你們能夠上google搜索一些相關優化的文章看看。關於各文件系統,你們能夠看一下這篇文章——《Linux日誌文件系統及性能分析》
4.5)數據庫調優
數據庫調優並非個人強項,我就僅用我很是有限的知識說上一些吧。注意,下面的這些東西並不必定正確,由於在不一樣的業務場景,不一樣的數據庫設計下可能會獲得徹底相反的結論,因此,我僅在這裏作一些通常性的說明,具體問題還要具體分析。
A)數據庫引擎調優
我對數據庫引擎不是熟,可是有幾個事情我以爲是必定要去了解的。
B)SQL語句優化
關於SQL語句的優化,首先也是要使用工具,好比:MySQL SQL Query Analyzer,Oracle SQL Performance Analyzer,或是微軟SQL Query Analyzer,基本上來講,全部的RMDB都會有這樣的工具,來讓你查看你的應用中的SQL的性能問題。 還可使用explain來看看SQL語句最終Execution Plan會是什麼樣的。
還有一點很重要,數據庫的各類操做須要大量的內存,因此服務器的內存要夠,優其應對那些多表查詢的SQL語句,那是至關的耗內存。
下面我根據我有限的數據庫SQL的知識說幾個會有性能問題的SQL:
仍是那句話,具體要看什麼樣的數據,什麼樣的SQL語句,你才知道用哪一種方法是最好的。
關於SQL語句的優化,網上有不少文章, 不一樣的數據庫引擎有不一樣的優化技巧,正如本站之前轉發的《MySQL性能優化的最佳20+條經驗》