文章目录
Dubbo
说到底,dubbo 的本质就是一个==分布式== rpc(远程服务调用) 框架,在需要用到分布式且需要远程调用的时候,我们就会选择 dubbo。
1. 互联网商的应用架构发展
1.1. 单一应用架构
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。
1.2. 垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。
1.3. 分布式服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。
1.4. 流动计算架构
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。
聊完了应用架构的发展,也是时候回归主题了,我们为什么要用 dubbo 呢?
2. Dubbo 的核心功能
- Remoting: 远程通讯,提供对多种 NIO 框架抽象封装,包括“同步转异步”和“请求-相应”模式的信息交换方式;
- Cluster: 服务框架,提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持;
- Registry: 服务注册中心,基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。
那么为了以上功能,Dubbo 又有怎样的组件角色来协作完成分布式管理呢?
3. Dubbo 的组件角色
3.1. 角色之间的关系
节点 | 角色说明 |
---|---|
Provider | 暴露服务的服务提供方 |
Consumer | 调用远程服务的服务消费方 |
Registry | 服务注册与发现的注册中心 |
Monitor | 统计服务的调用次数和调用时间的监控中心 |
Container | 服务运行容器 |
3.3. 调用关系说明:
- 服务容器负责启动,加载,运行服务提供者。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
4. 配置
4.1. 本地服务 Spring 配置
local.xml:
<bean id=“xxxService” class=“com.xxx.XxxServiceImpl” />
<bean id=“xxxAction” class=“com.xxx.XxxAction”>
<property name=“xxxService” ref=“xxxService” />
</bean>
4.2. 远程服务 Spring 配置
在本地服务的基础上,只需做简单配置,即可完成远程化:
- 将上面的
local.xml
配置拆分成两份,将服务定义部分放在服务提供方remote-provider.xml
,将服务引用部分放在服务消费方remote-consumer.xml
。 - 并在提供方增加暴露服务配置
<dubbo:service>
,在消费方增加引用服务配置<dubbo:reference>
。
remote-provider.xml:
<!-- 和本地服务一样实现远程服务 -->
<bean id=“xxxService” class=“com.xxx.XxxServiceImpl” />
<!-- 增加暴露远程服务配置 -->
<dubbo:service interface=“com.xxx.XxxService” ref=“xxxService” />
remote-consumer.xml:
<!-- 增加引用远程服务配置 -->
<dubbo:reference id=“xxxService” interface=“com.xxx.XxxService” />
<!-- 和本地服务一样使用远程服务 -->
<bean id=“xxxAction” class=“com.xxx.XxxAction”>
<property name=“xxxService” ref=“xxxService” />
</bean>
5. 快速搭建一个基于SpringBoot 的Dubbo 服务
基础框架的搭建:
-
Springboot-dubbo-demo 是一个父项目
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.imooc</groupId> <artifactId>dubbo-demo</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <modules> <module>api</module> <module>consumer</module> <module>provider</module> </modules> </project>
-
api 是对外提供接口的模块:
<dependency> <groupId>com.imooc</groupId> <artifactId>dubbo-demo-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
其pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.imooc</groupId> <artifactId>dubbo-demo-api</artifactId> <version>1.0-SNAPSHOT</version> </project>
内部对外提供一个接口
sayHello:
package com.imooc.springboot.dubbo.demo; public interface DemoService { String sayHello(String name); }
-
provider 服务提供方
这个模块需要做的事就是:
- 加入接口的相关依赖 jar 包
- 在
application.properties
配置文件中配置dubbo
相关信息 - 实现接口类
- 启动类编写
pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.imooc</groupId> <artifactId>dubbo-demo-provider</artifactId> <dependencies> <dependency> <groupId>io.dubbo.springboot</groupId> <artifactId>spring-boot-starter-dubbo</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>com.imooc</groupId> <artifactId>dubbo-demo-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
application.properties:
# dubbo 提供者的别名,只是个标识 spring.dubbo.application.name=demo-provider # zk地址 spring.dubbo.registry.address=zookeeper://127.0.0.1:2181 # dubbo 协议 spring.dubbo.protocol.name=dubbo # dubbo 端口号 spring.dubbo.protocol.port=20880 # 这里是我们要发布到 dubbo 接口的所在包位置 spring.dubbo.scan=com.imooc.springboot.dubbo.demo.provider
启动类:
package com.imooc.springboot.dubbo.demo.provider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MainProvider { public static void main(String[] args) { SpringApplication.run(MainProvider.class,args); } }
实现类:
package com.imooc.springboot.dubbo.demo.provider; import com.alibaba.dubbo.config.annotation.Service; import com.imooc.springboot.dubbo.demo.DemoService; @Service public class DemoServiceImpl implements DemoService { @Override public String sayHello(String name) { return "Hello, " + name + " (from Spring Boot)"; } }
-
consumer
服务消费者
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.imooc</groupId> <artifactId>dubbo-demo-consumer</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>io.dubbo.springboot</groupId> <artifactId>spring-boot-starter-dubbo</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>com.imooc</groupId> <artifactId>dubbo-demo-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
application.properties:
server.port=8080 #dubbo config spring.dubbo.application.name=demo-consumer spring.dubbo.registry.address=zookeeper://127.0.0.1:2181 spring.dubbo.scan=com.imooc.springboot.dubbo.demo.consumer
启动类:
package com.imooc.springboot.dubbo.demo.consumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MainConsumer { public static void main(String[] args) { SpringApplication.run(MainConsumer.class,args); } }
controller:
package com.imooc.springboot.dubbo.demo.consumer; import com.alibaba.dubbo.config.annotation.Reference; import com.imooc.springboot.dubbo.demo.DemoService; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class DemoConsumerController { @Reference private DemoService demoService; @RequestMapping("/sayHello") public String sayHello(@RequestParam String name) { return demoService.sayHello(name); } }
5.1. debug 查看过程
先启动 provider,再启动consumer(port:8080)
-
发送 http 请求
-
首先进入是是controller层
注意:demoService 如果为null 则代表我们的dubbo服务搭建失败;
这里注入采用的是 dubbo 的注解
@Reference
-
接下来通过dubbo 找到 服务提供者
-
最后 通过 dubbo 进行返回
最后附加一个,搭建项目的博客介绍(按照介绍来其实也可以很好的spring boot 整合 dubbo):
The link@[toc]
Dubbo
说到底,dubbo 的本质就是一个==分布式== rpc(远程服务调用) 框架,在需要用到分布式且需要远程调用的时候,我们就会选择 dubbo。
1. 互联网商的应用架构发展
1.1. 单一应用架构
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。
1.2. 垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。
1.3. 分布式服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。
1.4. 流动计算架构
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。
聊完了应用架构的发展,也是时候回归主题了,我们为什么要用 dubbo 呢?
2. Dubbo 的核心功能
- Remoting: 远程通讯,提供对多种 NIO 框架抽象封装,包括“同步转异步”和“请求-相应”模式的信息交换方式;
- Cluster: 服务框架,提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持;
- Registry: 服务注册中心,基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。
那么为了以上功能,Dubbo 又有怎样的组件角色来协作完成分布式管理呢?
3. Dubbo 的组件角色
3.1. 角色之间的关系
[外链图片转存失败(img-4WEBmGIL-1563496913227)(dubbo.assets/dubbo.jpg)]
节点 | 角色说明 |
---|---|
Provider | 暴露服务的服务提供方 |
Consumer | 调用远程服务的服务消费方 |
Registry | 服务注册与发现的注册中心 |
Monitor | 统计服务的调用次数和调用时间的监控中心 |
Container | 服务运行容器 |
3.3. 调用关系说明:
- 服务容器负责启动,加载,运行服务提供者。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
[外链图片转存失败(img-axCb3NG7-1563496913228)(dubbo.assets/16241d6d49d9ccf0.png)]
4. 配置
4.1. 本地服务 Spring 配置
local.xml:
<bean id=“xxxService” class=“com.xxx.XxxServiceImpl” />
<bean id=“xxxAction” class=“com.xxx.XxxAction”>
<property name=“xxxService” ref=“xxxService” />
</bean>
4.2. 远程服务 Spring 配置
在本地服务的基础上,只需做简单配置,即可完成远程化:
- 将上面的
local.xml
配置拆分成两份,将服务定义部分放在服务提供方remote-provider.xml
,将服务引用部分放在服务消费方remote-consumer.xml
。 - 并在提供方增加暴露服务配置
<dubbo:service>
,在消费方增加引用服务配置<dubbo:reference>
。
remote-provider.xml:
<!-- 和本地服务一样实现远程服务 -->
<bean id=“xxxService” class=“com.xxx.XxxServiceImpl” />
<!-- 增加暴露远程服务配置 -->
<dubbo:service interface=“com.xxx.XxxService” ref=“xxxService” />
remote-consumer.xml:
<!-- 增加引用远程服务配置 -->
<dubbo:reference id=“xxxService” interface=“com.xxx.XxxService” />
<!-- 和本地服务一样使用远程服务 -->
<bean id=“xxxAction” class=“com.xxx.XxxAction”>
<property name=“xxxService” ref=“xxxService” />
</bean>
5. 快速搭建一个基于SpringBoot 的Dubbo 服务
基础框架的搭建:
[外链图片转存失败(img-AzY8zQ2b-1563496913228)(dubbo.assets/1563418301857.png)]
-
Springboot-dubbo-demo 是一个父项目
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.imooc</groupId> <artifactId>dubbo-demo</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <modules> <module>api</module> <module>consumer</module> <module>provider</module> </modules> </project>
-
api 是对外提供接口的模块:
<dependency> <groupId>com.imooc</groupId> <artifactId>dubbo-demo-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
其pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.imooc</groupId> <artifactId>dubbo-demo-api</artifactId> <version>1.0-SNAPSHOT</version> </project>
内部对外提供一个接口
sayHello:
package com.imooc.springboot.dubbo.demo; public interface DemoService { String sayHello(String name); }
[外链图片转存失败(img-cWwF0vV9-1563496913229)(dubbo.assets/1563418630737.png)]
-
provider 服务提供方
这个模块需要做的事就是:
- 加入接口的相关依赖 jar 包
- 在
application.properties
配置文件中配置dubbo
相关信息 - 实现接口类
- 启动类编写
[外链图片转存失败(img-GB5Sz5Sw-1563496913229)(dubbo.assets/1563418812657.png)]
pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.imooc</groupId> <artifactId>dubbo-demo-provider</artifactId> <dependencies> <dependency> <groupId>io.dubbo.springboot</groupId> <artifactId>spring-boot-starter-dubbo</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>com.imooc</groupId> <artifactId>dubbo-demo-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
application.properties:
# dubbo 提供者的别名,只是个标识 spring.dubbo.application.name=demo-provider # zk地址 spring.dubbo.registry.address=zookeeper://127.0.0.1:2181 # dubbo 协议 spring.dubbo.protocol.name=dubbo # dubbo 端口号 spring.dubbo.protocol.port=20880 # 这里是我们要发布到 dubbo 接口的所在包位置 spring.dubbo.scan=com.imooc.springboot.dubbo.demo.provider
启动类:
package com.imooc.springboot.dubbo.demo.provider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MainProvider { public static void main(String[] args) { SpringApplication.run(MainProvider.class,args); } }
实现类:
package com.imooc.springboot.dubbo.demo.provider; import com.alibaba.dubbo.config.annotation.Service; import com.imooc.springboot.dubbo.demo.DemoService; @Service public class DemoServiceImpl implements DemoService { @Override public String sayHello(String name) { return "Hello, " + name + " (from Spring Boot)"; } }
-
consumer
服务消费者
[外链图片转存失败(img-k2E1j7w3-1563496913230)(dubbo.assets/1563419107755.png)]
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.3.RELEASE</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.imooc</groupId> <artifactId>dubbo-demo-consumer</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>io.dubbo.springboot</groupId> <artifactId>spring-boot-starter-dubbo</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>com.imooc</groupId> <artifactId>dubbo-demo-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
application.properties:
server.port=8080 #dubbo config spring.dubbo.application.name=demo-consumer spring.dubbo.registry.address=zookeeper://127.0.0.1:2181 spring.dubbo.scan=com.imooc.springboot.dubbo.demo.consumer
启动类:
package com.imooc.springboot.dubbo.demo.consumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MainConsumer { public static void main(String[] args) { SpringApplication.run(MainConsumer.class,args); } }
controller:
package com.imooc.springboot.dubbo.demo.consumer; import com.alibaba.dubbo.config.annotation.Reference; import com.imooc.springboot.dubbo.demo.DemoService; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class DemoConsumerController { @Reference private DemoService demoService; @RequestMapping("/sayHello") public String sayHello(@RequestParam String name) { return demoService.sayHello(name); } }
5.1. debug 查看过程
先启动 provider,再启动consumer(port:8080)
-
发送 http 请求
[外链图片转存失败(img-W8AziZns-1563496913231)(dubbo.assets/1563419391799.png)]
-
首先进入是是controller层
[外链图片转存失败(img-L2pYx5gN-1563496913231)(dubbo.assets/1563419482486.png)]
注意:demoService 如果为null 则代表我们的dubbo服务搭建失败;
这里注入采用的是 dubbo 的注解
@Reference
-
接下来通过dubbo 找到 服务提供者
[外链图片转存失败(img-Hi9U5Oov-1563496913232)(dubbo.assets/1563419769364.png)]
-
最后 通过 dubbo 进行返回
最后附加一个,搭建项目的博客介绍(按照介绍来其实也可以很好的spring boot 整合 dubbo):
6. dubbo 集群容错
集群调用失败的时候,Dubbo 提供多种容错方法,缺省为 failover
重试。
[外链图片转存失败(img-5L3MBsFD-1563496913233)(dubbo.assets/cluster.jpg)]
- 这里的
Invoker
是Provider
的一个可调用Service
的抽象,Invoker
封装了Provider
地址及Service
接口信息 Directory
代表多个Invoker
,可以把它看成List<Invoker>
,但与List
不同的是,它的值可能是动态变化的,比如注册中心推送变更Cluster
将Directory
中的多个Invoker
伪装成一个Invoker
,对上层透明,伪装过程包含了容错逻辑,调用失败后,重试另一个Router
负责从多个Invoker
中按路由规则选出子集,比如读写分离,应用隔离等LoadBalance
负责从多个Invoker
中选出具体的一个用于本次调用,选的过程包含了负载均衡算法,调用失败后,需要重选
6.1.FailOver Cluster 失败自动切换
当失败是,重试其它服务器。通常用于读操作,但是重试延迟高,我们可以通过 retries="2"
来设置重试次数,不含第一次。
6.2. Failfast Cluster 快速失败
只发起一次调用,失败就报错。通常用于非幂等性的写操作,比如新增操作。
6.3. Failsafe Cluster 失败安全
出现异常直接忽略。通常用于写入审计日志等操作。
6.4. Failback Cluster 失败自动恢复
后台记录失败请求,定时重发。通常用于消息通知操作
6.5. Forking Cluster 并行调用多个服务器
调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。可以通过 forks="2"
来设置最大并行数。
6.6. Broadcast Cluster 广播调用所有提供者
逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息.
7. 负载均衡
- 随机,按权重设置随机概率。在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
- 轮询,按公约后的权重设置轮询比率。存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
- 最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
- 一致性 Hash,相同参数的请求总是发到同一提供者。当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。