Dubbo進階

来源:https://www.cnblogs.com/yangyuanhu/archive/2020/03/10/12458362.html
-Advertisement-
Play Games

註冊中心zookeeper 什麼是註冊中心: 註冊中心就是用來存儲服務信息的地方,就像房屋中介一樣; 為什麼需要註冊中心: 在前面的例子中我們使用了客戶端與伺服器直連的方式完成了服務的調用,在實際開發中這回帶來一些問題,例如伺服器地址變更了,或服務搭建了集群,客戶端不知道服務的地址,此時註冊中心就派 ...


註冊中心zookeeper

什麼是註冊中心:

註冊中心就是用來存儲服務信息的地方,就像房屋中介一樣;

為什麼需要註冊中心:

在前面的例子中我們使用了客戶端與伺服器直連的方式完成了服務的調用,在實際開發中這回帶來一些問題,例如伺服器地址變更了,或服務搭建了集群,客戶端不知道服務的地址,此時註冊中心就派上用場了,服務提供方發佈服務後將服務信息放在zookeeper中,然後消費方從zookeeper獲取伺服器信息,進行調用,這樣就使提供方和消費方解開了耦合,也讓服務提供方可以更方便的搭建集群;

使用:

1.啟動zookeeper,單機和集群都可以

2.在雙方配置文件中指定註冊中心的信息(內容相同)

<!--註冊中心 N/A 表示不使用註冊中心 直連客戶端  地址可以是一個或多個 多個表示集群-->
    <dubbo:registry protocol="zookeeper" address="10.211.55.6:2181,10.211.55.7:2181"/>

需要說明的是,註冊中心不是必須使用zookeeper,dubbo還支持其他三種:Simple,Redis,Multicast,因其優秀的可用性,官方推薦使用zookeeper;

Dubbo的其他配置方式

API配置

簡單的說就是不使用配置文件而是使用使用代碼來完成配置,該方式主要用於測試環境或集成其他框架,不推薦用於生產環境;

服務提供者:

public class ProviderApplication {
    public static void main(String[] args) throws IOException {
//        xmlConfig();
        apiConfig();
        System.in.read();//阻塞主線程保持運行
    }

    private static void apiConfig() {
        //應用配置
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("my-service");
        applicationConfig.setQosEnable(true);
        //註冊中心
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setProtocol("zookeeper");
        registryConfig.setAddress("10.211.55.6:2181,10.211.55.7:2181");
        //rpc協議
        ProtocolConfig protocolConfig = new ProtocolConfig();
        protocolConfig.setName("dubbo");
        protocolConfig.setPort(20880);
        //發佈服務
        ServiceConfig<HelloService> serviceConfig = new ServiceConfig<HelloService>();
        serviceConfig.setApplication(applicationConfig);
        serviceConfig.setProtocol(protocolConfig);
        serviceConfig.setRegistry(registryConfig);
        serviceConfig.setInterface(HelloService.class);
        serviceConfig.setRef(new HelloServiceImpl());
        serviceConfig.export();
    }

消費者:

public class ConsumerApplication {
    public static void main(String[] args) {
//        xmlConfig();
        apiConfig();
    }

    private static void apiConfig() {
        //應用配置
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("my-consumer");
        applicationConfig.setQosEnable(false);
                //註冊中心
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setProtocol("zookeeper");
        registryConfig.setAddress("10.211.55.6:2181,10.211.55.7:2181");
                //調用服務
        ReferenceConfig<HelloService> serviceReferenceConfig = new ReferenceConfig<HelloService>();
        serviceReferenceConfig.setApplication(applicationConfig);
        serviceReferenceConfig.setRegistry(registryConfig);
        serviceReferenceConfig.setInterface(HelloService.class);
        HelloService service = serviceReferenceConfig.get();
        String tom = service.sayHello("tom");
        System.out.println(tom);
    }

註解配置

註解配置是使用較多的一種方式,可加快開發速度,讓我們從繁瑣的配置文件中解脫出來;

Dubbo使用了Spring容器來管理bean,所以配置方式也大同小異,可使用Configuration將一個類作為配置類;在該類中提供必要的幾個bean

服務提供者

配置類:

@Configuration
@EnableDubbo(scanBasePackages = "com.yyh.service")
public class ProviderConfiguration {
    //無論如何配置我們最終需要的還是那幾個bean
    @Bean
    public ApplicationConfig applicationConfig(){
        //應用配置
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("my-service");
        applicationConfig.setQosEnable(true);
        return applicationConfig;
    }

    @Bean
    public RegistryConfig registryConfig(){
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setProtocol("zookeeper");
        registryConfig.setAddress("10.211.55.6:2181,10.211.55.7:2181");
        return registryConfig;
    }

    @Bean
    public ProtocolConfig protocolConfig(){
        //rpc協議
        ProtocolConfig protocolConfig = new ProtocolConfig();
        protocolConfig.setName("dubbo");
        protocolConfig.setPort(20880);
        return protocolConfig;
    }
}

服務實現類:

//註意該註解是Dubbo提供的 不要用錯
@Service
public class HelloServiceImpl implements HelloService {
    public String sayHello(String name) {
        return "hello: "+name;
    }
}

發佈服務:

public static void main(String[] args) throws IOException {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class);
    context.start();
    System.in.read();//阻塞主線程保持運行
}

消費者

配置類:

@Configuration
@EnableDubbo
@ComponentScan("com.yyh.consumer")
public class ConsumerConfiguration {
    @Bean
    public ApplicationConfig applicationConfig(){
        //應用配置
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("my-consumer");
        applicationConfig.setQosEnable(true);
        return applicationConfig;
    }

    @Bean
    public RegistryConfig registryConfig(){
        RegistryConfig registryConfig = new RegistryConfig();
        registryConfig.setProtocol("zookeeper");
        registryConfig.setAddress("10.211.55.6:2181,10.211.55.7:2181");
        return registryConfig;
    }
}

消費者類:

@Component
public class SayHelloConsumer {
  
    @Reference
    private HelloService helloService;

    public void sayHello(){
        String jack = helloService.sayHello("jack");
        System.out.println(jack);
    }
}

執行測試:

public class ConsumerApplication {
    public static void main(String[] args) {
                AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class);
        SayHelloConsumer consumer = context.getBean(SayHelloConsumer.class);
        consumer.sayHello();
    }

可以發現消費者不需要指定ProtocolConfig,主要服務端固定埠即可;

使用properties配置

相比xml和api的方式,properties是體量是最輕的,在面對一些簡單配置時可以採用properties

服務提供者

在resource下提供名為dubbo.properties的文件,內容如下:

dubbo.application.name=my-service
dubbo.application.owner=jerry
dubbo.protocol.dubbo.port=1099
dubbo.registry.address=zookeeper://10.211.55.6:2181

配置類:

@Configuration
@EnableDubbo(scanBasePackages = "com.yyh.service")
@PropertySource("classpath:/dubbo.properties")
public class AnnotationAndPropperties {
}

測試代碼:

public class ProviderApplication {
    public static void main(String[] args) throws IOException {
        annotationAndPropConfig();
        System.out.println("服務已啟動  按任意鍵退出");
        System.in.read();//阻塞   主線程  保持運行
    }
    private static void annotationAndPropConfig() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AnnotationAndPropperties.class);
        context.start();
    }
}

消費者

同樣提供properties文件,但不需要指定protocol

dubbo.application.name=my-service
dubbo.application.qos.enable=false
dubbo.application.owner=jerry
dubbo.registry.address=zookeeper://10.211.55.6:2181

配置類:

@EnableDubbo
@Configuration
@ComponentScan("com.yyh.consumer")
@PropertySource("classpath:/dubbo.properties")
public class AnnotationAndPropConfiguration {
}

消費者類:

@Component
public class SayHelloConsumer {
  
    @Reference
    private HelloService helloService;

    public void sayHello(){
        String jack = helloService.sayHello("jack");
        System.out.println(jack);
    }
}

測試類:

public class ConsumerApplication {
    public static void main(String[] args) {
                AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class);
        SayHelloConsumer consumer = context.getBean(SayHelloConsumer.class);
        consumer.sayHello();
    }

強調:註解使用時,掃描服務的實現類使用dubbo提供的EnableDubbo註解,而掃描其他bean用的是spring的ComponentScan註解;

常用配置項

1.啟動時檢查

預設情況下,dubbo在啟動時會自動檢查依賴(作為消費者)的服務是否可用,若服務不可用則直接拋出異常並阻止容器正常初始化,但在一些情況下我們會希望先啟動程式,因為服務可能會在之後的時間里變為可用的;

啟動檢查註冊中心

<!--啟動程式時是否檢查註冊中心的可用性-->
<dubbo:registry protocol="zookeeper" check="true" address="10.211.55.8:2181,10.211.55.7:2181,10.211.55.6:2181"/>

啟動檢查服務提供方(對所有提供者)

<!--這裡的啟動指的是從容器中獲取一個服務方的代理對象時  即getBean()時是否檢查-->
<dubbo:consumer check="false"/>

啟動檢查服務提供方(對某個提供者)

<!--這裡的啟動指的是從容器中獲取一個服務方的代理對象時  即getBean()時是否檢查-->
<dubbo:reference interface="com.yyh.service.HelloService" id="helloService" />

properties文件寫法:

java -Ddubbo.reference.com.foo.BarService.check=false
#強制修改所有reference的check
java -Ddubbo.reference.check=false
#當reference的check為空時有效
java -Ddubbo.consumer.check=false
java -Ddubbo.registry.check=false

2.集群容錯

在後續的使用中我們可能會對某一個服務部署多個示例形成集群,隨著項目的運行時間越來越常,一些服務節點可能會宕機或是由於網路原因暫時不可用,集群容錯可指定在調用服務失敗時dubbo要採取的行為;

dubbo提供以下6種容錯機制:

策略名稱 優點 缺點 主要應用場景
failover(預設) 對調用者屏蔽調用失敗的信息 額外資源開銷,資源浪費 通訊環境良好,併發不高的場景
failfast 業務快速感知失敗狀態進行自主決策 產生較多報錯的信息 非冪等性操作,需要快速感知失敗的場景
failsafe 即使失敗了也不會影響核心流程 對於失敗的信息不敏感,需要額外的監控 旁路系統,失敗不影響核心流程正確性的場景
failback 失敗自動非同步重試 重試任務可能堆積 對於實時性要求不高,且不需要返回值的一些非同步操作
forking 並行發起多個調用,降低失敗概率 消耗額外的機器資源,需要確保操作冪等性 資源充足,且對於失敗的容忍度較低,實時性要求高的場景
broadcast 支持對所有的服務提供者進行操作 資源消耗很大 通知所有提供者更新緩存或日誌等本地資源信息

冪等性:指的是每次調用都會產生相同的結果,即不會對數據進行寫操作(增刪改)

配置方式:

容錯配置分為兩個粒度:介面級別,方法級別

服務方配置:

服務方配置即將容錯配置放在服務提供方,這樣一來所有消費方就可以使用統一的容錯機制,而不用每個消費方都配一遍;

<!--介面級別:-->
<dubbo:service interface="com.yyh.service.HelloService" ref="helloService" cluster="failover" retries="2"/>
<!--方法級別:-->
<dubbo:service interface="com.yyh.service.HelloService" cluster="failover" ref="helloService">
   <dubbo:method name="sayHello" retries="2"/>
</dubbo:service>

消費方配置:

<!--介面級別:-->
<dubbo:service interface="com.yyh.service.HelloService" ref="helloService" cluster="failsafe"/>
<!--方法級別-->
<dubbo:service interface="com.yyh.service.HelloService" cluster="failover" ref="helloService">
  <dubbo:method name="sayHello" retries="2"/>
</dubbo:service>

3.負載均衡

為了提高系統的可用性,能夠承受更大的併發量,我們會將壓力的服務部署為集群,但是如果每次請求都交給集群中的同一個節點,那這個幾點很可能直接就宕了,所以合理的分配任務給集群中的每一臺機器也是我們必須考慮的事情,好在dubbo已經提供相應的功能,我們只需簡單的配置即可完成負載均衡;

dubbo支持的任務分配方式:

隨機random

顧名思義,從Provider列表中選擇隨機選擇一個,但是我們可以為Provider指定權重,權重越大的被選中的幾率越高,因此對於性能更好的機器應設置更大的權重,反之則反,如果不指定負載均衡,預設使用隨機負載均衡;

輪詢roundrobin

即依次調用所有Provider,每個Provider輪流處理請求,當然我們也可以指定權重,Provider收到的請求數量比約等於權重比; 性能差的機器可能會累積一堆請求,最終拖慢整個系統;

基於活躍數leastactive

每個Provider收到一個請求則將活躍數+1,每處理完成一個請求則活躍數-1,新的請求將會交給活躍數最少的Provider; 簡單的說性能越好的機器將收到更多的請求,反之則反;

基於hash一致consistenthash

將根據Provider的 ip 或者其他的信息為Provider生成一個 hash,並將這個 hash 投射到 [0, 232 - 1] 的圓環上。當有請求時,則使用請求參數計算得出一個hash值。然後查找第一個大於或等於該 hash 值的緩存Provider,並將請求交予該Provider處理。如果當前Provider掛了,則在下一次請求時,為緩存項查找另一個大於其 hash 值的Provider即可。 具體演算法參考:去官網看看

配置方法:

與容錯配置一樣,我們可以選擇在服務方或是消費方進行設置;

服務方:

<!--介面級別-->
<dubbo:service interface="com.yyh.service.HelloService" loadbalance="roundrobin" />
<!--方法級別-->
<dubbo:service interface="com.yyh.service.HelloService" cluster="failover" ref="helloService">
  <dubbo:method name="sayHello" retries="2" loadbalance="roundrobin"/>
</dubbo:service>

消費方:

<!--介面級別-->
<dubbo:reference interface="com.yyh.service.HelloService" id="helloService" loadbalance="roundrobin"/>
<!--方法級別-->
<dubbo:reference interface="com.yyh.service.HelloService" id="helloService">
    <dubbo:method name="sayHello" loadbalance="roundrobin"/>
</dubbo:reference>

直連

即跳過註冊中新直接找服務提供方,必須提前明確服務提供方的地址,所以該方式一般僅用於開發調試;

<dubbo:registry address="N/A"/>

僅訂閱

僅訂閱指的是,不發佈服務到註冊中心,只從註冊中心訂閱依賴的服務;

使用場景:當我們要開發一個新的Provider,而這個Provider需要依賴其他Provider時,使用,其目的是避免正在開發的服務發佈後被消費方調用,因為開發還未完成,可能造成意想不到的結果; 這就用到了僅訂閱,再搭配直連即可完成開發調試;

<dubbo:registry protocol="zookeeper" address="10.211.55.8:2181" register="false"/>

僅註冊

僅註冊指的是,發佈自身服務到註冊中心,但不從註冊中心訂閱依賴的服務;

使用場景: 自身需要對外提供服務,但是依賴的某個服務還在開發調試總,不能正常提供訪問;

<dubbo:registry protocol="zookeeper" address="10.211.55.8:2181" subscribe="false"/>

多註冊中心

對於一些大型系統,為了加快響應速度,可能會在不同地區進行部署,例如阿裡雲分佈在7個不同城市,有的時候可能因為當地系統還未部署完成,但是仍然需要提供訪問,這是就需要我們將相同的服務註冊到多個不同的註冊中心;

反過來,一些時候當前系統依賴的服務可能部署在不同的註冊中心中,這就需要同時向多個不同的註冊中心訂閱服務;

配置方式也非常簡單,添加額外registry即可;

案例:

我們在Common模塊中創建新的介面com.yyh.service.UserService,同時在Provider中實現該介面,最後發佈到註冊中心;

發佈到多個註冊中心

<!--兩個註冊中心-->
<dubbo:registry id="reg1" protocol="zookeeper" address="10.211.55.8:2181,10.211.55.7:2181,10.211.55.6:2181"/>
<dubbo:registry id="reg2" protocol="zookeeper" address="10.211.55.7:2188"/>

<!--註冊到多個註冊中心 id用逗號隔開-->
<dubbo:service registry="reg1,reg2" interface="com.yyh.service.HelloService" ref="helloService" cluster="failsafe" loadbalance="random"/>
<!--userService僅註冊到id為reg2的註冊中心-->
<dubbo:service registry="reg2" interface="com.kkb.service.UserService" ref="userService" cluster="failsafe" loadbalance="random"/>

<!--實現Bean-->
<bean id="helloService" class="com.kkb.service.impl.HelloServiceImpl"/>
<bean id="userService" class="com.kkb.service.impl.UserServiceImpl"/>

從不同註冊中心訂閱

<!--兩個註冊中心-->
<dubbo:registry id="reg1" protocol="zookeeper" address="10.211.55.8:2181,10.211.55.7:2181,10.211.55.6:2181"/>
<dubbo:registry id="reg2" protocol="zookeeper" address="10.211.55.7:2188"/>
<!--從兩個註冊中心分別訂閱 -->
<dubbo:reference interface="com.yyh.service.HelloService" id="helloService" cluster="failover" retries="3" registry="reg1"/>
<dubbo:reference interface="com.yyh.service.UserService" id="userService" cluster="failover" retries="3" registry="reg2"/>
<dubbo:consumer check="false"/>

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Python廣告,鋪天蓋地,小白們霧裡看花,Python無限美好。作為會20幾種語言的編程愛好者,我先說說如果入門python應該想好三大問題,並且在此戳穿三大謊言。 ...
  • 結構體 用一組變數定義一個事物 struct student //student 是一種數據類型 { int id; char name[20]; char sex; int age; }mike,bob;變數定義除了跟在結構體定義後面,還可以:student std1,std2;跟int a,b; ...
  • uwsgi uWSGI是一個Web伺服器,它實現了WSGI協議、uwsgi、http等協議。Nginx中HttpUwsgiModule的作用是與uWSGI伺服器進行交換。 WSGI是一種Web伺服器網關介面。它是一個Web伺服器(如nginx,uWSGI等伺服器)與web應用(如用Flask框架寫的 ...
  • springboot攔截器 說明:和springmvc一樣去實現HandlerInterceptor介面 import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerIn ...
  • 準備工作: 使用環境 :PHPStudy 開啟Apache和Mysql 打開代碼編輯器 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Calculator</title> </head> <body> <f ...
  • 1. 方法 2. 例子 (1)增加/修改 D[key] = value 1 >>> D = {1: 'a', 2: 'b', 3: 'c'} 2 >>> D[4] = 'd' 3 >>> D[1] = 'A' 4 >>> D 5 {1: 'A', 2: 'b', 3: 'c', 4: 'd'} 6 ...
  • 本文主要介紹const修飾符在C++中的主要用法,下麵會從兩個方面進行介紹: 類定義中使用const 、 非類定義中使用const 1. 非類定義中使用const 非類定義中使用const是指:在除了類定義以外的場景中使用const。 1.1 變數 頂層const:變數本身是個常量 底層const: ...
  • 我們見慣了上古時代,由電子管組成的時鐘。在 AI 時代,有沒有更加新潮的時間顯示方式?是的,數據集也能做成時鐘,每天早上,讓 MNIST 手寫數字喚醒你一天的記憶。 ​ MNIST 是電腦視覺中不老的經典,當第一代捲積神經網路在這個手寫數字數據集上綻放出耀眼的光芒,它註定會載入「史冊」。 儘管目前 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...