前言个人博客:👉进入博客,关注下博主,感谢~
🌈所有博客均在上面博客首发,其他平台同步更新
🏆大家一起进步,多多指教~
本篇是在k8s服务发现svc环境基础上来实现灰度方案,但是不是基于k8s实现。(我在餐厅吃饭,而不是我通过这个餐厅自己做法自己干饭)
k8s服务发现在抛开nacos作为注册中心的基础上,大部分公司会采用云原生来实现服务的注册,就是svc。当服务启动之后,pod会被service监听到,然后将end point注册上去,然后将服务名写到iptables
在流量进来的时候,会先经过网关ingress,然后通过iptables,来找到pod地址,进行路由。
实现思路在初探灰度发布系列–AB Test以及栗子这一篇的时候,我们介绍通过nacos实现灰度,就是通过nacos来拿到所有实例,以及实例里面元数据,进行负载均衡。
在k8s svc里头,我们也可以通过拿到这个服务列表来实现灰度,当然这个实现起来也是可以的。但是今天我们另辟蹊径,找个更简单的方法来实现。
实现方案
如上图所示,灰度用户会有特定标识,比如header不同,或者请求参数不同,ip不同,我们可以在网关层来进行不同打标,然后加上我们特定的标识,图中右边userid,如果生产用户默认给个666,让它路由到test域名,灰度用户路由到dev域名,这样就实现了灰度方案
网关源码(版本3.1.1)既然我们是基于网关来改造,那么就要熟悉网关源码
基本类类名 | 用途 |
---|---|
DispatcherHandler | HTTP请求处理程序/控制器的中央调度器。分派给注册的处理程序以处理请求,从而提供方便的映射功能。 |
HandlerMapping | 将请求映射到处理程序对象 |
HandlerAdapter | 用于使用任何处理程序接口 |
HandlerResultHandler | 进程处理程序返回值 |
网关源码
gateway在处理请求的时候,首先会在HttpWebHandlerAdapter进入DefaultWebFilterChain
DefaultWebFilterChainorg.springframework.web.server.handler.DefaultWebFilterChain#filter
DispatcherHandler- org.springframework.web.reactive.DispatcherHandler#setApplicationContext
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
initStrategies(applicationContext);
}
protected void initStrategies(ApplicationContext context) {
Map mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerMapping.class, true, false);
ArrayList mappings = new ArrayList<>(mappingBeans.values());
AnnotationAwareOrderComparator.sort(mappings);
this.handlerMappings = Collections.unmodifiableList(mappings);
Map adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerAdapter.class, true, false);
this.handlerAdapters = new ArrayList<>(adapterBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerResultHandler.class, true, false);
this.resultHandlers = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(this.resultHandlers);
}
这个类继承了ApplicationContextAware,也就是在类初始化之后会进行相关初始化 *** 作。它会拿到所有HandlerAdapter,HandlerResultHandler,HandlerMapping实现类
- org.springframework.web.reactive.DispatcherHandler#handle
这个handler就是每个处理处理逻辑
RoutePredicateHandlerMapping这个就是路由配置映射,会在路由配置表找,url对应哪个服务,服务在哪里
org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#lookupRoute
比如说我们添加了header带上特定参数,它在这个类会进行校验判断
FilteringWebHandler它会加载所有继承GatewayFilter类,然后进行排序。网关基本所有拦截器都会在这层去实现
灰度demo- 网关配置
spring:
cloud:
gateway:
routes:
# 服务
- id: a1
uri: https://dev-xx.com
predicates:
- Path=/xx/**
- Header=userid, 888
- id: a2
uri: https://test-xx.com
predicates:
- Path=/xx/**
- Header=userid, 666
网关通过header头来区分去哪里,那么我们就要在网关对特定流量进行染色
通过这个类RoutePredicateHandlerMapping,我们知道网关在这里进行路由规则判断,那么其实我们需要在它之前进行做手脚,如果通过GlobalFilter是无法实现的,他也在handler里头,而且优先级比RoutePredicateHandlerMapping低。
- 方法:实现WebFilter,改写header头
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
@Component
public class MyWebHandler implements WebFilter {
@Override
public Mono filter(ServerWebExchange exchange, WebFilterChain chain) {
String userid = exchange.getRequest().getHeaders().getFirst("userid");
if (StringUtils.isEmpty(userid)) {
ServerHttpRequest request = exchange.getRequest().mutate()
.header("userid", "666")
.build();
return chain.filter(exchange.mutate().request(request).build());
}
return chain.filter(exchange);
}
}
在这里我们可以实现对Header、host、IP、自定义需求来改写header!
就是如果你不带上userid这个header,默认给你加上,路由到生产。如果你加上了,可以自定义逻辑路由到灰度域名。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)