
Beautiful Concurrency & Pretty Erlang
前言
環(huán)信以“連接人與人,連接人與商業(yè)”為使命,旨在為廣大企業(yè)開(kāi)發(fā)者提供最優(yōu)質(zhì)的全球即時(shí)通訊PaaS服務(wù)。如何實(shí)現高并發(fā)場(chǎng)景下,彈性化的保障服務(wù)質(zhì)量是我們一貫的業(yè)務(wù)要求和技術(shù)追求。
本文試圖通過(guò)漸進(jìn)的技術(shù)分析,和大家分享我們在互聯(lián)網(wǎng)高并發(fā)技術(shù)方案選擇上的一些思考和決策;從技術(shù)選型的高度為架構師在面對高并發(fā)業(yè)務(wù)設計時(shí)需要考慮的方方面面做一個(gè)參考。
接下來(lái),enjoy:
Beautiful Concurrency–并發(fā)的必要性
- 世界是并發(fā)的,軟件也應該是并發(fā)的
我們生活在其中的世界,就是一個(gè)巨大的并發(fā)系統。每時(shí)每刻,在世界的每一個(gè)角落,人類(lèi)的每一個(gè)個(gè)體都在和這個(gè)世界進(jìn)行著(zhù)頻繁的能量交互,信息交互也是其中的重要組成部分;當我們轉換身份,以造物主的視角俯瞰這個(gè)世界里所有的萬(wàn)物(動(dòng)物,植物,海洋,土壤,機器等等)時(shí),也可以看到它們同樣在和這個(gè)世界進(jìn)行著(zhù)無(wú)休止的能量/信息交互。
為了與這個(gè)世界進(jìn)行有效的交互,軟件也應該是并發(fā)的。
- 世界是分布的,軟件也應該是分布的
地球是圓的,世界是平的,不管怎樣,從宇宙大爆炸的那個(gè)奇點(diǎn)之后,就是分布的宇宙/世界。作為與世界萬(wàn)物(包括人類(lèi)自己)交互的軟件,自然也必須滿(mǎn)足分布式要求。而這種地理分布(Geo.Distribution)特性,也僅是并發(fā)在空間維度下的反映而已。
- 世界不可預測,軟件也應該是容錯的
沒(méi)有完美的世界:沖突,災難隨時(shí)在發(fā)生,不管在什么樣的維度上。作為軟件,bug,crash也是不可規避的現實(shí)挑戰。即使存在完美的沒(méi)有bug的程序,運行程序的硬件也可能出現故障。為了增強軟件的容錯性,代碼的獨立性(指一個(gè)故障不會(huì )影響到故障任務(wù)以外的其它任務(wù))和故障檢測以及故障處理是關(guān)鍵:這一切都需要并發(fā),因為串行程序的容錯性遠遠不如并發(fā)程序。
并發(fā)方案概覽
“七個(gè)模型”來(lái)源于PaulButcher著(zhù)的《Seven Concurrency Models in Seven Weeks》,中文譯名《七周七并發(fā)模型》,概覽的介紹了并發(fā)領(lǐng)域的常見(jiàn)方案,希望能給架構師提供一個(gè)輪廓化的分類(lèi)描述。本人在其基礎上添加了一些自己的拓展思考(見(jiàn)下文中斜體部分):
1.線(xiàn)程與鎖:線(xiàn)程與鎖模型有很多眾所周知的不足,但仍是其他模型的技術(shù)基礎,也是很多并發(fā)軟件開(kāi)發(fā)的首選。—這個(gè)方案其實(shí)是一個(gè)anti-pattern,在高并發(fā)場(chǎng)景下如履薄冰(bug,dead lock如影隨形),讓開(kāi)發(fā)者和運維人員膽戰心驚。Ugly Locks to Ugly Concurrency (丑陋的鎖,丑陋的并發(fā)):locks and condition variables is fundamentally flawed!
2.函數式編程:函數式編程日漸重要的原因之一,是其對并發(fā)編程和并行編程提供了良好的支持。函數式編程消除了可變狀態(tài),所以從根本上是線(xiàn)程安全的,而且易于并行執行。—函數之美,邏輯之美!相信很多從命令式語(yǔ)言(Imperative Programming)轉戰到函數式編程語(yǔ)言(Functional Programminmg)的時(shí)候都會(huì )發(fā)出這樣的感嘆。其實(shí)這一進(jìn)步恰恰體現了人類(lèi)在不斷的進(jìn)化過(guò)程中,對這個(gè)世界認知不斷提煉,思維模式逐步由具象走向抽象的演進(jìn)軌跡。而回到高并發(fā)的話(huà)題上,函數式編程以不可變狀態(tài)這一簡(jiǎn)易的策略,贏(yíng)得了完美贊譽(yù),儼然已是君臨天下的明日霸主!
3.分離標識與狀態(tài):如果一個(gè)線(xiàn)程引用了持久數據結構,那么其他線(xiàn)程對數據結構的修改對該線(xiàn)程就是不可見(jiàn)的。因此持久數據結構對并發(fā)編程的意義非比尋常,其分離了標識(identity)與狀態(tài)(state)。—這又是一個(gè)很妙的策略,而大家熟知的version control system如git,包括比特幣/區塊鏈的機制都是這一思想指導下的具體實(shí)踐,限于篇幅,本文不做進(jìn)一步展開(kāi)。
4.ActorModel:一種適用性很廣的并發(fā)編程模型,適用于共享內存模型和分布式內存模型,也適合解決地理分布型問(wèn)題,能提供強大的容錯性。—最開(kāi)始接觸到Actor模型就是通過(guò)Erlang語(yǔ)言,后來(lái)又接觸到Akka(基于Scala)等基于各種語(yǔ)言實(shí)現的框架,也越來(lái)越體會(huì )到這一模型在高并發(fā)場(chǎng)景下的游刃有余。本文后續部分會(huì )展開(kāi)介紹。另外,做個(gè)招聘小廣告,環(huán)信通訊云研發(fā)團隊正在廣納英才,歡迎懂Erlang,有相關(guān)高并發(fā)開(kāi)發(fā)經(jīng)驗的小伙伴加盟,虛位以待!點(diǎn)這里直接聯(lián)系我們喲!
5.CSP(Communicating Sequential Processes,CSP):表面上看,CSP模型與Acto rModel很相似,兩者都基于消息傳遞。不過(guò)CSP模型側重于傳遞信息的通道,而Actor Model側重于通道兩端的實(shí)體,使用CSP模型的代碼會(huì )帶有明顯不同的風(fēng)格。—這里就是channel可以大施拳腳的天地了,gogogo!限于篇幅,本文不做進(jìn)一步展開(kāi)。同樣的,歡迎懂Golang,有相關(guān)高并發(fā)開(kāi)發(fā)經(jīng)驗的小伙伴加盟,虛位以待!
6.數據級并行:每個(gè)筆記本電腦里都藏著(zhù)一臺超級計算機——GPU。GPU利用了數據級并行,不僅可以快速進(jìn)行圖像處理,也可以用于更廣闊的領(lǐng)域。如果要進(jìn)行有限元分析、流體力學(xué)計算或其他的大量數字計算,GPU的性能將是不二選擇。—在過(guò)去的兩年里,華人之光,黃仁勛(Jensen Huang,CEO of Nvidia),從自家的壁爐里一次又一次給大家帶來(lái)了震撼世界的革新產(chǎn)品,讓之前高不可攀的GPU飛入尋常百姓家,也帶來(lái)了一次又一次的算力之爭。相信在不久的將來(lái),有了GPU算力加持和人工智能算法的普惠使用,會(huì )有無(wú)數的AI應用層出不窮的涌現,它們會(huì )從云端落地到邊緣,人類(lèi)可能會(huì )比自己想象的更早的進(jìn)入前途未卜的人機爭霸時(shí)代。
7.Lambda架構:Lambda架構綜合了Map Reduce和流式處理的特點(diǎn),是一種可以處理多種大數據問(wèn)題的架構。—Lambda架構也是采用了數據并行處理技術(shù),但是它把并行算力的微觀(guān)場(chǎng)景放大到了一個(gè)更大的尺度:將數據和計算分布到成千上萬(wàn)臺機器組成的集群上進(jìn)行,將并發(fā),分布特性整合到一套方案中,通過(guò)兩層(批處理層-Batch Layer,加速層-Speed Layer/Streaming Process)的組合,實(shí)現了高計算效率和低延遲的“魚(yú)與熊掌兼得”。
Pretty Erlang
環(huán)信的全球即時(shí)通訊云的核心網(wǎng)絡(luò )是基于Erlang/OTP開(kāi)發(fā)的,截止目前共服務(wù)了幾十萬(wàn)APP客戶(hù),單集群日消息幾十億量級并還在不斷挑戰新高。多年的經(jīng)驗積累,我們仍在不斷的對系統進(jìn)行優(yōu)化,榨取計算,網(wǎng)絡(luò )等資源的內生價(jià)值,挑戰系統一個(gè)又一個(gè)不斷提升的指標要求。感謝Erlang/OTP,有了它,我們像站在了巨人肩膀上的一名揮舞利刃的勇士,能夠從容應對各種“黑云壓城城欲摧”的業(yè)務(wù)壓力和不斷變化,五花八門(mén)的業(yè)務(wù)需求。以下,我們簡(jiǎn)單總結了Erlang/OTP幾點(diǎn)讓我們“迷醉的特質(zhì)”,給想入坑的小伙伴以參考:
Letit Crash!
再一次,讓我們理解了“思維高度決定人生高度”。當其它語(yǔ)言或者解決方案防御性的,想方設法捕獲異常/錯誤并盡力挽回“敗局”的時(shí)候,Erlang采納了”Letitcrash!”的策略,把重點(diǎn)放在了錯誤的檢測和錯誤通知體系上,通過(guò)嚴謹設計的單向,雙向link機制,OTP基于此設計的supervisor behaviour層級(Hierarchical)管理匯報機制,”任其崩潰“的同時(shí)又干凈漂亮的將所有Actor(進(jìn)程)在發(fā)生異常時(shí)的行為進(jìn)行了簡(jiǎn)單但有效的管理,獲得了意想不到的好處:
代碼簡(jiǎn)潔易懂,僅在需要關(guān)心崩潰處理的層級存在容錯代碼;
由于A(yíng)ctor Model的設計,Actor之間相互獨立,也不共享狀態(tài),因此任何一個(gè)Actor的崩潰并不會(huì )影響其它Actor,遑論它的管理者(Supervisor),因此管理者可以從容的處理被管理Actor的崩潰;
管理者也可以不處理崩潰,僅記錄相應崩潰,繼而通過(guò)查看崩潰通知來(lái)進(jìn)行后續處理。這個(gè)策略在后續PatternMatching時(shí)候還會(huì )見(jiàn)到,我們可以在_Other(所有匹配均未觸發(fā))保護匹配中記錄相應信息,而不必為事先預估不到的場(chǎng)景絞盡腦汁!
Actor Model
Actor Model是PureOO的設計(而Java類(lèi)與方法的設計并不是,意不意外?):每一個(gè)Actor封裝了狀態(tài),外界并沒(méi)有任何方法來(lái)操縱(manipulate)對象,它們唯有通過(guò)發(fā)送消息通知Actor,由Actor自己控制對消息的處理,這種簡(jiǎn)化同樣為高并發(fā)處理提供了意料之外的強大支持。
Actor Model適用于共享內存模型和分布式內存模型,也適合解決地理分布型問(wèn)題,能提供強大的容錯性,用了都說(shuō)好!
我個(gè)人在曾經(jīng)的工作中做過(guò)一個(gè)網(wǎng)絡(luò )安全過(guò)濾的產(chǎn)品,是靠自己團隊設計編寫(xiě)的一套消息隊列處理機制來(lái)解耦不同業(yè)務(wù)對相同數據的處理,后來(lái)回想起來(lái)才驀然發(fā)現其實(shí)這就是個(gè)簡(jiǎn)陋的ActorModel設計,只是那個(gè)時(shí)候還不知道Erlang/OTP,要是早用上這把利器,能節省我生命中多少個(gè)日日夜夜啊!
Functional Programming
介紹函數式編程的書(shū)籍,資料已經(jīng)很多了,本文不做過(guò)多的展開(kāi)。簡(jiǎn)單列舉下個(gè)人的幾點(diǎn)體會(huì ):
程序最終還是要交給機器處理,因此要盡量按照機器的思維模式去編寫(xiě)程序(雖然有時(shí)候會(huì )讓程序員頭大),最簡(jiǎn)單的(a+b)與(+ab):前者對人類(lèi)友好,而后者對機器友好,因而也能帶來(lái)更好的程序一致性,繼而使得系統可以設計的更簡(jiǎn)單;
命令式編程的代碼由一系列改變全局狀態(tài)的語(yǔ)句構成,而函數式編程則是將計算過(guò)程抽象成表達式求值。這些表達式由純數學(xué)函數構成,而這些數學(xué)函數是第一類(lèi)對象(我們可以像操作數值一樣操作第一類(lèi)對象)并且沒(méi)有副作用。由于沒(méi)有副作用,函數式編程可以更容易做到線(xiàn)程安全,因此特別適合于并發(fā)/并行編程。
函數之美帶來(lái)美之并發(fā)!原文摘抄:
For me, a beautiful program is one that is so simple and elegant that it obviously has no mistakes, rather than merely having no obvious mistakes. If we want to write parallel programs that work reliably, we must pay particular attention to beauty.
Pattern Matching
又一個(gè)讓你被美折服的設計:函數在這種Pattern Matching的語(yǔ)法結構的描摹下,儼然變成了一道道證明題,你只需要描述(并不需要窮舉)你所關(guān)心的場(chǎng)景(Conditon)下自己的想法,剩下的就交給”模式匹配“這個(gè)自動(dòng)化機器幫你完成。你可能想不到的是,”PatternMatching“發(fā)揮功效的地方并不只是case/if出現的地方,你的整個(gè)代碼都是在”Pattern Matching“的魔力下散發(fā)它優(yōu)雅的魅力。
Future Evolution
對高并發(fā)的不懈追求將一直是環(huán)信通訊云研發(fā)團隊的目標,我們也期待在這條崎嶇山路上不斷攀登,厚積薄發(fā),為環(huán)信的客戶(hù)帶來(lái)一貫的極致產(chǎn)品體驗!