做者黃挺,螞蟻金服高級技術專家,螞蟻金服分佈式架構 SOFA 的開源負責人。目前在螞蟻金服中間件團隊負責應用框架與服務化相關的工做。前端
本文根據黃挺在 2018/09/01 微服務實踐沙龍(上海站)分享整理,這篇文章中,一共列舉了 SOFA 在發展過程當中四種多語言的支持方式。node
世界上的編程語言千千萬,每一個人都有本身偏好的語言,git
有人認爲 PHP 是世界上最好的語言。也有人很是喜歡 Java,強類型,泛型,多態,性能也很是不錯。也有人很喜歡 Ruby,再好比 Paul Graham 在他著名的「黑客與畫家」的書中表達了對 Lisp 的無限喜好。我的對於語言的喜愛是無可厚非的。github
相信你們都據說過巴別塔,人類想要造巴別塔通天,上帝知道了,就讓不一樣族羣的人類說不一樣的語言,最後人類之間因爲語言溝通不流暢,巴別塔沒有形成。從這個故事中咱們能夠學到要作成一件事情,溝通是多麼地重要。數據庫
假設一家公司的業務的目標就是通天,咱們都知道只使用一門語言是不能解決全部的問題,前端幾乎都是 JavaScript 系的語言,後端的語言則更加五花八門,從現實地角度來看,必須選擇不一樣的語言來解決不一樣的問題,那麼這些語言之間怎麼作相互通訊,就是咱們須要去解決的問題。編程
回到微服務這個領域,若是要解決基本的通訊的問題,基本上只要解決三個問題就能夠了,首先是基本的網絡通訊的能力,而後是雙方須要協商好數據怎麼序列化和反序列化,最後要解決服務發現的問題,要調用對方的服務,總得知道從哪裏去尋找對方的服務吧。後端
可是解決完這些基本的問題以後,由於微服務把整個系統給分佈式化了,接下來咱們又得面對分佈式的問題,這個領域的問題可就多了,包括負載均衡,鏈路追蹤,限流,熔斷,鏈路加密,服務鑑權等等一大堆的問題。那麼在微服務這個領域下去解決多語言的問題,咱們就必然要在這些問題上作考量,作抉擇。瀏覽器
首先,咱們嘗試一個比較簡單的方法來解決多語言的問題,假設如今有一個 Java 寫的 SOFA 系統,它經過 SOFARPC 裏面的默認的長鏈接基於 TCP 的協議 Bolt 暴露了一個服務,這個時候有一個 NodeJS 的系統須要去調用它,最簡單的方式能夠怎麼作呢?網絡
咱們能夠嘗試在 SOFA 這一端把原來的服務經過一種新的形式給暴露出來,提供一個JSONover HTTP 的形式讓 NodeJS 的系統去調用,在 SOFA 裏面去提供一個 JSON over HTTP 的服務很是方便,只要對原來的配置稍做修改便可。架構
爲何選擇 JSON over HTTP 的方式呢?由於 JSON 以及 HTTP 在每一個語言裏面幾乎都有原生的支持,即便沒有原生的支持,也有三方庫來支持,並且相對來講,每一個語言支持地都比較好。經過 JSON over HTTP,咱們解決了網絡通訊和序列化的問題。
服務發現的問題怎麼來解決呢?也很簡單,能夠經過一些 F5 的這樣的設備,而後 NodeJS 的應用經過 DNS 的方式去發現 F5 的設備,而後經過 F5 這樣的設備再將請求轉到後面的 SOFA 應用的集羣上面,就能夠解決了,這邊可能須要去作的就是花點錢,買個負載均衡設備而已,固然,若是你用 K8s 的話,那麼就能夠經過 K8s 的 Service,Service 對於使用方來講,跟 DNS 是如出一轍的。
可是這種方式只能解決服務發現以及基本的通訊的問題,另外的一些高階的能力,好比熔斷,限流等能力,都沒法經過這種方式來解決。因此這種方式比較適合於在一些相對來講邊緣的場景下去解決多語言通訊問題,若是調用過程當中的流量可用,不會有突發的流量,錯誤也是能夠忍受的,那麼採用這種方式多是比較經濟實惠的。這個也是螞蟻金服早期不少多語言的場景的廣泛的方式。
隨着 NodeJS 在業界關注度愈來愈高,螞蟻金服也但願將 NodeJS 應用在更加核心的場景,在當前的螞蟻的整個體系中,BFF 層更多都是由 NodeJS 的應用來承擔。
把 NodeJS 應用在覈心場景下,上面提到的第一種方式固然是徹底不夠的,咱們須要的不只僅是一個簡單的通訊的方式,而是一個完整的微服務的解決方案。剛好螞蟻的 NodeJS 團隊的技術實力也很是地深厚,因此就想到了能夠經過將 Java 體系中的各個微服務的組件作一個 NodeJS 的版本,好比對於通訊協議 Bolt,在 NodeJS 這邊,也搞了一個 sofa-bolt-node,對於 Hessian 序列化的協議,也搞了一個 NodeJS 的 Hessian 的支持 sofa-hessian-node,對於 SOFARPC,也搞了一個 sofa-rpc-node,其餘的能力,好比服務發現,負載均衡,限流/熔斷,鏈路追蹤等等,都有對應的 NodeJS 的實現。
這種對應的一個語言重複造一遍輪子的方式比較好的支撐了 NodeJS 在螞蟻金服做爲 BFF 層的發展,而且經過這種方式,各項功能基本上沒有太大的損失,基本上 Java 可以實現的能力,NodeJS 也都可以實現。
可是隨着時間的推移,咱們發現這種造輪子的方式也有一些沒法繞過的問題,前面說到 Java 的微服務框架的能力 Node 基本上都可以實現,可是對於一些能力已經深刻地使用了 Java 語言特性的一些能力,好比註解,在 NodeJS 中是沒法直接實現的,致使 NodeJS 這一端只能用一些很是 Hack 的方式來解決這種類型的問題。另外,就是在多語言的維護成本上,一樣的功能,須要 Java 和 NodeJS 維護兩套,這種方式不但對於每一個語言的團隊的要求比較高,而最終也致使同一個功能,每每須要相比於原來兩倍的能力來實現,一樣的 Bug,可能也須要 Fix 兩次。
總結來講,這種方式可讓大部分的功能在不一樣的語言中都獲得比較好的實現,可是一旦一些功能和特定的語言特性綁定,別的語言實現起來就會很是 Hack,而且不容易維護。另外,這種方式須要整個團隊付出比較多的成本,成本每每和語言的個數成正比,兩個語言可能還好,可是一旦出現更多的語言須要支持,成本可能就難以承受。
相信每一個公司多多少少都有一個 API 網關,這個網關每每負責多端的接入,而且也會有多協議的支持,瀏覽器端可能會採用 HTTPS 來接入,iOS 和 Android 可能會採用私有的協議來對接,API 網關會將接入端的協議最終再轉換成內部的協議,而且做爲一個 API 網關,每每也會有鑑權,限流等等能力。
API 網關做爲微服務體系裏面的一部分,其須要解決的問題和整個微服務體系須要去解決的問題很是相似,做爲 API 網關,自己就須要去對接多語言的客戶端(iOS,Android),能夠說很是適合用 API 網關相似的方式來解決多語言問題。
咱們能夠基於 API 網關改造出一個做用於內部的多語言的網關出來,在多語言網關這一層來實現微服務上的一些限流,熔斷,服務鑑權,負載均衡等等能力,這樣,這些能力就不用每一個語言單獨去實現,只須要實現一次就夠了。可是對於服務發現這一塊,業務系統仍是須要用某種服務發現的機制來發現多語言網關,這部分仍是須要選擇一個通用的方案,好比 DNS + F5,或者每一個語言單獨實現。
除此以外,多語言網關由於是集中式地部署,還會引入一個新的問題,就是資源隔離的問題,假設多語言網關後端的一個服務忽然變慢了,那麼可能會將多語言網關本身給拖垮掉,進而影響到多語言網關代理的其餘服務。
要解決這個問題,有兩種方式能夠去解決,一種是作線程池的隔離,能夠給一些重要的業務一些單獨的線程池,不重要的業務再放到一個大的單獨的線程池裏面。
線程池隔離的方案裏面僅僅作到了線程池的隔離,其餘的資源的隔離其實並無作,好比 CPU 和 Memory 之類的隔離等等,若是想要更加完全的隔離方式,能夠採用和線程池隔離相似的方式,給重要的服務用獨立的多語言網關來爲其服務,不重要的服務,再給一個大的獨立的集羣去服務。
若是說要進一步地去解決多語言網關資源隔離的問題,可否進一步地將集中式的網關分佈式化呢,假設每個應用的實例都可以給它單獨地配置一個多語言網關的話,那麼就能夠完全解決多語言網關的資源隔離的問題。
實際上,最近在業界很是火的 Service Mesh 就是這樣的方法,在 Service Mesh 裏面,這個「分佈式的多語言網關」叫作 Sidecar。
在 Service Mesh 的體系下,咱們可讓微服務裏面的一些能力下沉到 Sidecar,無論是什麼語言開發的系統接入到整個微服務體系中,都只須要接入這個Sidecar 就能夠了,這個 Sidecar 裏面能夠作服務發現,限流熔斷,服務鑑權等等的能力,對於特定語言的業務系統來講,只須要和另外一個語言的協議可以對接起來就能夠了,其餘的一些能力都交給 Sidecar 便可。
可是,對於 Service Mesh 這樣的架構,雖然只須要實現一次就能夠達到支持多語言的目的,而且沒有多語言網關那樣的資源的瓶頸,可是相對來講,運維成本卻高上很多,畢竟,Sidecar 是須要和業務系統部署在一塊兒。在 VM 的場景下,Sidecar 和業務系統部署在同一個 VM 下,那麼對於 Sidecar 的保活,升級,回滾都是須要單獨去解決的。若是在 K8s 的體系下,那麼 Sidecar 的運維的問題就比較好解決了,K8s 的 Pod 的概念很是適合於 Sidecar 這種方式,Sidecar 和業務能夠跑在不一樣的 Container 裏面,能夠作到 Sidecar 和業務之間的資源的進一步的隔離。
在 Service Mesh 這個方向上,SOFA 也開源了本身的 ServiceMesh 的方案 SOFAMesh,歡迎你們詳細了解。
在這篇文章中,一共列舉了 SOFA 在發展過程當中四種多語言的支持方式:
1. 簡單的方式:直接使用 JSON over HTTP + DNS,能夠解決基本的通訊的問題,可是缺失了微服務下的其餘的高級能力。
2. 造輪子的方式:每一個語言單獨實現微服務的各類能力,適合須要適配的語言比較少的狀況,須要投入比較大的人力,而且個別特性可能沒法在多個語言中徹底實現。
3. 多語言網關的方式:能夠實現一次,把微服務裏面的大部分的能力集中到多語言網關裏實現,須要用額外的手段去解決資源隔離的問題,多語言系統依舊須要面臨如何發現多語言網關的問題。
4. Service Mesh 方式:至關於「分佈式多語言網關」,給每個服務的實例都加上一個 Sidecar,由 Sidecar 來提供微服務須要的能力,業務系統只須要專一於選擇通訊以及序列化協議便可,這種模式在沒有 K8s 的支持下有比較大的運維難度。
這些都是咱們實踐過程當中的一些作法和體會,但願你們能夠結合本身的業務階段來參考。
SOFA 中間件是螞蟻金服自主研發的金融級分佈式中間件,包含了構建金融級雲原生架構所需的各個組件,包括微服務研發框架,RPC 框架,服務註冊中心,分佈式定時任務,限流/熔斷框架,動態配置推送,分佈式鏈路追蹤,Metrics 監控度量,分佈式高可用消息隊列,分佈式事務框架,分佈式數據庫代理層等組件,也是在金融場景裏錘鍊出來的最佳實踐。
SOFAMesh 相關內容:
項目地址:http://github.com/alipay/sofa-mesh
長按關注,獲取最新分佈式架構乾貨
歡迎你們共同打造 SOFAStack https://github.com/alipay