這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
原文 http://peter.bourgon.org/go-kit/
The modern enterprise
當我們聽到 企業(enterprise)這個詞的時候,往往會聯想到老派,緩慢, 繁文褥節等名詞,就比如 IBM HP 甚至紅帽這樣的公司,他們已經在長達數十年的時間內成為科技行業的領導者。現在,一些如 Google Amazon Twitter,Netflix,Facebook,Spotify,乃至 SoundCloud 這些公司正成為互連網行業的主流,這些現代的企業通常有以下一些特質:
- 技術導向
- 專註使用者產品和使用者體驗
- 成功的,爆炸式的增長
- 100-1000 數量級的工程師
- 採用面向服務的架構 (SOA)
最後一點尤其關鍵。
A service-oriented architecture
除了少數的例外,絕大多數的現代企業在經曆過相似的技術架構演變後,都已經轉向了面向服務的架構(或者 microservice):
- 創業初期基於 RoR (或者類似的架構)快速開發的龐然大物
- 將關鍵模組剝離獨立開,向 SOA 靠攏
- 可能進行更加細緻的解耦,變成 microservices
採用 SOA 可以得到很多好處,但是是有代價的。一個分布式系統天然會比實現同樣功能的龐然大物般的單一服務要複雜。解決和管理這些分布式系統代理程式的複雜性,通常最終會產出一些類庫和架構。在現代的企業裡,一些久經考驗的事實標準會開始進入大家的視野,通常以開源項目的形式。我認為, Twitter 的 Finagle 是最值得一提的一個;Netflix 也維護了一坨這樣的開源項目。當然還有很多小公司開源了很多同質的項目。
這些類庫通常是用 Scala 寫的,和其他的一些 JVM 語言配合使用。Scala 在這個領域有很多好處: 表達力強,某些情境下效能不錯。但它並不是銀彈,從任何角度上看,它文法都太複雜,工具鏈巨難用,甚至在語言設計上有些自相矛盾(函數式 vs 過程式)。這意味著很少有人能很好的理解和運用這門語言,這會導致一些不可避免的壞模式的產生:拷貝-粘貼代碼;對於一些問題進行錯誤的抽象,重複造輪。
在這個大環境下,Go 就有機會了。清晰(簡潔)高內聚的設計,對開發人員友好的工具鏈,產生原生的二進位代碼(不需要平台相關的 runtime), 接近 C 的運行時效率讓其非常適合進行 SOA 架構的開發,特別是對比現在的最新的程式設計語言和相關架構。除此之外,Go 還有一個和它的年紀並不匹配的優秀的生態系統和第三方庫,同時還有很多的成功案例可以參考。但是 Go 還(暫時)缺乏一個成熟的綜合性的分布式服務架構(工具包)。我認為,這個坑很快就要被填上了 :)
What Go needs
我認為,Go 需要一個類似 Finagle 的工具包, GoKit,讓其可以變成一個進行現代 SOA 架構開發的語言(作為 Java / Scala 之外的另一個合格的候選語言)
Gokit
在我的想法中, Gokit 有一組相互關聯的包組成,作為開發大型 SOA 架構的基礎架構。這個工具包應該是綜合性的,包含實現分布式系統的各種重要部分的組件;它會在自己的架構中包含一些常見的分布式系統模組,比如 Finagle;同時它應該整合一些最常用的基礎架構組件來減少開發時候的阻礙,同時加強與現有系統的溝通。
我認為這個工具包應該是只包含核心組件的最小集,我會逐一的介紹我設想中的各個組件,但是目前僅是我自己認為的最小集合,我會在這裡發起一個討論,來收集大家的想法。
package metrics
指標模組,用戶端和伺服器需要徹底的儀錶化(指標可即時度量),這意味著需要收集諸如:系統記憶體,CPU使用方式,GC資訊等等。這也意味著需要收集服務層的指標,如請求回應時間,內部隊列長度,每個過程的延遲(比如流水線作業);同樣意味著需要包含商務邏輯的指標,如某些業務事件的吞吐,或者上層業務的異常等。
package log
日誌模組,不同的公司對於日誌有著不同的需求,比如記錄層級,schema, log的儲存位置等。我認為工具包可以基於標準庫的 log 庫為核心,然後提供可選的模組,如記錄層級,schema 定義和增強,還有不同的log後端,log的後端可以支援輸出 stdin/stdout, 也可以輸出到 syslog, nsq, kafka 這類的系統。
工具包的 log 模組應該可以服務一切類 log 形式的資料,不僅僅只是應用的診斷資訊。
package server
server 包,可能是最大的和最重要的組件了。理想情況下,我們應該可以直接以實現一個 Go 介面的形式來實現一個服務。server 包在內部需要封裝服務的一些常見需求,例如服務的監控,請求的 tracing,串連池管理,抗壓,節流等工作。對上述任何一個功能點,也需要提供介面,來實現可拔插的策略。server 庫還需要整合服務發現模組,同時在不同的 transport 方式下運行良好。可參考的實現是: Fingle, Karyon 等。
package client
client 包是 server 包的一個自然的伴侶,它像 server 包一樣也應該封裝很多常用的模式如:用戶端的限速,斷路保護,串連池等。它也應該和服務發現模組整合,在不同的 transports 方式下正常工作。可參考的實現是: Finagle, Ribbon 等。可見,client 和 server 包應該能共用代碼,比如串連池,限速, request tracing 什麼的,都是可以抽出來的。
Service discovery (服務發現)
服務發現,在一個動態(易變)的網路中串連用戶端和服務端是一個龐大的課題。有很多手段可以實現,從靜態配置ip,到動態拓撲結構變化訂閱,還有各種在此之間的方案。這個工具包應該相容你所在公司的現有的基礎服務,至少得支援靜態寫入程式碼配置ip地址,並且支援一些常見的開源解決方案如 consul, etcd, smartstack (zookeeper) 等系統。
package transport
通訊模組,service 的實現應該與其的通訊方式解耦,一個獨立的 service 應該可以支援綁定多種不同的通訊格式。這裡的通訊方式指的是一個廣義的概念:請求(回複)資料的序列化(還原序列化),支援諸如 json/gob/protobuf, thrift, avro 等格式;同時請求(回複)的通道可以支援 HTTP/RPC/ raw TCP。
好處
如果我們的分布式系統確實只是依賴一組約定,我們可以利用它們作為簡化的假設,並建立一個更易於理解和可靠的模式。畢竟,簡單性是可靠性的前提條件。更進一步:設想,利用這些約定,得到整個系統的運行時狀態的工具。它可能允許我們在對異構的服務執行個體進行統一的度量。有了這些資訊,我們可以建立動態系統,使系統動態地根據環境的變化作出反應。這將使像基於負載的 auto-scale,或者沒有人工參與的安全持續部署等進階的模式。
僅僅是這些好處,就足以把我們交的稅補回來的了 :) 同時將這些基礎組件轉化成了真正的商業價值。而且未來是敞開的,還有很多可能性,我們現在並不知道是什麼。
下一步
當我把這個 talk 在 FOSDEM 和 Google Campus London 聚會發表後,我收到了許多熱情的開發人員有類似的想法。我備受鼓舞,我想建立一個工作群組,探討這些想法,並開始實現 Gokit。
促使我做這個工作是因為我希望看到 Go 語言能夠更加的成功,並且將 Go 引入這個領域,我相信我會從中大大受益。運氣好的話,我認為我們在幾個月後會有一個早期的可用於產生環境的版本。一開始,我會建立了一個郵件清單,在這裡我們可以開始收集需求和想法,並組織初步的開發工作。我也建立了gokit.io作為官網,以後可能用於host gokit的一些包。http://gokit.io如果你對上述這些東西感興趣,希望你能加入郵件討論群組!