我為什么從python轉向go

應puppet大拿劉宇的邀請锌历,我去西山居運維團隊做了一個簡短分享序无,談談為什么我要將我們的項目從python轉向go乘盼。

坦白的講螟凭,在一幫python用戶面前講為什么放棄python轉而用go其實是一件壓力蠻大的事情亿虽,語言之爭就跟vim和emacs之爭一樣菱涤,是一個永恒的無解話題,稍微不注意就可能導致粉絲強烈地反擊洛勉。所以我只會從我們項目實際情況出發(fā)粘秆,來講講為什么我最終選擇了go。

為什么放棄python

首先坯认,我其實得說說為什么我們會選擇python翻擒。在我加入企業(yè)快盤團隊之前,整個項目包括更早的金山快盤都是采用python進行開發(fā)的牛哺。至于為什么這么選擇陋气,當時的架構師蔥頭告訴我,主要是因為python上手簡單引润,開發(fā)迅速巩趁。對于團隊里面大部分完全沒服務端開發(fā)經驗的同學來說,python真的是一個很好的選擇淳附。

python的簡單高效议慰,我是深有體會的。當時私有云項目也就幾個程序員奴曙,但是我們要服務多家大型企業(yè)别凹,進行定制化的開發(fā),多虧了python洽糟,我們才能快速出活炉菲。后來企業(yè)快盤掛掉之后,我們啟動輕辦公項目坤溃,自然也使用python進行了原始版本的構建拍霜。

python雖然很強大,但我們在使用的時候也碰到了一些問題薪介,主要由如下幾個方面:

  • 動態(tài)語言

    python是一門動態(tài)強類型語言祠饺。但是,仍然可能出現(xiàn)int + string這樣的運行時錯誤汁政,因為對于一個變量道偷,在寫代碼的時候缀旁,我們有時候很容易就忘記這個變量到底是啥類型的了。

    在python里面试疙,可以允許同名函數的出現(xiàn)诵棵,后一個函數會覆蓋前一個函數抠蚣,有一次我們系統(tǒng)一個很嚴重的錯誤就是因為這個導致的祝旷。

    上面說到的這些,靜態(tài)語言在編譯的時候就能幫我們檢測出來嘶窄,而不需要等到運行時出問題才知道怀跛。雖然我們有很完善的測試用例,但總有case遺漏的情況柄冲。所以每次出現(xiàn)運行時錯誤吻谋,我心里都想著如果能在編譯的時候就發(fā)現(xiàn)該多好。

  • 性能

    其實這個一直是很多人吐槽python的地方现横,但python有它適合干的事情漓拾,硬是要用python進行一些高性能模塊的開發(fā),那也有點難為它了戒祠。

    python的GIL導致無法真正的多線程骇两,大家可能會說我用多進程不就完了。但如果一些計算需要涉及到多進程交互姜盈,進程之間的通訊開銷也是不得不考慮的低千。

    無狀態(tài)的分布式處理使用多進程很方便,譬如處理http請求馏颂,我們就是在nginx后面掛載了200多個django server來處理http的,但這么多個進程自然導致整體機器負載偏高示血。

    但即使我們使用了多個django進程來處理http請求,對于一些超大量請求救拉,python仍然處理不過來难审。所以我們使用openresty,將高頻次的http請求使用lua來實現(xiàn)亿絮「婧埃可這樣又導致使用兩種開發(fā)語言,而且一些邏輯還得寫兩份不同的代碼壹无。

  • 同步網絡模型

    django的網絡是同步阻塞的葱绒,也就是說岖是,如果我們需要訪問外部的一個服務猾浦,在等待結果返回這段時間,django不能處理任何其他的邏輯(當然灯抛,多線程的除外)。如果訪問外部服務需要很長時間对嚼,那就意味著我們的整個服務幾乎在很長一段時間完全不可用夹抗。

    為了解決這個問題,我們只能不斷的多開django進程摆舟,同時需要保證所有服務都能快速的處理響應,但想想這其實是一件很不靠譜的事情忆矛。

  • 異步網絡模型

    tornado的網絡模型是異步的,這意味著它不會出現(xiàn)django那樣因為外部服務不可用導致這個服務無法響應的問題请垛。話說催训,比起django洽议,我可是非常喜歡tornado的,小巧簡單漫拭,以前還寫過幾篇深入剖析tornado的文章了亚兄。

    雖然tornado是異步的,但是python的mysql庫都不支持異步采驻,這也就意味著如果我們在tornado里面訪問數據庫审胚,我們仍然可能面臨因為數據庫問題造成的整個服務不可用。

    其實異步模型最大的問題在于代碼邏輯的割裂挑宠,因為是事件觸發(fā)的菲盾,所以我們都是通過callback進行相關處理颓影,于是代碼里面就經常出現(xiàn)干一件事情各淀,傳一個callback,然后callback里面又傳callback的情況诡挂,這樣的結果就是整個代碼邏輯非乘榻剑混亂。

    python沒有原生的協(xié)程支持璃俗,雖然可以通過gevent奴璃,greenlet這種的上patch方式來支持協(xié)程,但畢竟更改了python源碼城豁。另外苟穆,python的yield也可以進行簡單的協(xié)程模擬,但畢竟不能跨堆棧唱星,局限性很大雳旅,不知道3.x的版本有沒有改進。

  • 開發(fā)運維部署

    當我第一次使用python開發(fā)項目间聊,我是沒成功安裝上項目需要的包的攒盈,光安裝成功mysql庫就弄了很久。后來哎榴,是一位同事將他整個python目錄打包給我用型豁,我才能正常的將項目跑起來。話說尚蝌,現(xiàn)在有了docker迎变,是多么讓人幸福的一件事情。

    而部署python服務的時候飘言,我們需要在服務器上面安裝一堆的包衣形,光是這一點就讓人很麻煩,雖然可以通過puppet热凹,salt這些自動化工具解決部署問題泵喘,但相比而言泪电,靜態(tài)編譯語言只用扔一個二進制文件,可就方便太多了纪铺。

  • 代碼失控

    python非常靈活簡單相速,寫c幾十行代碼才能搞定的功能,python一行代碼沒準就能解決鲜锚。但是太簡單突诬,反而導致很多同學無法對代碼進行深層次的思考,對整個架構進行細致的考量芜繁。來了一個需求旺隙,啪啪啪,鍵盤敲完開速實現(xiàn)骏令,結果就是代碼越來越混亂蔬捷,最終導致了整個項目代碼失控。

    雖然這也有我們自身的原因榔袋,譬如沒好的代碼review機制周拐,沒有好的項目規(guī)范,但個人感覺凰兑,如果一個程序員沒經過良好的編碼訓練妥粟,用python很容易就寫出爛的代碼,因為太自由了吏够。

    當然勾给,我這里并不是說用python無法進行大型項目的開發(fā),豆瓣锅知,dropbox都是很好的例子播急,只是在我們項目中,我們的python代碼失控了喉镰。

上面提到的都是我們在實際項目中使用python遇到的問題旅择,雖然最終都解決了,但是讓我愈發(fā)的覺得侣姆,隨著項目復雜度的增大生真,流量性能壓力的增大,python并不是一個很好的選擇捺宗。

為什么選擇go

說完了python柱蟀,現(xiàn)在來說說為什么我們選擇go。其實除了python蚜厉,我們也有其他的選擇长已,java,php,lua(openresty)术瓮,但最終我們選擇了go康聂。

雖然java和php都是最好的編程語言(大家都這么爭的),但我更傾向一門更簡單的語言胞四。而openresty恬汁,雖然性能強悍,但lua仍然是動態(tài)語言辜伟,也會碰到前面說的動態(tài)語言一些問題氓侧。最后,前金山許式偉用的go导狡,前快盤架構師蔥頭也用的go约巷,所以我們很自然地選擇了go。

go并不是完美旱捧,一堆值得我們吐槽的地方独郎。

  • error,好吧廊佩,如果有語言潔癖的同學可能真的受不了go的語法囚聚,尤其是約定的最后一個返回值是error。項目里面經常會充斥這樣的代碼:

    if _, err := w.Write(data1); err != nil {
        returun err
    }
    if _, err := w.Write(data2); err != nil {
        returun err
    }
    

    難怪有個梗是對于一個需求标锄,java的程序員在寫配置的時候,go程序員已經寫了大部分代碼茁计,但是當java的程序員寫完的時候料皇,go程序員還在寫err != nil

    這方面星压,errors-are-values倒是推薦了一個不錯的解決方案践剂。

  • 包管理,go的包管理太弱了娜膘,只有一個go get逊脯,也就是如果不小心更新了一個外部庫,很有可能就導致現(xiàn)有的代碼編譯不過了竣贪。雖然已經有很多開源方案军洼,譬如godep以及現(xiàn)在才出來的gb等,但畢竟不是官方的演怎。貌似google也是通過vendor機制來管理第三方庫的匕争。希望go 1.5或者之后的版本能好好處理下這個問題。

  • GC爷耀,java的GC發(fā)展20年了甘桑,go才這么點時間,gc鐵定不完善。所以我們仍然不能隨心所欲的寫代碼跑杭,不然在大請求量下面gc可能會卡頓整個服務铆帽。所以有時候,該用對象池德谅,內存池的一定要用锄贼,雖然代碼丑了點,但好歹性能上去了女阀。

  • 泛型宅荤,雖然go有inteface,但泛型的缺失會讓我們在實現(xiàn)一個功能的時候寫大量的重復代碼浸策,譬如int32和int64類型的sort冯键,我們得為分別寫兩套代碼,好冗余庸汗。go 1.4之后有了go generate的支持惫确,但這種的仍然需要自己根據go的AST庫來手動寫相關的parser,難度也挺大的蚯舱。雖然也有很多開源的generate實現(xiàn)改化,但畢竟不是官方的。

當然還有很多值得吐槽的地方枉昏,就不一一列舉了陈肛,但是go仍舊有它的優(yōu)勢。

  • 靜態(tài)語言兄裂,強類型句旱。靜態(tài)編譯能幫我們檢查出來大量的錯誤,go的強類型甚至變態(tài)到不支持隱式的類型轉換晰奖。雖然寫代碼感覺很別扭谈撒,但減少了犯錯的可能。
  • gofmt匾南,應該這是我知道的第一個官方提供統(tǒng)一格式化代碼工具的語言了啃匿。有了gofmt,大家的代碼長一個樣了蛆楞,也就沒有花括號到底放到結尾還是新開一行這種蛋疼的代碼風格討論了溯乒。因為大家的代碼風格一樣,所以看go的代碼很容易臊岸。
  • 天生的并行支持橙数,因為goroutine以及channel,用go寫分布式應用帅戒,寫并發(fā)程序異常的容易灯帮。沒有了蛋疼的callback導致的代碼邏輯割裂崖技,代碼邏輯都是順序的。
  • 性能钟哥,go的性能可能趕不上c迎献,c++以及openresty,但真的也挺強悍的腻贰。在我們的項目中吁恍,現(xiàn)在單機就部署了一個go的進程,就完全能夠勝任以前200個python進程干的事情播演,而且CPU和MEM占用更低冀瓦。
  • 運維部署,直接編譯成二進制写烤,扔到服務器上面就成翼闽,比python需要安裝一堆的環(huán)境那是簡單的太多了。當然洲炊,如果有cgo感局,我們也需要將對應的動態(tài)庫給扔過去。
  • 開發(fā)效率暂衡,雖然go是靜態(tài)語言询微,但我個人感覺開發(fā)效率真的挺高,直覺上面跟python不相上下狂巢。對于我個人來說撑毛,最好的例子就是我用go快速開發(fā)了非常多的開源組件,譬如ledisdb隧膘,go-mysql等代态,而這些最開始的版本都是在很短的時間里面完成的。對于我們項目來說疹吃,我們也是用go在一個月就重構完成了第一個版本,并發(fā)布西雀。

實際項目中一些Go Tips

到現(xiàn)在為止萨驶,我們幾乎所有的服務端項目都已經轉向go,當然在使用的時候也遇到了一些問題艇肴,列出來算是經驗分享吧腔呜。

  • godep,我們使用godep進行第三方庫管理再悼,但是godep我碰到的最大的坑就是build tag問題核畴,如果一個文件有build tag,godep很有可能就會忽略這個文件冲九。
  • IO deadline谤草,如果能自己在應用層處理的都自己處理跟束,go的deadline內部是timer來控制,但timer內部采用一個array來實現(xiàn)的heap丑孩,全局共用一個鎖冀宴,如果大并發(fā)量,并且timer數量過多温学,timeout變動太頻繁略贮,很容易就引起性能問題。
  • GC仗岖,這個前面也說了卫枝,多用內存池,對象池站蝠,另外叔锐,我還發(fā)現(xiàn),如果對象的生命周期跟goroutine一致紧帕,對性能的提升也不錯盔然,也在go的group問過相關問題,大家猜測可能是因為一些對象其實是在goroutine的8k棧上面分配的是嗜,所以一起回收沒有額外GC了愈案。
  • Go gob,如果要做RPC服務鹅搪,gob并不是一個很好的選擇站绪,首先就跟python的pickle不通用,然后為了做不同系統(tǒng)的數據傳入丽柿,任何包都必須帶上類型的詳細信息恢准,size太大。go里面現(xiàn)在還沒一套官方的RPC方案甫题,gRPC貌似有上位的可能馁筐。

總結

雖然我現(xiàn)在選擇了go,但是并不表示我以后不會嘗試其他的語言坠非。語言沒有好壞敏沉,能幫我解決問題的就是好語言。但至少在很長的一段時間炎码,我都會用go來進行開發(fā)盟迟。Let' go!!!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市潦闲,隨后出現(xiàn)的幾起案子攒菠,更是在濱河造成了極大的恐慌,老刑警劉巖歉闰,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辖众,死亡現(xiàn)場離奇詭異卓起,居然都是意外死亡,警方通過查閱死者的電腦和手機赵辕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門既绩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人还惠,你說我怎么就攤上這事饲握。” “怎么了蚕键?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵救欧,是天一觀的道長。 經常有香客問我锣光,道長笆怠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任誊爹,我火速辦了婚禮蹬刷,結果婚禮上,老公的妹妹穿的比我還像新娘频丘。我一直安慰自己办成,他們只是感情好,可當我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布搂漠。 她就那樣靜靜地躺著迂卢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪桐汤。 梳的紋絲不亂的頭發(fā)上而克,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天,我揣著相機與錄音怔毛,去河邊找鬼员萍。 笑死,一個胖子當著我的面吹牛拣度,可吹牛的內容都是我干的充活。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼蜡娶,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了映穗?” 一聲冷哼從身側響起窖张,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蚁滋,沒想到半個月后宿接,有當地人在樹林里發(fā)現(xiàn)了一具尸體赘淮,經...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年睦霎,在試婚紗的時候發(fā)現(xiàn)自己被綠了梢卸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡副女,死狀恐怖蛤高,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情碑幅,我是刑警寧澤戴陡,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站沟涨,受9級特大地震影響恤批,放射性物質發(fā)生泄漏。R本人自食惡果不足惜裹赴,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一喜庞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧棋返,春花似錦延都、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至酵颁,卻和暖如春嫉你,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背躏惋。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工幽污, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人簿姨。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓距误,卻偏偏與公主長得像,于是被迫代替她去往敵國和親扁位。 傳聞我的和親對象是個殘疾皇子准潭,可洞房花燭夜當晚...
    茶點故事閱讀 45,107評論 2 356

推薦閱讀更多精彩內容