最近弄伺服器的優化,在大量機械人面前,效能問題凸現出來。我是啟用幾台亞馬孫伺服器(一年免費用,每個區隨便開一台,呵呵)去轟炸伺服器了,然後記憶體暴漲,從幾百兆漸漸的公升到1個g,然後2個g,接著3個g。可憐本人的伺服器也就3個g,當超越3g的時候,有些伺服器程序就被oom了。
一開始我覺得,是否人數太多,訊息量太大導致的?然後用一些效能檢測工具pprof之類,很多都指向protobuf(本人用的是google的protobuf做網路協議的)。然後,向寫go-protobuf的提了乙個issue,用極其爛的英語說goproto記憶體洩露啊,有沒有辦法解決一下?於是他們的回答說,我提的問題,沒有反應出記憶體洩露,只是記憶體不停的申請。不過也確實,這東西記憶體洩露,應該是不可能的,畢竟是gc語言。難道是某些東西把記憶體佔著不釋放導致?
想到這裡我突然想起來了,goroutine這東西其實挺耗記憶體的(傳說),於是乎,是否從這方面下手?原來我是每個客戶端都會分配乙個session,來維護連線的了。然後每個session會啟動3個goroutine,一是用來讀取訊息,乙個是用來傳送訊息,還有乙個是用來檢測生命週期的。當大量客戶端連線時,那goroutine就是3倍客戶端的數量啊。
golang號稱可以百萬級別併發,但goroutine也不應該無限制的建立吧,畢竟每次都向系統申請記憶體,系統記憶體總有耗盡的一天吧。那有沒有乙個池一樣的東西,可以讓goroutine可以重用,而不需要不節制的建立呢?
我們知道c#在.net 4以上有乙個所謂task的介面,它是用執行緒池的。 執行緒池目的就是執行緒可以重用,goroutine其實比執行緒輕量級,但問題是golang只是給了我們乙個keyword——go,然後就沒有然後了。咋辦?
在偶然的機會上看到一篇文章,連線如下:
蹲廁所看了半個小時,終於明白了。上面**很清楚了,我就不貼了。我說說我的體會吧。goroutine池,跟物件池不一樣。物件池是物件用完丟進池中,以便重用,那麼池一開始是沒用東西的。但goroutine池則不一樣,因為它是不可控制的,不想c#執行緒一樣,返回乙個位址,可以隨便關閉什麼的,也不能像物件那樣,先是無,然後建立,用完就放池裡面。它建立後,如果邏輯完了,它就消亡了,因此必須一直維持這個goroutine!那麼,這池就是這樣了,一開始先開著n個goroutine。但一開始沒邏輯執行啊,怎麼辦,那就讓它們阻塞!用channel!那麼怎麼執行邏輯?那就是用介面!當阻塞的goroutine塞入乙個東西,channel取出來,那麼就可以工作了。邏輯就是調乙個通用的函式!
那麼,池的作用就顯示出來了。我把session的三個需要用到goroutine的邏輯,封裝成乙個介面函式,那麼,goroutine總量就降了很多,記憶體也降下去了。
不過上面文章的池有乙個問題,就是當任務數量遠遠少於goroutine數量時,有可能會瞬間重複呼叫n次。我於是加了標誌位,當某一任務在執行時,就不讓他再進入工作了。那麼保證它只能工作一次了。
golang開發 二 安裝 Golang
當然了我們的安裝都是在vagrant裡面安裝,vagrant ssh。不用虛擬機器了,本機安裝當然也可以。go is a tool for managing go source code.usage go command arguments the commands are build compil...
golang開發 二 安裝 Golang
當然了我們的安裝都是在vagrant裡面安裝,vagrant ssh。不用虛擬機器了,本機安裝當然也可以。go is a tool for managing go source code.usage go command arguments the commands are build compil...
golang多核的使用
實際上協程只是發生在單個程序內部的,要是想充分的發掘多核cpu的潛力,還是需要多程序的支援。對於多核程式設計,go是天生支援,那麼我們在什麼情況下應該用多核心來加速程式,而在什麼情況下用單核即可呢?現在我們用一簡單的程式來說明下 定義任務佇列 varwaitgroup sync waitgroup ...