回复
聊聊 Spring Cloud 全链路灰度发布 方案~(二)
love374
发布于 2022-7-12 17:02
浏览
0收藏
第六个问题:说了这么多,具体如何实现?
网关中首先需要定义一个全局过滤器,伪代码如下:
public class GlobalGrayFilter implements GlobalFilter{
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//① 解析请求头,查看是否存在灰度发布的请求头信息,如果存在则将其放置在ThreadLocal中
HttpHeaders headers = exchange.getRequest().getHeaders();
if (headers.containsKey(GrayConstant.GRAY_HEADER)){
String gray = headers.getFirst(GrayConstant.GRAY_HEADER);
if (StrUtil.equals(gray,GrayConstant.GRAY_VALUE)){
//②设置灰度标记
GrayRequestContextHolder.setGrayTag(true);
}
}
//③ 将灰度标记放入请求头中
ServerHttpRequest tokenRequest = exchange.getRequest().mutate()
//将灰度标记传递过去
.header(GrayConstant.GRAY_HEADER,GrayRequestContextHolder.getGrayTag().toString())
.build();
ServerWebExchange build = exchange.mutate().request(tokenRequest).build();
return chain.filter(build);
}
}
①处的代码:从请求头中获取客户端传递过来的灰度标记(这里根据自己业务需要自行更改),判断是否是灰度发布
②处的代码:GrayRequestContextHolder则是自定义的ThreadLocal实现的线程隔离工具,用来存放灰度标记
③处的代码:将灰度标记放置在请求头中,传递给下游微服务,这里是和令牌一个逻辑。
“注意:这个全局过滤器一定要放在OAuth2.0鉴权过滤器之前,优先级要调高”
全局过滤器中已经将灰度标记打上了,放置在GrayRequestContextHolder中,下面只需要改造Ribbon的负载均衡的策略去注册中心选择灰度服务。
创建GrayRule,代码如下:
/**
* 灰度发布的规则
*/
public class GrayRule extends ZoneAvoidanceRule {
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
@Override
public Server choose(Object key) {
try {
//从ThreadLocal中获取灰度标记
boolean grayTag = GrayRequestContextHolder.getGrayTag().get();
//获取所有可用服务
List<Server> serverList = this.getLoadBalancer().getReachableServers();
//灰度发布的服务
List<Server> grayServerList = new ArrayList<>();
//正常的服务
List<Server> normalServerList = new ArrayList<>();
for(Server server : serverList) {
NacosServer nacosServer = (NacosServer) server;
//从nacos中获取元素剧进行匹配
if(nacosServer.getMetadata().containsKey(GrayConstant.GRAY_HEADER)
&& nacosServer.getMetadata().get(GrayConstant.GRAY_HEADER).equals(GrayConstant.GRAY_VALUE)) {
grayServerList.add(server);
} else {
normalServerList.add(server);
}
}
//如果被标记为灰度发布,则调用灰度发布的服务
if(grayTag) {
return originChoose(grayServerList,key);
} else {
return originChoose(normalServerList,key);
}
} finally {
//清除灰度标记
GrayRequestContextHolder.remove();
}
}
private Server originChoose(List<Server> noMetaServerList, Object key) {
Optional<Server> server = getPredicate().chooseRoundRobinAfterFiltering(noMetaServerList, key);
if (server.isPresent()) {
return server.get();
} else {
return null;
}
}
}
逻辑很简单,如下:
- 获取灰度标记
- 从Nacos注册中心获取灰度服务和正常服务
- 根据灰度标记去判断,如果灰度发布则选择特定的灰度服务进行转发
定义一个配置类,注入改造的灰度策略GrayRule,如下:
/**
* 灰度部署的负载规则配置类
* 注意:这个类一定不要被Spring Boot 扫描进入IOC容器中,一旦扫描进入则对全部的服务都将生效
*/
public class GrayRuleConfig {
@Bean
public GrayRule grayRule(){
return new GrayRule();
}
}
“注意:这个GrayRuleConfig不能被扫描进入IOC容器,一旦扫描进入则全局生效”
文章转自公众号:码猿技术专栏
标签
已于2022-7-12 17:02:07修改
赞
收藏
回复
相关推荐