-
Notifications
You must be signed in to change notification settings - Fork 512
服务路由之就近路由
生产环境服务为了高可用、容灾等能力往往需要多机房、多城市、多地域部署。
如上图所示,范围从小到大依次为: Campus < Zone < Region < All
其中 Campus、Zone、Region 在服务注册发现领域模型里统一定义为元数据,是一种特殊的位置元数据(Location Metadata)。
以一个实际的部署模型为例:上海机房一、上海机房二、杭州机房一、杭州机房二、北京机房。
- 三层模型
-
Campus(上海机房一) <Zone(上海) <Region(华东)
- 三层模型有时太过于复杂,也可简化成两层模型
-
Zone(上海机房一) <Region(上海)
就近路由顾名思义,服务调用时按照 同 Campus、同 Zone、同 Region 的优先级从高到低依次选取目标服务实例。核心是减少服务调用因物理距离增加的网络耗时。
本质上,就近路由是一种基于特定一组位置元数据的元数据路由。
Important
Campus、Zone、Region 的名称必须全局唯一,不允许重复。
- ❌ 错误示例:
huadongRegion 下有zone-a,huabeiRegion 下也有zone-a - ✅ 正确示例:
huadongRegion 下为zone-sh-a,huabeiRegion 下为zone-bj-a
注意:
1.5.0版本后才支持元数据路由
请参考 服务路由基础操作 文档,引入依赖以及增加配置。
就近路由为默认开启的功能,如果需要关闭,则添加如下配置:
spring.cloud.polaris.router.nearby-router=false可以通过以下方式设置服务实例的位置元数据,优先级为 动态SPI > 环境变量 > 应用配置。
通过环境变量打标是一种最简单的方式,但是公司内部可能有其它的方式打标,例如:
- 在机器上的某一个配置文件,例如:
/etc/metadata - 通过调用 CMDB 系统获取位置信息
所以 SCT 定义了一个 InstanceMetadataProvider 的SPI,用于用户自定义实现获取位置信息,实现如下方法,即可配置相应的位置信息:
/**
* The region of current instance.
*
* @return the region info.
*/
default String getRegion() {
return "";
}
/**
* The zone of current instance.
*
* @return the zone info.
*/
default String getZone() {
return "";
}
/**
* The campus/datacenter of current instance.
*
* @return the campus or datacenter info.
*/
default String getCampus() {
return "";
}SCT(Spring Cloud Tencent 的缩写) 内置了一组位置元数据环境变量标签:
SCT_METADATA_CAMPUSSCT_METADATA_ZONESCT_METADATA_REGION
服务在启动时,SCT 会读取这一组环境变量作为元数据上报到注册中心,从而传递到主调端。
可以通过查看启动日志确认是否正确打标:
grep "Loaded static metadata info" xx.log
SCT 也支持在业务应用的配置文件中设置位置元数据,设置方式为在 application.yml 等配置文件中添加如下所示:
spring:
cloud:
tencent:
metadata:
content:
region: huanan
zone: shenzhen
campus: shenzhen-zone-1就近路由插件默认匹配区间为 [Zone, All],也就是优先匹配 Zone,如果未匹配到,则继续匹配 Region,适用于简单的两层模型。
如果您的部署模型为三层模型(Campus、Zone、Region),则需要增加配置项从 Campus 开始匹配。
- 2.0.0.0 及以上版本的调整方式:
设置方式为在 application.yml 等配置文件中添加如下所示:
spring:
cloud:
polaris:
router:
nearby-router:
matchLevel: campus- 1.14.0 以下版本的调整方式:
该配置需要放在 main/resources/polaris.yml 中:
consumer:
serviceRouter:
plugin:
nearbyBasedRouter:
#描述: 就近路由的最小匹配级别。region(大区)、zone(区域)、campus(园区)
matchLevel: campus
#描述: 最大匹配级别
maxMatchLevel: all我们提供的示例代码quickstart-example可以体验到SCT就近路由的能力。
在示例代码中,quickstart-callee-service-a和quickstart-callee-service-b分别作为QuickstartCalleeService的两个实例A和B,分别运行在48083和48084接口上。他们的位置元数据分别是 huanan/shenzhen-zone-1和huanan/shenzhen-zone-2。
另一个服务QucikstartCallerService提供了一些接口调用QuickstartCalleeService中的服务。
我们以QucikstartCallerService#/quickstart/caller/rest为例来演示就近路由功能。在CustomMetadataProvider类中设置服务的大区和区域,可以看到QucikstartCallerService默认的大区在huadong,没有设置区域。
试着多调用几次QucikstartCallerService#/quickstart/caller/feign,会发现被调实例为A和B。
Quickstart [QuickstartCalleeService] Service [10.15.119.34:48083] is called. datasource = [jdbcUrl='null', username='null', password='null'].
Quickstart [QuickstartCalleeService] Service [10.15.119.34:48084] is called. datasource = [jdbcUrl='null', username='null', password='null'].
Quickstart [QuickstartCalleeService] Service [10.15.119.34:48083] is called. datasource = [jdbcUrl='null', username='null', password='null'].
Quickstart [QuickstartCalleeService] Service [10.15.119.34:48084] is called. datasource = [jdbcUrl='null', username='null', password='null'].
修改QucikstartCallerService的CustomMetadataProvider,将大区和区域改为与实例A位置元数据一致的huanan/shenzhen-zone-1:
@Component
public class CustomMetadataProvider implements InstanceMetadataProvider {
@Override
public String getRegion() {
return "huadong";
}
@Override
public String getZone(){
return "shenzhen-zone-1";
}
}此时,试着多调用几次QucikstartCallerService#/quickstart/caller/feign,会发现QucikstartCallerService只调用了实例A。
Quickstart [QuickstartCalleeService] Service [10.15.119.34:48083] is called. datasource = [jdbcUrl='null', username='null', password='null'].
Quickstart [QuickstartCalleeService] Service [10.15.119.34:48083] is called. datasource = [jdbcUrl='null', username='null', password='null'].
由于实例A的位置元数据与QucikstartCallerService的位置元数据更匹配(双方都在huanan/shenzhen-zone-1),因此实例A的优先级高于实例B,因此SCT将被调服务路由到实例A。
就近路由的原理其实非常简单,以 feign 调用为例,例如调用 http://user-serivce/user/get。
- 根据服务名(user-service)获取目标服务全量实例地址集合
- 这一步中,SCT 只会返回健康的实例集合。细节可参考源码PolarisLoadBalancer.java
- 根据元数据路由规则从全量实例中挑出部分满足规则的实例子集
- 这一步中,SCT 会执行一次地址 Filter 链,输入是全量地址,输出是经过所有地址 Filter 之后的结果。其中一个 Filter 就是就近路由 Filter NearbyRouter。执行 Filter 链的调用代码请参考:PolarisLoadBalancerCompositeRule#doRouter
- 根据第二步的实例子集,执行负载均衡策略,选中其中一个实例。并替换请求 Url 例如:
http://192.168.1.1:8080/user/get
- 执行负载均衡调用代码请参考:PolarisLoadBalancerCompositeRule#choose
- 您在使用过程中遇到任何问题,请提 Issue 或者加入我们的开发者群告诉我们,我们会在第一时间反馈
- Spring Cloud Tencent 社区期待您的加入,一个 Star、PR 都是对我们最大的支持
- 项目介绍
- 使用指南
- 最佳实践
- 开发文档
- 学习资料