dubbo 初探

dubbo官網:http://dubbo.io前端

Dubbo背景和簡介(摘自 http://blog.csdn.net/noaman_wgs/article/details/70214612)

Dubbo開始於電商系統,所以在這裏先從電商系統的演變講起。java

  1. 單一應用框架(ORM) 
    當網站流量很小時,只需一個應用,將全部功能以下單支付等都部署在一塊兒,以減小部署節點和成本。 
    缺點:單一的系統架構,使得在開發過程當中,佔用的資源愈來愈多,並且隨着流量的增長愈來愈難以維護 
    這裏寫圖片描述nginx

  2. 垂直應用框架(MVC) 
    垂直應用架構解決了單一應用架構所面臨的擴容問題,流量可以分散到各個子系統當中,且系統的體積可控,必定程度上下降了開發人員之間協同以及維護的成本,提高了開發效率。 
    缺點:可是在垂直架構中相同邏輯代碼須要不斷的複製,不能複用。 
    這裏寫圖片描述git

  3. 分佈式應用架構(RPC) 
    當垂直應用愈來愈多,應用之間交互不可避免,將核心業務抽取出來,做爲獨立的服務,逐漸造成穩定的服務中心 
    這裏寫圖片描述github

  4. 流動計算架構(SOA) 
    隨着服務化的進一步發展,服務愈來愈多,服務之間的調用和依賴關係也愈來愈複雜,誕生了面向服務的架構體系(SOA),也所以衍生出了一系列相應的技術,如對服務提供、服務調用、鏈接處理、通訊協議、序列化方式、服務發現、服務路由、日誌輸出等行爲進行封裝的服務框架算法

從以上是電商系統的演變能夠看出架構演變的過程: 
這裏寫圖片描述spring

  • 單一應用架構apache

    • 當網站流量很小時,只需一個應用,將全部功能都部署在一塊兒,以減小部署節點和成本。
    • 此時,用於簡化增刪改查工做量的 數據訪問框架(ORM) 是關鍵。
  • 垂直應用架構服務器

    • 當訪問量逐漸增大,單一應用增長機器帶來的加速度愈來愈小,將應用拆成互不相干的幾個應用,以提高效率。
    • 此時,用於加速前端頁面開發的 Web框架(MVC) 是關鍵。
  • 分佈式服務架構 
    • 當垂直應用愈來愈多,應用之間交互不可避免,將核心業務抽取出來,做爲獨立的服務,逐漸造成穩定的服務中心,使前端應用能更快速的響應多變的市場需求。
    • 此時,用於提升業務複用及整合的 分佈式服務框架(RPC) 是關鍵。
  • 流動計算架構 
    • 當服務愈來愈多,容量的評估,小服務資源的浪費等問題逐漸顯現,此時需增長一個調度中心基於訪問壓力實時管理集羣容量,提升集羣利用率。
    • 此時,用於提升機器利用率的 資源調度和治理中心(SOA) 是關鍵。

在這裏插播一條關於RPC的簡介: 
RPC(Remote Procedure Call Protocol):遠程過程調用: 
兩臺服務器A、B,分別部署不一樣的應用a,b。當A服務器想要調用B服務器上應用b提供的函數或方法的時候,因爲不在一個內存空間,不能直接調用,須要經過網絡來表達調用的語義傳達調用的數據。 
說白了,就是你在你的機器上寫了一個程序,我這邊是沒法直接調用的,這個時候就出現了一個遠程服務調用的概念。網絡

RPC是一種經過網絡從遠程計算機程序上請求服務,而不須要了解底層網絡技術的協議。RPC協議假定某些傳輸協議的存在,如TCP或UDP,爲通訊程序之間攜帶信息數據。在OSI網絡通訊模型中,RPC跨越了傳輸層和應用層。RPC使得開發包括網絡分佈式多程序在內的應用程序更加容易。 
RPC採用客戶機/服務器模式。請求程序就是一個客戶機,而服務提供程序就是一個服務器。首先,客戶機調用進程發送一個有進程參數的調用信息到服務進程,而後等待應答信息。在服務器端,進程保持睡眠狀態直到調用信息到達爲止。當一個調用信息到達,服務器得到進程參數,計算結果,發送答覆信息,而後等待下一個調用信息,最後,客戶端調用進程接收答覆信息,得到進程結果,而後調用執行繼續進行。

RPC須要解決的問題: 
(能夠稍做了解,詳情可查看別的博文)

  • 通信問題 : 主要是經過在客戶端和服務器之間創建TCP鏈接,遠程過程調用的全部交換的數據都在這個鏈接裏傳輸。鏈接能夠是按需鏈接,調用結束後就斷掉,也能夠是長鏈接,多個遠程過程調用共享同一個鏈接。
  • 尋址問題 : A服務器上的應用怎麼告訴底層的RPC框架,如何鏈接到B服務器(如主機或IP地址)以及特定的端口,方法的名稱名稱是什麼,這樣才能完成調用。好比基於Web服務協議棧的RPC,就要提供一個endpoint URI,或者是從UDDI服務上查找。若是是RMI調用的話,還須要一個RMI Registry來註冊服務的地址。
  • 序列化 與 反序列化 : 當A服務器上的應用發起遠程過程調用時,方法的參數須要經過底層的網絡協議如TCP傳遞到B服務器,因爲網絡協議是基於二進制的,內存中的參數的值要序列化成二進制的形式,也就是序列化(Serialize)或編組(marshal),經過尋址和傳輸將序列化的二進制發送給B服務器。 
    同理,B服務器接收參數要將參數反序列化。B服務器應用調用本身的方法處理後返回的結果也要序列化給A服務器,A服務器接收也要通過反序列化的過程。

Dubbo是什麼

Dubbo是:

  • 一款分佈式服務框架
  • 高性能和透明化的RPC遠程服務調用方案
  • SOA服務治理方案

天天爲2千多個服務提供大於30億次訪問量支持,並被普遍應用於阿里巴巴集團的各成員站點以及別的公司的業務中。


Dubbo架構

這裏寫圖片描述

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

調用流程 
0.服務容器負責啓動,加載,運行服務提供者。 
1.服務提供者在啓動時,向註冊中心註冊本身提供的服務。 
2.服務消費者在啓動時,向註冊中心訂閱本身所需的服務。 
3.註冊中心返回服務提供者地址列表給消費者,若是有變動,註冊中心將基於長鏈接推送變動數據給消費者。 
4.服務消費者,從提供者地址列表中,基於軟負載均衡算法,選一臺提供者進行調用,若是調用失敗,再選另外一臺調用。 
5.服務消費者和提供者,在內存中累計調用次數和調用時間,定時每分鐘發送一次統計數據到監控中心


Dubbo註冊中心

對於服務提供方,它須要發佈服務,並且因爲應用系統的複雜性,服務的數量、類型也不斷膨脹; 
對於服務消費方,它最關心如何獲取到它所須要的服務,而面對複雜的應用系統,須要管理大量的服務調用。 
並且,對於服務提供方和服務消費方來講,他們還有可能兼具這兩種角色,即既須要提供服務,有須要消費服務。

經過將服務統一管理起來,能夠有效地優化內部應用對服務發佈/使用的流程和管理。服務註冊中心能夠經過特定協議來完成服務對外的統一。

Dubbo提供的註冊中心有以下幾種類型可供選擇

  • Multicast註冊中心
  • Zookeeper註冊中心
  • Redis註冊中心
  • Simple註冊中心

Dubbo優缺點

優勢:

  1. 透明化的遠程方法調用 
    - 像調用本地方法同樣調用遠程方法;只需簡單配置,沒有任何API侵入。
  2. 軟負載均衡及容錯機制 
    • 可在內網替代nginx lvs等硬件負載均衡器。
  3. 服務註冊中心自動註冊 & 配置管理 
    -不須要寫死服務提供者地址,註冊中心基於接口名自動查詢提供者ip。 
    使用相似zookeeper等分佈式協調服務做爲服務註冊中心,能夠將絕大部分項目配置移入zookeeper集羣。
  4. 服務接口監控與治理 
    -Dubbo-admin與Dubbo-monitor提供了完善的服務接口管理與監控功能,針對不一樣應用的不一樣接口,能夠進行 多版本,多協議,多註冊中心管理。

缺點:

    • 只支持JAVA語言

 

Dubbo Demo:

新建項目dubbo-demo,新建3個子項目:

dubbo-demo-common 公共項目(包含公共接口、公共domain,由於provider項目和consumer項目都有這些,因此抽出來放入另外一個項目)

dubbo-demo-provider 服務提供者(依賴dubbo-demo-common項目 )

dubbo-demo-consumer 服務消費者(依賴dubbo-demo-common項目 )

公共項目

User: 在dubbo 2.6,必須實現Serializable接口,不然會報錯:java.lang.IllegalStateException: Serialized class com.atyang.dubbo.domain.User must implement java.io.Serializable

public class User implements Serializable{
    private int id;
    private String name;

    public User() {
    }

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

UserService

public interface UserService {
    User getUser(int id);
}

UserUtil : 獲取用戶的工具類

public class UserUtil {
    private static Map<Integer, User> map = new HashMap<Integer, User>(10);
    static {
        for(int i=1;i<=10;i++){
            map.put(i, new User(i, "我是用戶-" + i));
        }
    }

    public static User getUser(int id){
        User user = map.get(id);
        if(null == user){
            user = new User(0, "----用戶不存在----");
        }
        return user;
    }
}

 

服務提供者

 

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>com.atyang.dubbo</artifactId>
        <groupId>dubbo-demo</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>dubbo-demo-provider</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.0</version>
        </dependency>
        <!--zk客戶端,不依賴的話,會報錯:Caused by: java.lang.ClassNotFoundException: org.I0Itec.zkclient.IZkStateListener-->
        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>
        <!--公共項目-->
        <dependency>
            <groupId>dubbo-demo</groupId>
            <artifactId>dubbo-demo-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

</project>

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    <dubbo:application name="demo-provider"/>
    <!-- 註冊中心地址 -->
    <dubbo:registry address="zookeeper://localhost:2181"/>
    <!-- dubbo暴露的服務端口 -->
    <dubbo:protocol name="dubbo" port="20880"/>

    <!--註冊服務到註冊中心-->
    <dubbo:service interface="com.atyang.dubbo.service.UserService" ref="userService"/>
    <bean id="userService" class="com.atyang.dubbo.service.impl.UserServiceImpl"/>
</beans>

 

 Service實現

public class UserServiceImpl implements UserService {
    public User getUser(int id) {
        System.out.println("--------用戶服務被消費--------- id=" + id);
        return UserUtil.getUser(id);
    }
}

啓動類

public class ProviderStart {
    public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                new String[] {"classpath:provider-spring.xml"});
        context.start();
        System.out.println("--------消費端服務已啓動-----");
        // press any key to exit
        System.in.read();
    }
}

服務消費者

 

 

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
    <dubbo:application name="demo-consumer"/>
    <dubbo:registry address="zookeeper://localhost:2181"/>
    <dubbo:reference id="userService" interface="com.atyang.dubbo.service.UserService"/>
</beans>

啓動類

public class ConsumerStart {
    public static void main(String[] args) throws IOException {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                new String[]{"classpath:consumer-spring.xml"});
        context.start();
        // obtain proxy object for remote invocation
        UserService userService = context.getBean("userService", UserService.class);
        // execute remote invocation
        User user = userService.getUser(3);
        // show the result
        System.out.println(user);
        // press any key to exit
        System.in.read();
    }
}

 

 

 代碼完成後,先啓動zookeeper,用zkCli.cmd鏈接後,查看zk節點: ls /

目前只有默認的 zookeeper節點

 啓動服務提供者

再查看zk節點,多了個dubbo

而後再啓動服務消費者,獲取到了用戶信息。消費端調用服務,就像調用本地方法同樣。dubbo的rpc就這麼方便

相關文章
相關標籤/搜索