Files
SOP/doc/docs/files/90014_原理分析之预发布灰度发布.md
tanghc 935bb2a454 3.0.0
2020-01-16 18:20:58 +08:00

93 lines
4.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 原理分析之预发布灰度发布
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