Loading...

📋 Dubbo 知识整理

在微服务知识整理的过程中,断断续续看了好些文档和视频教程,写下的笔记也很杂乱,现决定稍微专注一点,一鼓作气将这块知识整理完整。

基础知识

RPC(Remote Procedure Call)意为[远程过程调用]{.blue}。

RPC 是用来干什么的?

在微服务架构中,一个完整的项目,通常会被拆分成多个微型服务,但在业务过程中,这些服务彼此之间是存在调用关系的,对于这种跨服务之间的调用,通常就需要通过 RPC 来完成。简单来说,RPC 的目的,就是为了让程序能够像调用本地方法一样调用远程方法

既然有 HTTP 请求,为什么还要用 RPC 调用?

  1. RPC 的出现是早于 HTTP 的,RPC 主要是基于 TCP/IP 协议,而 HTTP 是基于 HTTP 协议的。
  2. HTTP 和 RPC 不是两个可以对等的比较概念。因为 HTTP 是一个通信协议,而 RPC 是一个完整的远程调用方案。
  3. 可以更简单地理解,HTTP 其实就是一种 RPC 的一种,它拥有更加具体的实现,但对于微服务之间的远程调用,则不太适用。
  4. 知乎问答上有更加详细的讨论,可点击此处前往查看。

RPC 的原理是什么?

要明白 RPC 的原理,首先应当了解如下几个概念:

  • 客户端:远程方法的调用者。
  • 客户端 Stub:它主要负责将调用的方法、类、方法参数等信息传递到服务端。
  • 网络传输:网络传输就是客户端将要调用的信息输到服务端,然后服务端执行完之后再把返回结果通过网络传输给你传输回来。网络传输即是指这种双向的数据传输过程。
  • 服务端 Stub:它的主要作用是接收客户端的请求,并指定对应的方法进行处理,最终将处理结果返回给客户端。
  • 服务端:远程方法的提供者。

RPC 原理示意图:

dubbo

  1. 客户端以本地调用方式调用远程服务。
  2. 客户端 stub 接收到调用后,将方法、参数等组装成能够进行网络传输的消息体(序列号):RpcRequest
  3. 客户端 stub 找到远程服务地址,并将消息发送到服务端。
  4. 服务端 stub 接收到消息并反序列化为 Java 对象:RpcRequest。
  5. 服务端 stub 根据 RpcRequest 中的类、方法、方法参数等信息调用本地方法。
  6. 服务端 stub 得到方法执行结果,并将其序列号为 RpcResponse 对象,并通过网络传输发送到客户端。
  7. 客户端 stub 接收到服务端的响应数据,并反序列化为 RpcResponse 对象。

Dubbo 概述

Dubbo 是什么?

Dubbo 是阿里巴巴开源的一款高性能、轻量级的 RPC 框架,它提供服务自动注册、自动发现等高效服务治理方案,可以和 Spring 框架无缝集成。

Dubbo 提供了六大核心能力:

image-20220301153753633

为什么要用 Dubbo?

随着服务化的进一步发展,服务越来越多,服务之间的调用和依赖关系也越来越复杂,诞生了面向服务的架构体系(SOA)。同时,也由此衍生出了一系列相应的技术,如对服务提供、服务调用、连接处理、通信协议、序列化方式、服务发现、服务路由、日志输出等行为进行封装的服务框架。就这样为分布式系统的服务治理框架就出现了,这也是 Dubbo 最初的产生。

Dubbo 的核心架构

下图是 Dubbo 官网描述的基本原理图:

Dubbo Architecture

其中,Dubbo 默认使用 zookeeper 作为其注册中心,监控中心在 Dubbo 的架构中并非必须。

快速入门

如前文所述,Dubbo 默认使用 zookeeper 作为其注册中心,因此,在正式入门前,需要了解如何安装 zookeeper,zookeeper 安装及相关基础知识,可参考文章《Zookeeper 基础教程》。

集成实例代码已上传到 Github 仓库,可自行查看,自出不进行详述:

高级特性

Dubbo Admin

  1. 介绍

    Dubbo Admin 是一个通过 vue + springboot 实现的 Dubbo 可视化管理界面。

  2. 下载

    https://github.com/apache/dubbo-admin

  3. 后端部署

    git clone https://github.com/apache/dubbo-admin.git
    cd dubbo-admin-server
    mvn clean package
    cd target
    java -jar dubbo-admin-server-0.1.jar
  4. 前端部署

    cd dubbo-admin-ui
    npm install
    npm run dev
  5. 注意事项

    • Dubbo Admin 前端依赖于 node.js 环境。
    • Dubbo Admin 默认账号密码均为 root。
    • Dubbo 默认使用 20880 端口连接注册中心,同一主机多个 Dubbo 客户端时应注意避免端口冲突。
    • 此部分尽量简化,如有疑问,可参考 Dubbo 官方提供的 Dubbo Admin 运维指南

协议与序列化

我们把对象转换为字节序列的过程称为对象的序列化,把字节序列恢复为对象的过程称为对象的反序列化。而 Dubbo 需要进行网络通信,就必然需要实现序列化和反序列化的过程。其实现序列化的方式也很简单,只需要使传输的对象类实现 Serializable 接口即可。

public class User implements Serializable {
    private Integer id;
}

🎈 Dubbo 支持的协议

Dobbo 支持的协议包括:dubbo、rmi、hessian、http、webservice、thrift、memcached、redis、rest。其中,dubbo:// 是 Dobbo 默认支持的协议。

Dubbo RMI Hessian Http WebService
连接数 单个 多个 多个 多个 多个
连接类型 长连接 短连接 短连接 短连接 短连接
通信协议 TCP TCP HTTP HTTP HTTP
传输方式 NIO 同步 同步 同步 同步
序列化 Hessian Java 标准二进制 Hessian 表单序列化 SOAP 文本序列化
使用场景 大并发,小数据 常规 文件、页面 支持客户端或js调用 系统集成,跨语言

Dubbo 针对不同服务,可以选择使用不同的协议:

<?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://dubbo.apache.org/schema/dubbo"
    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="world"  />
    <dubbo:registry id="registry" address="10.20.141.150:9090" username="admin" password="hello1234" />
    <!-- 多协议配置 -->
    <dubbo:protocol name="dubbo" port="20880" />
    <dubbo:protocol name="rmi" port="1099" />
    <!-- 使用dubbo协议暴露服务 -->
    <dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" protocol="dubbo" />
    <!-- 使用rmi协议暴露服务 -->
    <dubbo:service interface="com.alibaba.hello.api.DemoService" version="1.0.0" ref="demoService" protocol="rmi" /> 
</beans>

此外,Dubbo 也可以同时使用多个协议暴露服务:

<?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://dubbo.apache.org/schema/dubbo"
    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="world"  />
    <dubbo:registry id="registry" address="10.20.141.150:9090" username="admin" password="hello1234" />
    <!-- 多协议配置 -->
    <dubbo:protocol name="dubbo" port="20880" />
    <dubbo:protocol name="hessian" port="8080" />
    <!-- 使用多个协议暴露服务 -->
    <dubbo:service id="helloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" protocol="dubbo,hessian" />
</beans>

超时与重试机制

通过进行如下配置,即可实现 Dubbo 服务调用的超时与重试:

<!-- 服务调用超时设置为5秒,重试3次-->
<dubbo:service interface="com.provider.service.DemoService" ref="demoService" retries="3" timeout="5000"/>
<!-- <dubbo:consumer timeout="1000"></dubbo:consumer>-->

Dubbo 超时设置可以有两种方式:

  1. 服务提供者端设置超时(推荐)。
  2. 服务消费者端设置超时,其优先级更高。

服务调用超时,Dubbo 会自动进行重试,当未指定重试次数时,默认为重试两次。

除了通过 xml 的方式指定 Dubbo 超时重试等相关参数外,也可以通过指定注解参数的方式实现:

import org.apache.dubbo.config.annotation.Service;

@Service(timeout = 3000, retries = 3)

注:Dubbo 新版本中 @Service@Reference 已被标记为过时,并使用 DubboServiceDubboReference 进行替代。

多版本

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

<!-- 服务提供者端 -->
<dubbo:service interface="com.foo.BarService" version="1.0.0" />
<!-- 服务消费者端 -->
<dubbo:reference id="barService" interface="com.foo.BarService" version="*" />

同样,除了使用 xml 进行配置外,多版本参数也可以通过注解的方式进行指定:

// 服务提供者端
@Service(version = "1.0.0")
// 服务消费者端
@Reference(version = "1.0.0")

负载均衡

在集群负载均衡时,Dubbo 提供了多种均衡策略,缺省为 random 随机调用。具体实现上,Dubbo 提供的是客户端负载均衡,即由 Consumer 通过负载均衡算法得出需要将请求提交到哪个 Provider 实例。

目前 Dubbo 内置了如下负载均衡算法,用户可直接配置使用:

算法 特性 备注
RandomLoadBalance 加权随机 默认算法,默认权重相同
RoundRobinLoadBalance 加权轮询 借鉴于 Nginx 的平滑加权轮询算法,默认权重相同,
LeastActiveLoadBalance 最少活跃优先 + 加权随机 背后是能者多劳的思想
ShortestResponseLoadBalance 最短响应优先 + 加权随机 更加关注响应速度
ConsistentHashLoadBalance 一致性 Hash 确定的入参,确定的提供者,适用于有状态请求

xml 配置方式:

<!-- 服务端级别 -->
<dubbo:service interface="..." loadbalance="roundrobin" />
<!-- 服务端方法级别 -->
<dubbo:service interface="...">
    <dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:service>
<!-- 消费端级别 -->
<dubbo:reference interface="..." loadbalance="roundrobin" />
<!-- 消费端方法级别 -->
<dubbo:reference interface="...">
    <dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:reference>

注解配置方式:

@Reference(loadbalance = "random")
@Service(loadbalance = "random")

集群容错

在集群调用失败时,Dubbo 提供了多种容错方案,缺省为 failover 重试。Dubbo 主要有如下几种集群容错模式:

  1. Failover:失败自动切换,当出现失败,重试其它服务器。通常用于读操作,但重试会带来更长延迟。可通过 retries="2" 来设置重试次数(不含第一次)。
  2. Failfast:快速失败,只发起一次调用,失败立即报错。通常用于非幂等性的写操作,比如新增记录。
  3. Failsafe:失败安全,出现异常时,直接忽略。通常用于写入审计日志等操作。
  4. Failback:失败自动恢复,后台记录失败请求,定时重发。通常用于消息通知操作。
  5. Forking:并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可通过 forks="2" 来设置最大并行数。
  6. Broadcast:广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。
  7. Available:调用目前可用的实例(只调用一个),如果当前没有可用的实例,则抛出异常。通常用于不需要负载均衡的场景。
  8. Mergeable:将集群中的调用结果聚合起来返回结果,通常和group一起配合使用。通过分组对结果进行聚合并返回聚合后的结果,比如菜单服务,用group区分同一接口的多种实现,现在消费方需从每种group中调用一次并返回结果,对结果进行合并之后返回,这样就可以实现聚合菜单项。
  9. ZoneAware:多注册中心订阅的场景,注册中心集群间的负载均衡。

可以通过如下方式指定集群容错模式:

<!-- 在服务端设置 -->
<dubbo:service cluster="failsafe" />
<!-- 或在消费端设置 -->
<dubbo:reference cluster="failsafe" />

服务降级

Dubbo 可以通过服务降级功能临时屏蔽某个出错的非关键服务,并定义降级后的返回策略。

@Reference(mock = "forse:return null")
  • mock=force:return null 表示消费方对该服务的方法调用都直接返回 null 值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。
  • 还可以改为 mock=fail:return+null 表示消费方对该服务的方法调用在失败后,再返回 null 值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。

面试题

碍于精力,这一部分的内容并暂时做的比较简单,部分问题也暂未给出参考答案和相关提示。作答者可根据前文中的知识内容自行总结。

后续看情况会进行更新。

  1. Dubbo 是什么?{.quiz .fill}

    参考 Dubbo 概述部分作答即可。

    [这道题往往是作为 Dubbo 面试的预热题目,简单回答即可,等待面试官的追问。但其本质需要明确,Dubbo 本质上就是一款 RPC 框架。]{.mistake}

  2. 试举几个 Dubbo 支持的协议。{.quiz .fill}

    Dobbo 支持的协议包括:dubbo、rmi、hessian、http、webservice、thrift、memcached、redis、rest。其中,dubbo:// 是 Dobbo 默认支持的协议。

    [选择几个熟知的协议作答即可。]{.mistake}

  3. Dubbo 内置了哪几种服务容器?{.quiz .fill}

  4. Dubbo 中有哪几种主要角色?{.quiz .fill}

  5. Dubbo 服务注册与发现流程。{.quiz .fill}

  6. Dubbo 的注册中心如何实现,实现方案和推荐方案。{.quiz .fill}

  7. Dubbo 默认采用的通信框架是[]{.gap}。{.quiz}

    • Mina
    • Netty{.correct}
    • Grizzly
    • xSocket
      {.options}

    [除 xSocket 外,其他三个选项均是 Dubbo 支持的通信框架。]{.mistake}

  8. Dubbo 是如何进行序列号与反序列化的?{.quiz .fill}

参考

版权声明

本文链接:https://www.chinmoku.cc/java/advanced/dubbo-tutorial/

本博客中的所有内容,包括但不限于文字、图片、音频、视频、图表和其他可视化材料,均受版权法保护。未经本博客所有者书面授权许可,禁止在任何媒体、网站、社交平台或其他渠道上复制、传播、修改、发布、展示或以任何其他方式使用此博客中的任何内容。

Press ESC to close