Chiriri's blog Chiriri's blog
首页
  • Java

    • JavaSE
    • JavaEE
    • 设计模式
  • Python

    • Python
    • Python模块
    • 机器学习
  • Golang

    • Golang
    • gRPC
  • 服务器

    • Linux
    • MySQL
    • NoSQL
    • Kubernetes
  • 项目

    • 传智健康
    • 畅购商城
  • Hadoop生态

    • Hadoop
    • Zookeeper
    • Hive
    • Flume
    • Kafka
    • Azkaban
    • Hbase
    • Scala
    • Spark
    • Flink
  • 大数据项目

    • 离线数仓
  • 青训营

    • 第四届青训营
  • HTML

    • HTML
    • JavaScript
  • Vue

    • Vue2
    • TypeScript
    • Vue3
    • Uni-APP
  • 数据结构与算法
  • C语言
  • 考研数据结构
  • 计算机组成原理
  • 计算机操作系统
  • Java基础

    • Java基础
    • Java集合
    • JUC
    • JVM
  • 框架

    • Spring
    • Dubbo
    • Spring Cloud
  • 数据库

    • MySQL
    • Redis
    • Elasticesearch
  • 消息队列

    • RabbitMQ
    • RocketMQ
  • 408

    • 计算机网络
    • 操作系统
    • 算法
  • 分类
  • 标签
  • 归档
  • 导航站
GitHub (opens new window)

Iekr

苦逼后端开发
首页
  • Java

    • JavaSE
    • JavaEE
    • 设计模式
  • Python

    • Python
    • Python模块
    • 机器学习
  • Golang

    • Golang
    • gRPC
  • 服务器

    • Linux
    • MySQL
    • NoSQL
    • Kubernetes
  • 项目

    • 传智健康
    • 畅购商城
  • Hadoop生态

    • Hadoop
    • Zookeeper
    • Hive
    • Flume
    • Kafka
    • Azkaban
    • Hbase
    • Scala
    • Spark
    • Flink
  • 大数据项目

    • 离线数仓
  • 青训营

    • 第四届青训营
  • HTML

    • HTML
    • JavaScript
  • Vue

    • Vue2
    • TypeScript
    • Vue3
    • Uni-APP
  • 数据结构与算法
  • C语言
  • 考研数据结构
  • 计算机组成原理
  • 计算机操作系统
  • Java基础

    • Java基础
    • Java集合
    • JUC
    • JVM
  • 框架

    • Spring
    • Dubbo
    • Spring Cloud
  • 数据库

    • MySQL
    • Redis
    • Elasticesearch
  • 消息队列

    • RabbitMQ
    • RocketMQ
  • 408

    • 计算机网络
    • 操作系统
    • 算法
  • 分类
  • 标签
  • 归档
  • 导航站
GitHub (opens new window)
  • Java基础

  • 框架

    • Spring
    • Dubbo
      • Dubbo的分层
      • Dubbo的工作原理
      • 为什么要通过代理对象通信?
      • 说说服务暴露的流程?
      • 说说服务引用的流程?
      • 有哪些负载均衡策略?
      • 集群容错方式有哪些?
      • 了解Dubbo SPI机制吗?
      • 如果让你实现一个RPC框架怎么设计?
    • Spring Cloud
    • Mybatis
  • 数据库

  • 消息队列

  • 408

  • 大数据

  • 面试
  • 框架
Iekr
2023-11-11
目录

Dubbo

# Dubbo

# Dubbo 的分层

从大的范围来说,dubbo 分为三层,business 业务逻辑层由我们自己来提供接口和实现还有一些配置信息,RPC 层就是真正的 RPC 调用的核心层,封装整个 RPC 的调用过程、负载均衡、集群容错、代理,remoting 则是对网络传输协议和数据转换的封装。

划分到更细的层面,就是图中的 10 层模式,整个分层依赖由上至下,除开 business 业务逻辑之外,其他的几层都是 SPI 机制。

img

# Dubbo 的工作原理

  1. 服务启动的时候,provider 和 consumer 根据配置信息,连接到注册中心 register,分别向注册中心注册和订阅服务
  2. register 根据服务订阅关系,返回 provider 信息到 consumer,同时 consumer 会把 provider 信息缓存到本地。如果信息有变更,consumer 会收到来自 register 的推送
  3. consumer 生成代理对象,同时根据负载均衡策略,选择一台 provider,同时定时向 monitor 记录接口的调用次数和时间信息
  4. 拿到代理对象之后,consumer 通过代理对象发起接口调用
  5. provider 收到请求后对数据进行反序列化,然后通过代理调用具体的接口实现

img

# 为什么要通过代理对象通信?

主要是为了实现接口的透明代理,封装调用细节,让用户可以像调用本地方法一样调用远程方法,同时还可以通过代理实现一些其他的策略,比如:

  1. 调用的负载均衡策略
  2. 调用失败、超时、降级和容错机制
  3. 做一些过滤操作,比如加入缓存、mock 数据
  4. 接口调用数据统计

# 说说服务暴露的流程?

  1. 在容器启动的时候,通过 ServiceConfig 解析标签,创建 dubbo 标签解析器来解析 dubbo 的标签,容器创建完成之后,触发 ContextRefreshEvent 事件回调开始暴露服务
  2. 通过 ProxyFactory 获取到 invoker,invoker 包含了需要执行的方法的对象信息和具体的 URL 地址
  3. 再通过 DubboProtocol 的实现把包装后的 invoker 转换成 exporter,然后启动服务器 server,监听端口
  4. 最后 RegistryProtocol 保存 URL 地址和 invoker 的映射关系,同时注册到服务中心

img

# 说说服务引用的流程?

服务暴露之后,客户端就要引用服务,然后才是调用的过程。

  1. 首先客户端根据配置文件信息从注册中心订阅服务

  2. 之后 DubboProtocol 根据订阅的得到 provider 地址和接口信息连接到服务端 server,开启客户端 client,然后创建 invoker

  3. invoker 创建完成之后,通过 invoker 为服务接口生成代理对象,这个代理对象用于远程调用 provider,服务的引用就完成了

    img

# 有哪些负载均衡策略?

  1. 加权随机:假设我们有一组服务器 servers = [A, B, C],他们对应的权重为 weights = [5, 3, 2],权重总和为 10。现在把这些权重值平铺在一维坐标值上,[0, 5) 区间属于服务器 A,[5, 8) 区间属于服务器 B,[8, 10) 区间属于服务器 C。接下来通过随机数生成器生成一个范围在 [0, 10) 之间的随机数,然后计算这个随机数会落到哪个区间上就可以了。
  2. 最小活跃数:每个服务提供者对应一个活跃数 active,初始情况下,所有服务提供者活跃数均为 0。每收到一个请求,活跃数加 1,完成请求后则将活跃数减 1。在服务运行一段时间后,性能好的服务提供者处理请求的速度更快,因此活跃数下降的也越快,此时这样的服务提供者能够优先获取到新的服务请求。
  3. 一致性 hash:通过 hash 算法,把 provider 的 invoke 和随机节点生成 hash,并将这个 hash 投射到 [0, 232−1] 的圆环上,查询的时候根据 key 进行 md5 然后进行 hash,得到第一个节点的值大于等于当前 hash 的 invoker。

  1. 加权轮询:比如服务器 A、B、C 权重比为 5:2:1,那么在 8 次请求中,服务器 A 将收到其中的 5 次请求,服务器 B 会收到其中的 2 次请求,服务器 C 则收到其中的 1 次请求。

# 集群容错方式有哪些?

  1. Failover Cluster 失败自动切换:dubbo 的默认容错方案,当调用失败时自动切换到其他可用的节点,具体的重试次数和间隔时间可用通过引用服务的时候配置,默认重试次数为 1 也就是只调用一次。
  2. Failback Cluster 快速失败:在调用失败,记录日志和调用信息,然后返回空结果给 consumer,并且通过定时任务每隔 5 秒对失败的调用进行重试
  3. Failfast Cluster 失败自动恢复:只会调用一次,失败后立刻抛出异常
  4. Failsafe Cluster 失败安全:调用出现异常,记录日志不抛出,返回空结果
  5. Forking Cluster 并行调用多个服务提供者:通过线程池创建多个线程,并发调用多个 provider,结果保存到阻塞队列,只要有一个 provider 成功返回了结果,就会立刻返回结果
  6. Broadcast Cluster 广播模式:逐个调用每个 provider,如果其中一台报错,在循环调用结束后,抛出异常。

# 了解 Dubbo SPI 机制吗?

SPI 全称为 Service Provider Interface,是一种服务发现机制,本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类,这样可以在运行时,动态为接口替换实现类。

Dubbo 也正是通过 SPI 机制实现了众多的扩展功能,而且 dubbo 没有使用 java 原生的 SPI 机制,而是对齐进行了增强和改进。

SPI 在 dubbo 应用很多,包括协议扩展、集群扩展、路由扩展、序列化扩展等等。

使用方式可以在 META-INF/dubbo 目录下配置:

key=com.xxx.value
1

然后通过 dubbo 的 ExtensionLoader 按照指定的 key 加载对应的实现类,这样做的好处就是可以按需加载,性能上得到优化。

# 如果让你实现一个 RPC 框架怎么设计?

  1. 首先需要一个服务注册中心,这样 consumer 和 provider 才能去注册和订阅服务
  2. 需要负载均衡的机制来决定 consumer 如何调用客户端,这其中还当然要包含容错和重试的机制
  3. 需要通信协议和工具框架,比如通过 http 或者 rmi 的协议通信,然后再根据协议选择使用什么框架和工具来进行通信,当然,数据的传输序列化要考虑
  4. 除了基本的要素之外,像一些监控、配置管理页面、日志是额外的优化考虑因素。

那么,本质上,只要熟悉一两个 RPC 框架,就很容易想明白我们自己要怎么实现一个 RPC 框架。

编辑 (opens new window)
上次更新: 2023/12/06, 01:31:48
Spring
Spring Cloud

← Spring Spring Cloud→

最近更新
01
k8s
06-06
02
进程与线程
03-04
03
计算机操作系统概述
02-26
更多文章>
Theme by Vdoing | Copyright © 2022-2025 Iekr | Blog
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式