這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
原創文章,轉載請註明出處:伺服器非業餘研究http://blog.csdn.net/erlib 作者Sunface
為什麼我要選擇Erlang呢?
一、erlang特別適合中小團隊創業:
erlang有異常成熟、經過電信層級大規模驗證的OTP應用庫,只需要很簡單的代碼就能建立起異常穩定、容錯性強、擴充性強、高並發的伺服器架構,這也是erlang最寶貴的核心價值所在。
二、erlang是天生的並發語言:
erlang的並發特性是語言層級的,從開發伊始就採用了CSP併發模式, 以進程為單位,進程間沒有共用記憶體,變數不可變的實現方式保證了無鎖的並行存取模型,因此也是異常高效的,換句話說:你只要像平常一樣寫代碼就能並發,完全不用操心任何底層實現,你的代碼能完美的並行運行在多核伺服器上,如果你能寫出漂亮的並發層級的演算法和代碼(盡量少的順序代碼),那在32核機器上就能跑出32倍效能!!!! Go 語言的並行存取模型也是取經於Erlang,但是我認為Erlang的並行存取模型更優秀,因為進程間完全沒有共用記憶體,完全無鎖。
三、再介紹下我當初的業務需求:
一款多人線上遊戲,一個玩家走一步都要把訊息廣播給同屏的玩家,玩家聊天,戰鬥更涉及到大量的訊息廣播;如何應對?再有一個及其普通卻不太容易搞定的的需求:線上玩家列表怎麼實現?是啊,你是不是在想用哪種鎖合適?提到的兩個情境的關鍵詞是:高並發,大量廣播;可能你還會想到"鎖".
我嘗試過在.net下使用完成連接埠+TPL庫+protocol buffer來完成上面的功能,但是並沒有通過測試的檢驗,測試模型是聊天.在收發訊息方面,用戶端和伺服器一對一的收發壓力不大,但是一旦開啟廣播,壓力一下就上去了.對象的頻繁建立會導致記憶體回收,而記憶體回收會導致CPU和記憶體都飄忽不定,中間加入對象池會得到一定緩解,但是不能徹底解決問題,然後想到的就是人為幹預記憶體回收,判斷標準是什麼呢?那就是用PerformanceCounter吧,結果發現PerformanceCounter一次調用分配的記憶體相當大!最後一版的結果是:聊天室模型,一人說話廣播給所有人,300人線上能夠穩定,人數一多就開始不淡定了.這些都是經過量化分析得出的結果,使用的工具是Visual Studio2010中的Performace Profile工具.
需要解決的第二個問題就是並發加鎖,最簡單的測試模型就是線上玩家列表.這個問題同樣困擾了我很久,嘗試各種鎖,還是在拋異常,要麼就是效能的下降,問題此起彼伏.後續還要解決TCP通訊的資料格式,以及粘包等問題......
項目時間緊張,存在的風險很多,要儘快把技術方案確定下來然後去推進別的事情;但是可供選擇的方案有C++和Erlang.坦白講我和團隊的基礎如果使用C++方案,一定能搞出來,但是排錯和效能最佳化將是一個巨大的挑戰.那麼Erlang呢?從開篇引用的那段文字看,好像這就是我需要的,簡單瞭解了一下文法,還是很驚喜,由於之前對F#有過接觸,一下感覺很親切.而且我特別關注到:
優點:
1.面向並發,有成熟而且久經考驗的架構可供使用,網路部分已經經過了良好封裝
2.記憶體緩衝解決方案進程字典,前者的讀寫速度是50NS-100Ns層級的
3.對位元據解析的文法是直觀,簡單,強大(遊戲中有大量的位元據要處理
4.沒有共用記憶體! 沒有鎖!(我們在代碼中沒有過顯示使用鎖)
缺點
1.從一種語言過渡到另一種語言,會有各種不爽:
2.控制邏輯簡單只有if 和 case ,而且有if沒有else,沒有continue break goto
3.包括kernel庫和standlib庫在內,很多函數和變數的命名和傳統語言不一樣
因此我們就決定了採用erlang來重新寫一套全新的架構,事實證明當初的決定是無比正確的,一個極少需要重啟、能熱更、穩定的遊戲伺服器實在是太重要了,而且開發過程和維護是如此的快速和輕鬆,我們的團隊一致認為:從來沒有想過開發會是這麼一件愉快的事情!
既然Erlang已經被我“吹”的快飛起來了,為什麼還要使用Go?
鑒於Go語言已經婦孺皆知了,我也就不介紹了,大概說說我自己的情況,我這人沒啥其他興趣愛好,業餘時間絕大部分都花費在所謂的“程式員要不停的學習才不會落伍”上,因此在11年的時候,知道了go,斷斷續續學習了一年後,Go1.1版本出來後,發現改進很大,就開始認真研究並常年混跡在google-group及國外大牛的部落格世界中,自我感覺還可以。當然我絕對不是Go的“朝聖者”,也發現Go確實不是非常完美,具體可以參見“為什麼我要放棄Go“,此文作者的觀點我雖然不敢完全苟同,但是有些觀點還是贊同的,比如說很多Go愛好者是非常護短的,如果你敢說什麼“壞話”,就等著被查水表吧 ;)。
項目 |
nodejs |
python |
c++/ruby |
erlang |
golang |
體系成熟 |
4 |
3 |
5 |
5 |
3 |
開發效率 |
5 |
5 |
3 |
4 |
5 |
效能 |
3 |
3 |
5 |
5 |
4 |
加密發布 |
3 |
0 |
4 |
3 |
5 |
邏輯簡單 |
5 |
5 |
3 |
4 |
5 |
易學易用 |
5 |
5 |
2 |
5 |
4 |
跨平台 |
5 |
5 |
5 |
5 |
5 |
從上表中可以看出 erlang和go之間的互補性還是很好的,Go的體系成熟度等級確實還有待提高
由於Erlang和Go都是非常棒的語言,這裡就出現一個問題:二選其一還是物盡其用?經過深思熟慮後,我和團隊選擇了後者。首先,erlang的OTP寫伺服器並發架構非常之簡單、穩定且高效能,erlang的Mnesia資料庫也是很輕量:速度很快,分布式簡單,使用起來也很原生態(是Erlang標準庫支援的),所有的這些都能把程式員從繁瑣的工作中解放出來,但是,erlang也有個挺重要的問題(在不同業務情境中此問題也許很突出,也可能完全無關緊要,至少85%的情況下不算一個問題):它是虛擬機器語言,對於順序代碼的執行速度只有C的七分之一,雖然可以利用多核的優勢,但是在大型mmorpg中,訊息密集時,CPU的瓶頸還是挺明顯的,會影響玩家順暢的體驗感覺(ARPG)。
因此我就想如果邏輯這部分用Go來寫,是不是可以很好的利用這兩個語言的優點進行互補?心動不如行動,由於我們的erlang遊戲架構的藕合度還是挺低的,因此分離出來地圖伺服器,用Go重新實現了下,通過socket跟erlang架構部分進行通訊,發現效果異常之好,Go的效能、並發的原生支援再配合上erlang寫遊戲架構,在效能上已經絕不亞於C++架構,但是後者大家都懂,中關村程式員據說平均壽命50多歲,很大的一部分原因是因為這個。
以後的路怎麼走?
混合型編程會是以後的主流,因為沒有哪個語言是完美的,包括被眾多“朝聖者”所推崇的Go,如果我們能根據自己的業務情境,選對合適的語言,那不敢說事半功10倍,至少事半功倍應該是有的,所以不要被主流語言(Java,C++)禁錮了我們的世界,局限了我們的創新,如果能做到輕鬆愉快的開發,那這個世界該多美好!!