談談 Golang, 以及我走的一些彎路
在某乎上看到了這個問題,還是挺有意思的. 撕哪個語言最好,幾乎是工程師當中最好的引戰題目了. 今天我只想談談我是怎麼看待 Go 的,以及我走的一些彎路.
我是 2010 年在學校的時候瞭解到 Go 語言的. 當時的 Go 語言還是一塌糊塗,STW GC 是大家嘲諷 Go 語言的最佳標靶. 只要黑一句,Go 粉基本被噎得說不出話來.
我當時正想儲備一門帶併發程式設計模型的語言. 因為覺得未來 CPU 主頻不再增長的情況下,帶併發程式設計模型的語言肯定是未來的主流. 是共享記憶體型語言強有力的競爭對手.
候選名單如下:
Erlang,Golang,Scala 搭配 Akka.
首先 Scala 被我排除掉了,因為 Akka 的實現我覺得並不好,而且當時 Scala 並沒有本質上的重量級應用 ( Spark 雖然在 2010 年開源了,但是真正流行起來要到2012年後了 ). 其次就是 Go 和 Erlang 了.
當時我對 Erlang 非常痴迷,因為 Erlang 是唯一一個實現了軟實時排程器的程式語言. 這意味著這東西可以直接用來寫電話交換機 ( 當然 Erlang 誕生之初也是為了這個目標而存在的 ),而如果要用Go來寫電話交換機,很可能會電話打著打著,碰到了 STW GC,然後你就聽不到電話對面在講什麼了 ( 這也是為什麼後來 WhatsApp 用了 Erlang,50 個工程師寫出了支撐 9 億使用者的系統 ).
而且,Erlang 實現的系統,做到了 9 個 9 的可用性. 這是什麼概念? 這意味著全年停機時間不超過 31.56 毫秒. 幾乎就是不會停機了. 阿里雲都只能說自己的可靠性 6 個 9,AWS 的可用性只有 99.95%. 意味著每年要停機 4.5 小時左右.
Erlang 另外一個設計的好的地方是,它本身的 runtime 與其說是虛擬機器器,不如說是作業系統,是個執行時容器. 要知道 BEAM ( Erlang 虛擬機器器的名稱 ) 在1992年就被實現了. 而 Docker 2013 年才出現. 這是多麼超前的理念.
於是我義無反顧的學了 Erlang,而 Golang 我只是看了看語法,寫了幾個 demo,觀望了下.
時間來到了 2012年,我去 360 搜尋實習. 我被分配的一個任務就是寫一個監控程式,實時收集並展示 nginx 的連線數等狀態,做資料視覺化供運維工程師排程機器參考. 機器的數量非常多,並且要實時展示,這算是個難點. 我立刻想到了用 Erlang 寫,這簡直是為 Erlang 量身定做的場景.
我寫完了,並且順利的實現了功能. 這時候收到的反饋是,寫得很棒,但是公司沒有用 Erlang 的工程師,沒辦法維護,所以在建議下我又用 Node.js 的 websocket 和 Redis 的訂閱機制實現了個偽實時的監控系統... 這是我第一次,也是最後一次用 Erlang 給企業寫應用.
是的,Erlang 輸在了這裡. Erlang 的發明者 Joe Armstrong 有一篇文章 solving-the-wrong-problem 開頭第一句就說了這麼一句話:
We're right and the rest of the world is wrong. We (that is Erlang folks) are solving the right problem,the rest of the world (non Erlang people) are solving the wrong problem.
現在來看,這句話簡直太中二了,大意就是,錯的不是我,是世界.
Erlang 為什麼沒有在 CPU 主頻無法繼續提升,而核心數猛增的這麼好的生態下火起來. 這個問題其實大佬早就說過了. Erlang 也不是唯一一個倒下去的例子. Richard P. Gabriel ( Common Lisp的發明者之一 ) 在這篇文章中 The Rise of Worse is Better 很好地闡述了為什麼 Lisp 會沒人用,這個道理同樣適用於 Erlang 身上.
簡單來講就是,Erlang 太好了,為了完美的解決問題導致設計的很難學很難使用. 曲高和寡. 而那些簡單好用的垃圾,才能流行起來.
很合理,這個道理再簡單不過了. 這也是為什麼大家不去看書,而是喜歡去聽喜馬拉雅聽,喜歡去看知乎,喜歡去看掘金,喜歡這些被咀嚼一遍的東西,覺得學到了知識. 因為對大家來說,看書太難了,太痛苦了.
但當時我年輕啊,覺得那好辦,我這次選個最簡單的,於是我又跟風學了 Lua (openresty). 這個倒是很簡單,我是看左耳朵耗子老師那篇 LUA簡明教程 入門的. 我的確是在廁所蹲坑的時間就學會了,不到 1 小時 ( 有 JavaScript 經驗的同學會更快一些 ). 然後寫了很多個支援單機 10 萬+級別併發的應用 ( 比如熊貓TV直播間的右側禮物排行榜,比如掘金的全域性資料快取等等 ).
但 Golang 也有了類似解決方案. fasthttp 作為 Go 的代表型高效能WEB框架,輕鬆也可以支援 10 萬級別的併發.
是時間不等人. Golang 在 10 年時間,成為了怪物. 不但 STW GC 的問題解決了 ( 當然還是比不上軟實時的 GC 那麼平滑 ),而且有了 kubernetes 這樣的可怕的殺手鐗. 也許有同學不理解 kubernetes 的可怕. 未來,大家寫的程式很可能既不是直接執行在物理機上,也不是執行在 Xen,VMWare 等虛擬機器器上,而是都會執行在 Docker 上,由 kubernetes 進行排程. 甚至連選擇的權利都沒有 ( 不相信的同學可以問問在大廠的同學,他們有自己部署目標機的 root 許可權麼 ).
看到這裡,是不是很熟悉? Erlang 早都實現了這一切,甚至排程粒度更細,Erlang 實現了內建程式 ( 類似 goroutine ) 級別的排程. 而 Golang 的 goroutine 可不能跨 Docker 排程吧? ( 雖說接個網路通訊模擬下也能實現類似的東西 ) . Erlang 提出了 Let it Crash 的概念. 現在看看 kubernetes 瘋狂重啟你的 docker pod,是不是似曾相識?
openresty 也說明明是我先的 ( 白學現場 ),openresty 誕生之初,能輕鬆支援 10 萬級別併發訪問的WEB框架屈指可數. 但現在 Golang 也可以了. 甚至更好 ( 少背了個 nginx 這麼大個包袱 ).
讀到這裡,你也許會問,你這麼作死,每次幾乎都選錯了,怎麼還能混口飯吃? 那我只能說,我程式設計的入門語言是 PHP,這玩意比 Golang 還 New Jersey Style. 讓我能找到工作的也是 PHP. 而我卻在別的語言上持續作死. ......哈哈哈哈...... 這還真是悲哀.
有正在用 PHP 同學也許會問,那麼學 swoole 合適嗎? 我的建議是. 都是成年人了,不要做選擇,全都要. 無論是 swoole,fasthttp,netty,都值得你看. 我學了 Erlang 也並沒覺得自己吃虧. 這不,還能在這裡水一篇文章呢.