parent
d76c5a5963
commit
935bb2a454
@ -1,36 +1,37 @@ |
|||||||
* [首页](/?t=1578910309712) |
* [首页](/?t=1579169719974) |
||||||
* 开发文档 |
* 开发文档 |
||||||
* [快速体验](files/10010_快速体验.md?t=1578910309714) |
* [快速体验](files/10010_快速体验.md?t=1579169719976) |
||||||
* [项目接入到SOP](files/10011_项目接入到SOP.md?t=1578910309731) |
* [项目接入到SOP](files/10011_项目接入到SOP.md?t=1579169719993) |
||||||
* [新增接口](files/10020_新增接口.md?t=1578910309732) |
* [新增接口](files/10020_新增接口.md?t=1579169719993) |
||||||
* [开发流程](files/10021_开发流程.md?t=1578910309732) |
* [开发流程](files/10021_开发流程.md?t=1579169719993) |
||||||
* [业务参数校验](files/10030_业务参数校验.md?t=1578910309732) |
* [业务参数校验](files/10030_业务参数校验.md?t=1579169719993) |
||||||
* [错误处理](files/10040_错误处理.md?t=1578910309732) |
* [错误处理](files/10040_错误处理.md?t=1579169719993) |
||||||
* [编写文档](files/10041_编写文档.md?t=1578910309732) |
* [编写文档](files/10041_编写文档.md?t=1579169719993) |
||||||
* [接口交互详解](files/10050_接口交互详解.md?t=1578910309732) |
* [接口交互详解](files/10050_接口交互详解.md?t=1579169719993) |
||||||
* [easyopen支持](files/10070_easyopen支持.md?t=1578910309732) |
* [easyopen支持](files/10070_easyopen支持.md?t=1579169719993) |
||||||
* [使用签名校验工具](files/10080_使用签名校验工具.md?t=1578910309732) |
* [使用签名校验工具](files/10080_使用签名校验工具.md?t=1579169719993) |
||||||
* [ISV管理](files/10085_ISV管理.md?t=1578910309732) |
* [ISV管理](files/10085_ISV管理.md?t=1579169719994) |
||||||
* [自定义返回结果](files/10087_自定义返回结果.md?t=1578910309733) |
* [自定义返回结果](files/10087_自定义返回结果.md?t=1579169719994) |
||||||
* [自定义过滤器](files/10088_自定义过滤器.md?t=1578910309733) |
* [自定义过滤器](files/10088_自定义过滤器.md?t=1579169719994) |
||||||
* [自定义校验token](files/10089_自定义校验token.md?t=1578910309733) |
* [自定义校验token](files/10089_自定义校验token.md?t=1579169719994) |
||||||
* [路由授权](files/10090_路由授权.md?t=1578910309733) |
* [路由授权](files/10090_路由授权.md?t=1579169719994) |
||||||
* [接口限流](files/10092_接口限流.md?t=1578910309733) |
* [接口限流](files/10092_接口限流.md?t=1579169719994) |
||||||
* [监控日志](files/10093_监控日志.md?t=1578910309733) |
* [监控日志](files/10093_监控日志.md?t=1579169719994) |
||||||
* [SDK开发](files/10095_SDK开发.md?t=1578910309733) |
* [SDK开发](files/10095_SDK开发.md?t=1579169719994) |
||||||
* [使用SpringCloudGateway](files/10096_使用SpringCloudGateway.md?t=1578910309733) |
* [使用SpringCloudGateway](files/10096_使用SpringCloudGateway.md?t=1579169719994) |
||||||
* [应用授权](files/10097_应用授权.md?t=1578910309733) |
* [应用授权](files/10097_应用授权.md?t=1579169719994) |
||||||
* [提供restful接口](files/10100_提供restful接口.md?t=1578910309733) |
* [提供restful接口](files/10100_提供restful接口.md?t=1579169719995) |
||||||
* [文件上传](files/10104_文件上传.md?t=1578910309734) |
* [文件上传](files/10104_文件上传.md?t=1579169719995) |
||||||
* [配置Sleuth链路追踪](files/10109_配置Sleuth链路追踪.md?t=1578910309734) |
* [配置Sleuth链路追踪](files/10109_配置Sleuth链路追踪.md?t=1579169719995) |
||||||
* [预发布灰度发布](files/10110_预发布灰度发布.md?t=1578910309734) |
* [预发布灰度发布](files/10110_预发布灰度发布.md?t=1579169719995) |
||||||
* [动态修改请求参数](files/10111_动态修改请求参数.md?t=1578910309734) |
* [动态修改请求参数](files/10111_动态修改请求参数.md?t=1579169719995) |
||||||
* [使用eureka](files/10112_使用eureka.md?t=1578910309734) |
* [使用eureka](files/10112_使用eureka.md?t=1579169719995) |
||||||
* [扩展其它注册中心](files/10113_扩展其它注册中心.md?t=1578910309734) |
* [扩展其它注册中心](files/10113_扩展其它注册中心.md?t=1579169719995) |
||||||
* 原理分析 |
* 原理分析 |
||||||
* [原理分析之@ApiMapping](files/90010_原理分析之@ApiMapping.md?t=1578910309734) |
* [原理分析之@ApiMapping](files/90010_原理分析之@ApiMapping.md?t=1579169719995) |
||||||
* [原理分析之如何存储路由](files/90011_原理分析之如何存储路由.md?t=1578910309734) |
* [原理分析之如何存储路由](files/90011_原理分析之如何存储路由.md?t=1579169719995) |
||||||
* [原理分析之如何路由](files/90012_原理分析之如何路由.md?t=1578910309734) |
* [原理分析之如何路由](files/90012_原理分析之如何路由.md?t=1579169719995) |
||||||
* [原理分析之文档归纳](files/90013_原理分析之文档归纳.md?t=1578910309734) |
* [原理分析之文档归纳](files/90013_原理分析之文档归纳.md?t=1579169719996) |
||||||
* [2.x升3.x注意事项](files/90014_2.x升3.x注意事项.md?t=1578910309734) |
* [原理分析之预发布灰度发布](files/90014_原理分析之预发布灰度发布.md?t=1579169719996) |
||||||
* [常见问题](files/90100_常见问题.md?t=1578910309734) |
* [2.x升3.x注意事项](files/90099_2.x升3.x注意事项.md?t=1579169719996) |
||||||
|
* [常见问题](files/90100_常见问题.md?t=1579169719996) |
||||||
|
@ -0,0 +1,92 @@ |
|||||||
|
# 原理分析之预发布灰度发布 |
||||||
|
|
||||||
|
SOP网关采用`自定义负载均衡策略`来实现对预发布/灰度发布服务器实例的选择。 |
||||||
|
|
||||||
|
spring cloud gateway默认的负载均衡实现类在:`org.springframework.cloud.gateway.filter.LoadBalancerClientFilter.java`中 |
||||||
|
|
||||||
|
这个类主要做了几件事情: |
||||||
|
|
||||||
|
1. 解析出请求路径中的scheme |
||||||
|
2. 如果scheme不是以`lb`协议开头直接跳过 |
||||||
|
3. 如果scheme以`lb`协议开头,则说明需要进行负载均衡,选出一台微服务实例 |
||||||
|
4. 将`lb`协议解析成`http://ip:port`,继续向下请求 |
||||||
|
|
||||||
|
其中第4步是由`org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient`来完成的, |
||||||
|
我们只要分别继承`LoadBalancerClientFilter`和`RibbonLoadBalancerClient`,然后重写其中的方法就能完成自定义负载均衡。 |
||||||
|
|
||||||
|
SOP中的重写类是:`SopLoadBalancerClientFilter`和`SopLoadBalancerClient`,核心代码委托给了`LoadBalanceServerChooser`处理,核心代码如下: |
||||||
|
|
||||||
|
```java |
||||||
|
/** |
||||||
|
* 选择服务器 |
||||||
|
* |
||||||
|
* @param serviceId serviceId,仅gateway网关有作用 |
||||||
|
* @param exchange 请求上下文 |
||||||
|
* @param loadBalancer loadBalancer |
||||||
|
* @param superChooser 父类默认的选择 |
||||||
|
* @param serverChooserFunction 执行选择操作 |
||||||
|
* @return 返回服务器实例,没有选到则返回null |
||||||
|
*/ |
||||||
|
public R choose( |
||||||
|
String serviceId |
||||||
|
, T exchange |
||||||
|
, ILoadBalancer loadBalancer |
||||||
|
, Supplier<R> superChooser |
||||||
|
, Function<List<Server>, R> serverChooserFunction) { |
||||||
|
// 获取所有服务实例 |
||||||
|
List<Server> servers = loadBalancer.getReachableServers(); |
||||||
|
|
||||||
|
// 存放预发服务器 |
||||||
|
List<Server> preServers = new ArrayList<>(4); |
||||||
|
// 存放灰度发布服务器 |
||||||
|
List<Server> grayServers = new ArrayList<>(4); |
||||||
|
// 存放非预发服务器 |
||||||
|
List<Server> notPreServers = new ArrayList<>(4); |
||||||
|
|
||||||
|
for (Server server : servers) { |
||||||
|
// 获取实例metadata |
||||||
|
Map<String, String> metadata = getMetadata(serviceId, server); |
||||||
|
// 是否开启了预发模式 |
||||||
|
if (this.isPreServer(metadata)) { |
||||||
|
preServers.add(server); |
||||||
|
} else if (this.isGrayServer(metadata)) { |
||||||
|
grayServers.add(server); |
||||||
|
} else { |
||||||
|
notPreServers.add(server); |
||||||
|
} |
||||||
|
} |
||||||
|
notPreServers.addAll(grayServers); |
||||||
|
// 如果没有开启预发布服务和灰度发布,直接用默认的方式 |
||||||
|
if (preServers.isEmpty() && grayServers.isEmpty()) { |
||||||
|
return superChooser.get(); |
||||||
|
} |
||||||
|
// 如果是从预发布域名访问过来,则认为是预发布请求,选出预发服务器 |
||||||
|
if (this.isRequestFromPreDomain(exchange)) { |
||||||
|
return serverChooserFunction.apply(preServers); |
||||||
|
} |
||||||
|
// 如果是灰度请求,则认为是灰度用户,选出灰度服务器 |
||||||
|
if (this.isRequestGrayServer(exchange)) { |
||||||
|
return serverChooserFunction.apply(grayServers); |
||||||
|
} |
||||||
|
|
||||||
|
// 到这里说明不能访问预发/灰度服务器,则需要路由到非预发服务器 |
||||||
|
// 注意:这里允许走灰度服务器,如果不允许走,注释notPreServers.addAll(grayServers);这行 |
||||||
|
return serverChooserFunction.apply(notPreServers); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
其业务逻辑如下: |
||||||
|
|
||||||
|
1. 选出`serviceId`对应的所有服务器实例 |
||||||
|
2. 将服务器实例进行分类,分别放进`预发布List`,`灰度List`,`非预发布List`中 |
||||||
|
3. 如果`预发布List`,`灰度List`都为空,表示没有开启任何预发/灰度服务,直接使用父类的负载均衡策略 |
||||||
|
4. 如果是从预发布域名访问过来,则认为是预发布请求,选出预发服务器 |
||||||
|
5. 如果是灰度请求,则认为是灰度用户,选出灰度服务器 |
||||||
|
6. 最后剩下的是正常用户,正常用户不能走预发环境 |
||||||
|
|
||||||
|
## 参考类 |
||||||
|
|
||||||
|
- com.gitee.sop.gatewaycommon.gateway.filter.SopLoadBalancerClientFilter |
||||||
|
- com.gitee.sop.gatewaycommon.gateway.loadbalancer.SopLoadBalancerClient |
||||||
|
- com.gitee.sop.gatewaycommon.gateway.loadbalancer.GatewayLoadBalanceServerChooser |
||||||
|
|
Loading…
Reference in new issue