dubbo学习笔记

目录

 

一、dubbo简介

二、dubbo环境搭建&快速启动

三、dubbo配置

四、Dubbo执行过程

五、横向对比

 


一、dubbo简介

1.1 dubbo是什么

dubbo是一款高性能、轻量级的开源Java RPC框架

1.2 dubbo主要功能

  • 面向接口的远程方法调用

  • 智能容错和负载均衡

  • 以及服务自动注册和发现

1.3 dubbo结构

角色:注册中心,服务提供者,服务消费者,dubbo框架容器,监控中心

dubbo启动流程:

0)dubbo容器启动,加载、运行服务提供者

1)服务提供者启动时,向注册中心注册自己的服务

2)服务消费者启动时,从注册中心订阅自己所需的服务

3)注册中心返回服务提供者的地址列表给消费者,当服务提供者发生变化时;注册中心将基于长连接推送变更数据给消费者

4)服务消费者基于软负载均衡策略执行服务调用

5)服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心

1.4 dubbo发展历程

独家专访阿里高级技术专家北纬:Dubbo开源重启半年来的快意江湖

二、dubbo环境搭建&快速启动

2.1 注册中心(zookeeper)安装 

wget http://mirrors.cnnic.cn/apache/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz  #嫌慢的化可以直接下载附件
tar -zxvf zookeeper-3.4.14.tar.gz
cd zookeeper-3.4.14
cp conf/zoo_sample.cfg conf/zoo.cfg   #解压包里面只有zoo_sample.cfg,而没有zoo.cfg,zookeeper的启动依赖zoo.cfg
																			#按照自己需求配置zookeeper启动属性
 bash zkServer.sh start               #默认启动端口为2181

zookeeper-3.4.14.tar.gz

注册中心

成熟度

优点

缺点

建议

Zookeeper注册中心

Stable

支持基于网络的集群方式,有广泛周边开源产品,建议使用dubbo-2.3.3以上版本(推荐使用)

依赖于Zookeeper的稳定性

可用于生产环境

Redis注册中心

Stable

支持基于客户端双写的集群方式,性能高

要求服务器时间同步,用于检查心跳过期脏数据

可用于生产环境

Multicast注册中心

Tested

去中心化,不需要安装注册中心

依赖于网络拓扑和路由,跨机房有风险

小规模应用或开发测试环境

Simple注册中心

Tested

Dogfooding,注册中心本身也是一个标准的RPC服务

没有集群支持,可能单点故障

试用

2.2 dubbo管理控制台安装

SpringBoot + dubbo-admin-server + dubbo-admin-ui:(可选,不影响使用。安装管理控制台,可以可视化的管理服务)

  1. 下载管理控制台 https://github.com/apache/incubator-dubbo-admin (springboot项目)

  2. 启动dubbo-admin-server(后面需要在本地启动服务提供中和服务消费者,为了防止端口冲突,此处配置端口为8888)

  3. 启动dubbo-admin-ui,前端使用的是vue,需要Node环境

    nvm install 8.4.0
    nvm use 8.4.0
    cd dubbo-admin-ui
    npm install
    #更改config/index.js的target端口号为8888(dubbo-admin-server配置的端口号)
    npm run dev
    #浏览器访问localhost:8081

     

2.3 dubbo服务提供者

  1. pom.xml

    
        
            com.alibaba
            dubbo-bom
            2.6.4
            pom
            import
        
        
            com.alibaba
            dubbo
            2.6.4
        
        
            org.springframework
            spring-context
            4.3.10.RELEASE
        
        
            org.apache.curator
            curator-framework
            2.12.0
        
    
  2. provider.xml

    
    
        
        
        
        
        
        
        
        
        
        
    
  3. provider代码

    3.1 HelloWorldService.java

    public interface HelloWorldService {
        String sayHello(String name);
    }

    3.2 HelloWorldServiceImpl.java

    import com.sankuai.api.HelloWorldService;
    import org.springframework.stereotype.Service;
    
    @Service("helloWorldService")
    public class HelloWorldServiceImpl implements HelloWorldService {
    
        @Override
        public String sayHello(String name) {
            System.out.println("hello" + name);
            return "hello" + name;
        }
    }

    3.3 加载spring配置

    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import java.io.IOException;
    public class Main {
        public static void main(String[] args) throws IOException {
            ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("provider.xml");
            ctx.start();
            System.in.read();
        }
    }

    3.4 在监控中心观察到服务
    dubbo学习笔记_第1张图片

2.4 dubbo消费者

  1. pom.xml

    
        
            com.alibaba
            dubbo-bom
            2.6.4
            pom
            import
        
        
            com.alibaba
            dubbo
            2.6.4
        
        
            org.springframework
            spring-context
            4.3.10.RELEASE
        
        
            org.apache.curator
            curator-framework
            2.12.0
        
        
            com.sankuai
            dubbo.studying
            1.0-SNAPSHOT 
        
    
  2. consumer.xml

    
    
        
        
        
        
        
        
        
        
    
  3. consumer代码

    3.1 Conmunicate.java

    public interface Conmunicate {
        String communicate(String name) ;
    }

    3.2 ConmunicateImpl.java

    import com.sankuai.api.HelloWorldService;
    import com.sankuai.consumer.api.Conmunicate;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    @Service("conmunicateService")
    public class ConmunicateImpl implements Conmunicate {
        @Autowired
        HelloWorldService helloWorldService;
    
        public String communicate(String name) {
            return helloWorldService.sayHello(name);
        }
    }

    3.3 加载spring配置,并调用远程服务

    import com.sankuai.consumer.impl.ConmunicateImpl;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import java.io.IOException;
    
    public class Main {
        public static void main(String[] args) throws IOException {
            ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("consumer.xml");
            ConmunicateImpl conmunicate = (ConmunicateImpl) ctx.getBean("conmunicateService");
            String s = conmunicate.communicate("zhuyafeng");
            System.out.println(s);
            System.in.read();
        }
    }

    3.4 监控中心观察消费者信息

    dubbo学习笔记_第2张图片

2.5 dubbo监控中心安装

  1. 下载管理控制中心(https://github.com/apache/dubbo-admin/tree/master)

三、dubbo配置

3.1 配置之间的依赖关系

3.2 dubbo标签配置

标签

用途

解释

备注

服务配置

用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心

 

引用配置

用于创建一个远程服务代理,一个引用可以指向多个注册中心

引用缺省是延迟初始化的,只有引用被注入到其它 Bean,或被 getBean() 获取,才会初始化。如果需要饥饿加载,即没有人引用也立即生成动态代理,可以配置:

协议配置

用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受

 

应用配置

用于配置当前应用信息,不管该应用是提供者还是消费者

 

模块配置

用于配置当前模块信息,可选

 

注册中心配置

用于配置连接注册中心相关信息

 

监控中心配置

用于配置连接监控中心相关信息,可选

 

提供方配置

当 ProtocolConfig 和 ServiceConfig 某属性没有配置时,采用此缺省值,可选

 

消费方配置

当 ReferenceConfig 某属性没有配置时,采用此缺省值,可选

 

方法配置

用于 ServiceConfig 和 ReferenceConfig 指定方法级的配置信息

 

参数配置

用于指定方法参数配置

 

 

3.3 常用dubbo配置(以xml配置为例)

功能

功能

配置方式

备注

启动时检查

Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题,默认 check="true"

关闭所有服务检查

关闭注册中心检查

 

集群容错

在集群调用失败时,Dubbo 提供了多种容错方案,缺省为 failover 重试

集群容错模式

failover Cluster:失败自动切换,当出现失败,重试其它服务器

Failfast Cluster:快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。

Failsafe Cluster:失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。

Failback Cluster:失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作

Forking Cluster:并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。

 

默认为failover,配合重试使用(支持服务级,reference级和方法级配置)

负载均衡

在集群负载均衡时,Dubbo 提供了多种均衡策略,缺省为 random 随机调用

服务端服务级别

客户端服务级别

服务端方法级别

客户端方法级别

  1. 基于权重的随机负载均衡机制(random LoadBalance) 默认

  2. 基于权重的轮询负载均衡(RoundRobin LoadBalance)

  3. 基于最少活跃数负载均衡(LeastActive LoadBalance):选择响应速度最快的

  4. 一致性哈希负载均衡 (consistentHash LoadBalance)

直连服务提供者

在开发及测试环境下,经常需要绕过注册中心,只测试指定服务提供者,这时候可能需要点对点直连,点对点直连方式,将以服务接口为单位,忽略注册中心的提供者列表,A 接口配置点对点,不影响 B 接口从注册中心获取列表。

不要在线上使用!!!

多协议暴露

Dubbo 允许配置多协议,在不同服务上支持不同协议或者同一服务上同时支持多种协议。



    
    
    
    
    
    
    

 

 

 

服务分组

当一个接口有多种实现时,可以用 group 区分

服务提供者


服务消费者


dubbo2.2.0以上版本,服务消费者支持使用任意版本

 

多版本

当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。

可以按照以下的步骤进行版本迁移:

  1. 在低压力时间段,先升级一半提供者为新版本

  2. 再将所有消费者升级为新版本

  3. 然后将剩下的一半提供者升级为新版本

老版本服务提供者配置:

新版本服务提供者配置:

老版本服务消费者配置:

新版本服务消费者配置:

如果不需要区分版本,可以按照以下的方式配置 [1]:

 

Consumer只能消费与自己 “接口+分组+版本号” 一致的Provider提供的服务。

 

结果缓存

结果缓存 ,用于加速热门数据的访问速度,Dubbo 提供声明式缓存,以减少用户加缓存的工作量

接口级设置

方法级设置

 
  

 

 

上下文信息

获取当前RPC的上下文信息

// 本端是否为消费端,这里会返回true
boolean isConsumerSide = RpcContext.getContext().isConsumerSide();
// 获取最后一次调用的提供方IP地址
String serverIP = RpcContext.getContext().getRemoteHost();
// 获取当前服务配置信息,所有配置信息都将转换为URL的参数
String application = RpcContext.getContext().getUrl().getParameter("application");

 

 

provider异步执行

 

1.定义CompletableFuture签名的接口

public interface AsyncService {
    CompletableFuture sayHello(String name);
}

public class AsyncServiceImpl implements AsyncService {
    @Override
    public CompletableFuture sayHello(String name) {
        RpcContext savedContext = RpcContext.getContext();
        // 建议为supplyAsync提供自定义线程池,避免使用JDK公用线程池
        return CompletableFuture.supplyAsync(() -> {
            System.out.println(savedContext.getAttachment("consumer-key1"));
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "async response from provider.";
        });
    }
}

通过return CompletableFuture.supplyAsync(),业务执行已从Dubbo线程切换到业务线程,避免了对Dubbo线程池的阻塞。

2.使用AsyncContext

Dubbo提供了一个类似Serverlet 3.0的异步接口AsyncContext,在没有CompletableFuture签名接口的情况下,也可以实现Provider端的异步执行。

public interface AsyncService {
    String sayHello(String name);
}

public class AsyncServiceImpl implements AsyncService {
    public String sayHello(String name) {
        final AsyncContext asyncContext = RpcContext.startAsync();
        new Thread(() -> {
            // 如果要使用上下文,则必须要放在第一句执行
            asyncContext.signalContextSwitch();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 写回响应
            asyncContext.write("Hello " + name + ", response from provider.");
        }).start();
        return null;
    }
}

 

 

consumer异步调用

 

1.使用CompletableFuture签名的接口,此方法依赖于服务提供者事先定义CompletableFuture签名的服务

// 调用直接返回CompletableFuture
CompletableFuture future = asyncService.sayHello("async call request");
// 增加回调
future.whenComplete((v, t) -> {
    if (t != null) {
        t.printStackTrace();
    } else {
        System.out.println("Response: " + v);
    }
});
// 早于结果输出
System.out.println("Executed before response return.");

 

2.使用RpcContext


      
// 此调用会立即返回null
asyncService.sayHello("world");
// 拿到调用的Future引用,当结果返回后,会被通知和设置到此Future
CompletableFuture helloFuture = RpcContext.getContext().getCompletableFuture();
// 为Future添加回调
helloFuture.whenComplete((retValue, exception) -> {
    if (exception == null) {
        System.out.println(retValue);
    } else {
        exception.printStackTrace();
    }
});

 

3. 利用Java 8提供的default接口实现,重载一个带有带有CompletableFuture签名的方法

public interface GreetingsService {
    String sayHi(String name);
    
    // AsyncSignal is totally optional, you can use any parameter type as long as java allows your to do that.
    default CompletableFuture sayHi(String name, AsyncSignal signal) {
        return CompletableFuture.completedFuture(sayHi(name));
    }
}

方法1是直接使用服务端实现的异步执行

 

方法2,3是在客户端执行异步调用

 

 

Provider端异步执行和Consumer端异步调用是相互独立的,你可以任意正交组合两端配置

  • Consumer同步 - Provider同步

  • Consumer异步 - Provider同步

  • Consumer同步 - Provider异步

  • Consumer异步 - Provider异步

 

本地伪装

本地伪装通常用于服务降级,比如某验权服务,当服务提供方全部挂掉后,客户端不抛出异常,而是通过 Mock 数据返回授权失败。

package com.foo;
public class BarServiceMock implements BarService {
    public String sayHello(String name) {
        // 你可以伪造容错数据,此方法只在出现RpcException时被执行
        return "容错数据";
    }
}

 

 

本地伪装

本地伪装通常用于服务降级,比如某验权服务,当服务提供方全部挂掉后,客户端不抛出异常,而是通过 Mock 数据返回授权失败。

package com.foo;
public class BarServiceMock implements BarService {
    public String sayHello(String name) {
        // 你可以伪造容错数据,此方法只在出现RpcException时被执行
        return "容错数据";
    }
}

 

 

令牌验证

通过令牌验证在注册中心控制权限,以决定要不要下发令牌给消费者,可以防止消费者绕过注册中心访问提供者,另外通过注册中心可灵活改变授权方式,而不需修改或升级提供者

可以全局设置开启令牌验证:

也可在服务级别设置:

 

线程栈自动dump

当业务线程池满时,我们需要知道线程都在等待哪些资源、条件,以找到系统的瓶颈点或异常点。dubbo通过Jstack自动导出线程堆栈来保留现场,方便排查问题

 

默认策略:

  • 导出路径,user.home标识的用户主目录

  • 导出间隔,最短间隔允许每隔10分钟导出一次

指定导出路径:

# dubbo.properties dubbo.application.dump.directory=/tmp

 

 

序列化

dubbo支持多种序列化方式,支持使用高效的Java序列化(Kryo和FST)

性能:dubbo>hession2>json>java 其中dubbo序列化为阿里自研,不建议生产环境使用

 

3.3 dubbo配置属性的覆盖策略

dubbo的属性配置可以出现在狠多地方,关于这些配置的查找顺序符合以下规则:

  • 方法级优先,接口级次之,全局配置再次之。

  • 如果级别一样,则消费方优先,提供方次之。

dubbo学习笔记_第3张图片

四、Dubbo执行过程

4.1 服务注册时序图

 

 

 

4.2 服务发现时序图

4.3 服务调用

 

 

五、横向对比

5.1 各大互联网公司使用的RPC框架

公司

RPC框架

阿里巴巴

HSF、Dubbo

腾讯

Tars

百度

brpc

美团点评

mtthrift(基于thrift)、pigeon

微博

Motan

京东

JSF(基于Dubbo)

网易考拉

Dubbok(基于Dubbo)

当当

Dubbox(基于Dubbo)

Google

grpc

Facebook

thrift

Twitter

finagle

5.2 pigeon&dubbo对比

 

Dubbo

pigeon

备注

开发语言

Java

Java

 

分布式(服务治理)

dubbo monitor

pigeon

 

序列化方式

dubbo(基于hession2)、hession、json、jdk

fst、kryo

支持扩展

hessian、json、protobuf3、thrift、jdk

fst

支持扩展

 

注册中心

zookeeper、redis、multicast、simple

zookeeper->mns(基于zookeeper)

 

跨编程语言

不支持

不支持

 

配置方式

注解配置、schema配置、api配置

注解配置、schema配置、属性配置、api配置

 

服务通信协议

Dubbo 协议、 Rmi 协议、 Hessian 协议、 HTTP 协议、 WebService 协议、Dubbo Thrift 协议、Memcached 协议

HTTP协议,TCP协议

 

负载均衡

RandomLoadBalance (默认)、RoundRobinLoadBalance 、

ConsistentHash、LeastActive

WeightedAutoaware(默认,根据客户端到服务节点的在途请求数,结合有效权重,重新计算请求容量,挑选请求容量最小的服务节点进行随机负载)、Random、RoundRobin

 

服务容错

Failover(默认策略,重试次数2)

Failfast(只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录)

Failsafe(失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作)

Failback (失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作)

Forking(调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数)

Broadcast(广播调用所有提供者,逐个调用,任意一台报错则报错 。通常用于通知所有提供者更新缓存或日志等本地资源信息)

failfast(默认,失败之后直接返回)

failover(失败转移策略,当调用一个节点失败后,会调用另一个服务节点,重试次数默认为-1,不显示设置retry则不会重试)

failsafe(调用失败后,不抛异常,会返回默认值null)

forking(并行策略,并行同时调用多个服务节点,以最先返回的结果为最终结果返)

hedged(发起调用后,超过hedgedDelay时间后未返回结果,会再次向其他服务节点发送一个请求,以最先返回的结果为结果返回,主要用在解决服务调用长尾问题)

 

 

服务调用方式

同步(默认,通过配置asyn属性)

异步

oneway(通过方法里面配置return=“false”属性,同时可以使用sent="true"来等待消息发出,发送失败则抛异常)

callback

 

事件通知:Consumer 端在调用之前、调用之后或出现异常时,触发 oninvoke、onreturn、onthrow 三个事件。




    

 

sync 默认

oneway 提交请求,无需等待,不需要返回结果

future 请求提交给pigeon后立即返回,不等待返回结果,由pigeon负责等待返回结果,客户端可以自行决定何时何地来取返回结果

callback 回调方式,客户端将请求提交给pigeon后立即返回,也不等待返回结果,它与future方式的区别是,callback必须提供一个实现了pigeon提供的ServiceCallback接口的回调对象给pigeon,pigeon负责接收返回结果并传递回给这个回调对象

Pigeon 异步使用说明

其实不管是dubbo还是pigeon,同步调用的底层IO也是异步实现的。客户端发起同步调用之后,会得到一个future对象,只不过同步调用的线程会阻塞到timeout,如果超时没有还没有返回,则返回调用失败

 

调用方式判断:DubboInvoker

 

你可能感兴趣的:(java学习)