Node 調用 dubbo 服務的探索及實踐

1. 背景介紹

咱們公司是杭州的一家電商公司,公司內的技術體系較多,主要語言有了JAVA/PHP/Node,其中在19年的時候,公司制定了去PHP化的計劃,將後端邏輯沉澱到Java服務化當中,而部分服務化調用相關業務則須要Node扛起,而與Java進行通訊則須要通過Dubbo,由此咱們以Consumer的角色來探索與研究如何用Node調用Dubbo.javascript

調用鏈路


2.Dubbo簡介

2.1 什麼是dubbo

Dubbo是一款高性能、輕量級的開源Java RPC框架,它提供了三大核心能力:面向接口的遠程方法調用,智能容錯和負載均衡,以及服務自動註冊和發現。java

2.2 流程圖

調用流程圖

  • Provider : 暴露服務的服務提供方。
  • Consumer : 調用遠程服務的服務消費方。
  • Registry: 服務註冊與發現的註冊中心。
  • Monitor: 統計服務的調用次調和調用時間的監控中心。
  • Container: 服務運行容器。

3. 具體實現

3.1 協議選擇

官方雖然支持了不少種協議,可是真正適合於咱們的協議並非不少,譬如rmi協議主要是面向Java工程之間的調用,並不適合用於異構語言RPC場景,因此咱們接下來只針對部分協議進行分析,並結合咱們的實際的業務場景,最後來篩選出適合咱們的協議.git

鏈接個數 鏈接方式 傳輸協議 傳輸方式 序列化 適用範圍 適用場景
dubbo 單鏈接 長鏈接 TCP NIO 異步傳輸 Hessian 二進制序列化 傳入傳出參數數據包較小,消費者比提供者個數多,單一消費者沒法壓滿提供者 常規遠程服務方法調用
rmi 多鏈接 短鏈接 TCP 同步傳輸 Java 標準二進制序列化 傳入傳出參數數據包大小混合,消費者與提供者個數差很少,可傳文件。 常規遠程服務方法調用,與原生RMI服務互操做
hessian 多鏈接 短鏈接 HTTP 同步傳輸 Hessian二進制序列化 傳入傳出參數數據包較大,提供者比消費者個數多,提供者壓力較大,可傳文件。 頁面傳輸,文件傳輸,或與原生hessian服務互操做
http 多鏈接 短鏈接 HTTP 同步傳輸 表單序列化 傳入傳出參數數據包大小混合,提供者比消費者個數多,可用瀏覽器查看,可用表單或URL傳入參數 需同時給應用程序和瀏覽器 JS 使用的服務。
rest 多鏈接 短鏈接 HTTP 同步傳輸 表單序列化 同http,適用於更加符合rest規範的服務 同http

3.1.1 協議選擇 - dubbo

從使用場景上來看,dubbo協議是比較符合咱們實際業務需求的,因爲其數據包相較於Http協議體積小不少,傳輸速度也會更快,另外咱們能夠經過socket與provider創建長鏈接,能夠減小反覆建連帶來的沒必要要的網絡開銷.使用此協議,咱們須要注意的幾個點是github

  • 本地負載均衡策略
  • 與Provider創建TCP長鏈接
  • Hessian協議解析

小結 : 若是想要採用此協議鏈接Provider,可使用dubbo官方推薦dubbo2.js後端

3.1.2 協議選擇 - rest

此協議是基於http,因此對consumer端就基本上沒有了限制.並且此協議咱們在拼接好參數以後,能夠直接經過瀏覽器或者是HTTP請求工具便可查看結果,使用友好程度上來說,會優於dubbo. consumer端能夠直接使用request庫請求,也不存在協議解析以及socket狀態維護的問題,消費端的代碼實現難度也會比較小.使用此協議,咱們須要注意的幾個點 :瀏覽器

  • 須要使用keep-alive來與provider保持建連,不然http反覆斷開重連會帶來不少沒必要要的網絡開銷
  • 本地負載均衡策略
  • 此協議在dubbo 2.6.x+ 才支持

小結 : 性能上雖不及dubbo.但對開發人員相對友好,能夠結合業務自身場景進行選擇.網絡

3.1.3 補充

dubbo是支持一個服務以多種協議註冊,好比一個服務能夠同時註冊dubbo://rest://,若是你想用http,可是目前公司所暴露出來的協議只支持dubbo,能夠和提供服務的同窗商量一下,額外再添加一個http協議成本也是能在接收範圍內的.負載均衡

3.2 如何引用服務

目前引用服務有兩個方案,分別是框架

  • 直接引用
  • 經過註冊中心引用服務

3.2.1 直接引用服務

直接引用服務,顧名思義就是繞開註冊中心獲取咱們所想要的服務提供者,因爲繞開了註冊中心,天然也沒法作到服務發現,並且因爲單點問題,沒法作到負載均衡以及高可用,因此生產環境不推薦使用此模式的異步

可是因爲其開發上的便利性,在開發環境/測試環境仍能夠嘗試使用此模式.

直連provider

由上圖所示,開發同窗聯調過程當中,須要在項目工程中對指定服務開發同窗的機器進行直連,而其餘沒有指定的服務將會默認走註冊中心.爲了不對工程代碼的侵入性,咱們會在工程中創建應對不一樣環境的dubbo.properies,而dubbo.properies不會加入到工程的版本控制當中,主要用於解決不一樣環境下的服務直連問題.其中服務的控制粒度能夠精確到具體的服務.

直連代碼片斷

3.2.2 經過註冊中心引用服務

經過註冊中心發現引用服務,Dubbo經常使用的引用服務方式,能夠作到服務自動發現,負載均衡.正式環境調用基本基於此模式.其中註冊中心實現有不少種,例如Zookeeper/Redis/Multicast.官方推薦Zookeeper.

經過註冊中心引用服務

3.3 服務請求結構的定義

服務請求體結構,是在對dubbo在註冊中心上註冊信息的抽象以後的一層封裝,一方面能夠提高開發人員的開發效率,另外下降開發人員自身手動拼接請求的錯誤率.

3.3.1 服務的構成

咱們基於dubbo/rest兩種協議,來分析一下這兩種協議在註冊中心註冊包含哪些信息.

  • dubbo : dubbo://192.168.1.2:10880/com.service.ProductService?dubbo=2.8&methods=getById,getByName
  • rest : rest://192.168.1.2:10081/service/com.service.ProductService?dubbo=2.8&methods=getById,getByName

咱們對這兩個協議公共部分進行提取一下

  • protocol : 協議類型.例如 dubbo://.
  • host : provider主機地址
  • port : provider對外暴露服務的端口
  • interface : 對外暴露服務名稱,在java中是採用包名 + 服務名稱構成,例如com.service.ProductService
  • dubboVersion: dubbo版本
  • method:服務對外暴露的方法,一個服務會同時包含多個方法.
  • query:還有一個就是請求參數列表,此項是在java服務定義的,在註冊信息中沒法體現.

3.3.2 請求體的定義

基於上述服務結構構成的分析,dubbo和rest服務請求結構構成大致相似,咱們對不一樣的協議請求的能夠作以下定義.

// 1. dubbo協議的請求體定義
services.ProductService = (dubbo) => dubbo.proxyService({
    dubboInterface: 'com.service.ProductService',
    methods: {
        getById(id) {
            return [java.Long(id)];
        },
        getByName(name) {
            return [java.String(name)];
        }
    },
});
複製代碼
// rest 請求體定義
services.ProductService = (dubbo) => dubbo.proxyService({
    dubboInterface: 'com.service.ProductService',
    methods: {
        getById(id) {
            return {
                method: 'get',
                query: [parseInt(id)]
            };
        },
        getByName(name) {
            return [String(name)];
        }
    },
});
複製代碼

二者最大不一樣點在於參數定義上的不一樣,dubbo須要強制轉換爲強類型,而rest不須要.

3.4 服務定義的維護

咱們在對服務定義完成以後,接下來就會面臨一個使用上的問題,最直接的方法就是爲每一個工程每一個服務新建一個服務文件,可是一用就會發現一個問題請求定義的文件分散在不一樣工程,沒法進行統一維護升級,維護成本較高.

維護成本

咱們第一個反應是每一個服務抽象出來,各自成爲一個獨立的NPM包,譬如MemberService咱們能夠抽象成爲@dubbo-service/member-service,這樣就能夠解決文件分散在不一樣工程致使的維護問題.

解決維護問題

3.4.1 後續問題

事情到這裏,咱們已經解決了服務如何統必定義的問題,可是仍然沒有解決統一管理與維護的問題.如 :

  • 維護人員職責劃分問題.NPM包的維護工做該交給服務提供方仍是服務調用方?
  • 項目遷移成本問題.若是涉及到項目遷移問題,可能會涉及到不少現有的Java服務初始化的問題,而手動去定義服務工程量巨大,如何下降遷移成本問題是咱們不得不要面臨的問題.

4 最後

若是你以爲此篇文章對你有幫助,就順手點個贊吧~ 很是感謝

有什麼疑問能夠直接評論回覆或者私信我,我會盡我所能回覆你~

相關文章
相關標籤/搜索