RPC:Dubbo

Start

RPC

Remote Procedure Call 远程过程调用

  • 主要是基于TCP/IP协议,长连接,四个核心的组件:Client,Server,Client StubServer Stub
  • 选择RPC框架时的关注点:
    • I/O: 同步/异步,长/短连接
    • 线程调度模型: 单/多线程,线程池,线程调度算法的性能
    • 序列化方式: 可读 (eg: xml,json),二进制(eg: fastjson,jdk自带的序列化)
    • 多语言支持
    • 服务治理(服务发现,监控)
  • 流行的RPC框架:
    • Dubbo(阿里)/ Dubbox(当当): 基于Java开发,只支持Java的客户端和服务端
    • Motan (新浪): 基于Java开发
    • Thrift(Facebook -> Apache): 跨语言的RPC框架,无服务治理
    • Grpc (谷歌): 基于HTTP2.0协议(基于二进制的HTTP协议升级版本),跨语言的RPC框架(应用主要面向移动端)
  • 各RPC框架对比: RPC

Dubbo

  • 一款分布式服务框架
  • 高性能和透明化的RPC远程服务调用方案
  • SOA服务治理方案
  • 提供了三大核心能力:
    • 面向接口的远程方法调用
    • 智能容错和负载均衡
    • 服务自动注册和发现
  • 基于Java开发,只支持Java的客户端和服务端
  • 可以和Spring框架无缝集成

Dubbo 架构

  • 角色:
    • Provider: 暴露服务的服务提供方
    • Consumer: 调用远程服务的服务消费方
    • Registry: 服务注册与发现的注册中心
    • Monitor: 统计服务的调用次数和调用时间的监控中心
    • Container: 服务运行容器
  • 调用关系
    • Container负责启动,加载,运行Provider
    • Provider 启动时向注册中心注册自己提供的服务
    • Consumer 启动时向注册中心订阅自己所需的服务
    • Registry 返回服务提供者地址列表给Consumer (如果有变更,Registry将基于长连接推送变更数据给Consumer)
    • Consumer 从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用
    • Provider & Consumer 在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到 Monitor
  • 注:
    • Provider & Consumer & Registory 之间使用的是长连接
    • Provier & Consumer 之间使用非阻塞IO(NIO)通讯
    • Dubbo支持的注册中心有: Multicast,Zookeeper,Redis,Simple,下面的示例均使用Zookeeper

Dubbo Quick Start | dubbo-demo

HelloWorld

dependency

pom.xml

<!-- Dubbo (include spring)-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.6.2</version>
</dependency>

<!-- Curator (include zookeeper) -->
<!-- Note: need to change zookeeper version,the beta version zookeeper has issues -->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>4.0.1</version>
    <exclusions>
        <exclusion>
             <groupId>org.apache.zookeeper</groupId>
             <artifactId>zookeeper</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.6</version>
    <exclusions>
        <exclusion>
              <groupId>org.slf4j</groupId>
              <artifactId>slf4j-api</artifactId>
        </exclusion>
        <exclusion>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<!-- Junit -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

Provider

  • resources/demo-provider.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
             xmlns="http://www.springframework.org/schema/beans"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
             http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    
          <dubbo:application name="demoProvider"/>
          <dubbo:registry address="zookeeper://localhost:2181"/>
          <dubbo:protocol name="dubbo" port="20880"/>
          <dubbo:service interface="com.cj.dubbo.service.DemoService" ref="demoService"/>
          <bean id="demoService" class="com.cj.dubbo.service.DemoServiceImpl"/>
    
      </beans>
    
  • Service interface

    package com.cj.dubbo.service;
    public interface DemoService {
       String sayHello(String name);
    }
    
  • Service Impl

    package com.cj.dubbo.service;
    public class DemoServiceImpl implements DemoService {
      @Override
      public String sayHello(String name) {
          return "Hello "+name;
      }
    }
    

Consumer

  • resources/demo-consumer.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
         xmlns="http://www.springframework.org/schema/beans"
         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
         http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    
      <dubbo:application name="demoConsumer"/>
      <dubbo:registry address="zookeeper://192.168.99.100:2181"/>
      <dubbo:reference id="demoService" check="false" interface="com.cj.dubbo.service.DemoService"/>
    </beans>
    
  • Service interface

    package com.cj.dubbo.service;
    public interface DemoService {
       String sayHello(String name);
    }
    

Test

package com.cj.dubbo;
import java.io.IOException;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.cj.dubbo.consumer.HelloConsumerService;
import com.cj.dubbo.service.DemoService;
import com.cj.dubbo.service.HelloService;

public class DemoDubboTest {
    @Test
    public void runDemoProvider() throws IOException {
        System.setProperty("java.net.preferIPv4Stack", "true");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"demo-provider.xml"});
        context.start();
        System.out.println("Provider started.");
        System.in.read(); // press any key to exit
    }

    @Test
    public void runDemoConsumer() {
        // System.setProperty("java.net.preferIPv4Stack", "true");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"demo-consumer.xml"});
        context.start();
        DemoService demoService = (DemoService) context.getBean("demoService"); // obtain proxy object for remote invocation
        String hello = demoService.sayHello("world"); // execute remote invocation
        System.out.println(hello); // show the result
    }
}

Check zookeeper

[zk: zk01:2181(CONNECTED) 9] ls /dubbo
[com.cj.dubbo.service.DemoService]
[zk: zk01:2181(CONNECTED) 10] ls /dubbo/com.cj.dubbo.service.DemoService
[consumers, configurators, routers, providers]

Demo

Provider (SpringBoot)

  1. pom.xml

     <!-- springboot -->
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
     </dependency>
     <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
     </dependency>
    
     <!-- springboot dubbo -->
     <!-- <dependency>
         <groupId>com.alibaba.spring.boot</groupId>
         <artifactId>dubbo-spring-boot-starter</artifactId>
         <version>2.0.0</version>
     </dependency> -->
    
     <!-- Dubbo (include spring) -->
     <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>dubbo</artifactId>
         <version>2.6.2</version>
     </dependency>
    
     <!-- Curator (include zookeeper) -->
     <!-- Note: need to change zookeeper version,the beta version zookeeper has issues -->
     <dependency>
         <groupId>org.apache.curator</groupId>
         <artifactId>curator-recipes</artifactId>
         <version>4.0.1</version>
         <exclusions>
             <exclusion>
                  <groupId>org.apache.zookeeper</groupId>
                  <artifactId>zookeeper</artifactId>
             </exclusion>
         </exclusions>
     </dependency>
     <dependency>
         <groupId>org.apache.zookeeper</groupId>
         <artifactId>zookeeper</artifactId>
         <version>3.4.6</version>
         <exclusions>
             <exclusion>
                   <groupId>org.slf4j</groupId>
                   <artifactId>slf4j-api</artifactId>
             </exclusion>
             <exclusion>
                  <groupId>org.slf4j</groupId>
                  <artifactId>slf4j-log4j12</artifactId>
             </exclusion>
         </exclusions>
     </dependency>
    
  2. Configure

    • resources/log4j.properties
        ###set log levels###
        log4j.rootLogger=warn, stdout
        ###output to the console###
        log4j.appender.stdout=org.apache.log4j.ConsoleAppender
        log4j.appender.stdout.Target=System.out
        log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
        log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy hh:mm:ss:sss z}] %t %5p %c{2}: %m%n
      
    • resources/provider.xml

        <?xml version="1.0" encoding="UTF-8"?>
        <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
               xmlns="http://www.springframework.org/schema/beans"
               xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
               http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
      
            <dubbo:application name="helloProvider"/>
            <dubbo:registry address="zookeeper://localhost:2181"/>
            <dubbo:protocol name="dubbo" port="20881"/>
            <dubbo:service interface="com.cj.dubbo.service.HelloService"  ref="helloService"/>
      
        </beans>
      
    • Config: import the provider.xml

        package com.cj.dubbo.config;
        import org.springframework.context.annotation.Configuration;
        import org.springframework.context.annotation.ImportResource;
      
        @Configuration
        @ImportResource(locations={"classpath:provider.xml"})
        public class ProviderConfig {
        }
      
  3. Service

    • interface
        package com.cj.dubbo.service;
        public interface HelloService {
            public String sayHello(String name);
        }
      
    • implement

        package com.cj.dubbo.provider;
        import org.springframework.stereotype.Component;
        import com.cj.dubbo.service.HelloService;
      
        @Component("helloService")
        public class HelloServiceImpl implements HelloService {
            @Override
            public String sayHello(String name) {
                return "Hello, " + name + " (from Spring Boot)";
            }
        }
      
  4. Start

     package com.cj.dubbo;
     import org.springframework.boot.SpringApplication;
     import org.springframework.boot.autoconfigure.SpringBootApplication;
    
     @SpringBootApplication
     public class HelloProviderApplication {
         public static void main(String[] args) {
             SpringApplication.run(HelloProviderApplication.class,args);
             System.out.println("Start Application");
         }
     }
    

Consumer (Spring)

  1. pom.xml

     <!-- Curator(include Zookeeper) -->
     <dependency>
         <groupId>org.apache.curator</groupId>
         <artifactId>curator-recipes</artifactId>
         <version>4.0.1</version>
     </dependency>
    
     <!-- Dubbo (include Spring) -->
     <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>dubbo</artifactId>
         <version>2.6.2</version>
     </dependency>
    
     <!-- Junit -->
     <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.12</version>
     </dependency>
    
  2. Configure: resource/hello-consumer.xml

     <?xml version="1.0" encoding="UTF-8"?>
     <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
            xmlns="http://www.springframework.org/schema/beans"
            xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
            http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
    
         <dubbo:application name="helloConsumer"/>
         <dubbo:registry address="zookeeper://localhost:2181"/>
         <dubbo:reference id="helloService" check="false"  interface="com.cj.dubbo.service.HelloService"/>
    
         <bean id="helloConsumerService" class="com.cj.dubbo.consumer.HelloConsumerService">
             <property name="helloService" ref="helloService"/>
         </bean>
     </beans>
    
  3. Service

    • interface (same with Provider service interface)
        package com.cj.dubbo.service;
        public interface HelloService {
            public String sayHello(String name);
        }
      
    • Call the provided Service

        package com.cj.dubbo.consumer;
        import com.cj.dubbo.service.HelloService;
      
        public class HelloConsumerService {
            private HelloService helloService;
            public HelloService getHelloService() {
                return helloService;
            }
            public void setHelloService(HelloService helloService) {
                this.helloService = helloService;
            }
            public void printSay(String name) {
                if(helloService==null)
                    System.out.println("Can't get helloService!");
                System.out.println(helloService.sayHello(name));
            }
        }
      
  4. Test

     public class DemoDubboTest {
         @Test
         public void runHelloConsumer() {
             // System.setProperty("java.net.preferIPv4Stack", "true");
             ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"hello-consumer.xml"});
             context.start();
             HelloService helloService = (HelloService) context.getBean("helloService"); // obtain proxy object for remote invocation
             String hello=helloService.sayHello("Girl"); // execute remote invocation
             System.out.println(hello);                    // show the result
    
             System.out.println("---- Consume HelloService ----");
             HelloConsumerService consumer=context.getBean(HelloConsumerService.class);
             consumer.printSay("Boy");
    
         }
     }
    
  5. Check zookeeper

     [zk: zk01:2181(CONNECTED) 9] ls /dubbo
     [com.cj.dubbo.service.DemoService, com.cj.dubbo.service.HelloService]
    
     [zk: zk01:2181(CONNECTED) 18] ls /dubbo/com.cj.dubbo.service.HelloService      
     [consumers, configurators, routers, providers]
    
     [zk: zk01:2181(CONNECTED) 19] ls /dubbo/com.cj.dubbo.service.HelloService/providers
     [dubbo%3A%2F%2F192.168.31.78%3A20881%2Fcom.cj.dubbo.service.HelloService%3Fanyhost%3Dtrue%26application%3DhelloProvider%26dubbo%3D2.6.2%26generic%3Dfalse%26interface%3Dcom.cj.dubbo.service.HelloService%26methods%3DsayHello%26pid%3D1359%26side%3Dprovider%26timestamp%3D1549812635667]
    
     [zk: zk01:2181(CONNECTED) 20] ls /dubbo/com.cj.dubbo.service.HelloService/consumers
     []
    

Reference

My demo: dubbo-demo

什么是Dubbo

dubbo的详细介绍

dubbo从入门到精通