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

# 基础知识

RPC(Remote Procedure Call)意为远程过程调用

🎈 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 仓库,可自行查看,自出不进行详述:

  • Spring 集成 Dubbo,请点击此处
  • SpringBoot 集成 Dubbo,请点击此处

# 高级特性

# 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 默认支持的协议。

DubboRMIHessianHttpWebService
连接数单个多个多个多个多个
连接类型长连接短连接短连接短连接短连接
通信协议TCPTCPHTTPHTTPHTTP
传输方式NIO同步同步同步同步
序列化HessianJava 标准二进制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 是什么?

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

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

  2. 试举几个 Dubbo 支持的协议。

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

    选择几个熟知的协议作答即可。

  3. Dubbo 内置了哪几种服务容器?

  4. Dubbo 中有哪几种主要角色?

  5. Dubbo 服务注册与发现流程。

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

  7. Dubbo 默认采用的通信框架是

    • Mina
    • Netty
    • Grizzly
    • xSocket

    除 xSocket 外,其他三个选项均是 Dubbo 支持的通信框架。

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

# 参考

  • https://www.bilibili.com/video/BV1VE411q7dX
  • https://dubbo.apache.org/zh/docs/
  • https://zhangc233.github.io/2021/08/18/Dubbo/
  • https://www.cnblogs.com/jameszheng/p/10271341.html