本文依赖ribbon实现在Spring Cloud中的灰度测试。
POM引入
Zuul及下游服务中均引入包1
2
3
4
5
6<!-- 实现灰度测试关键包 -->
<dependency>
<groupId>io.jmnarloch</groupId>
<artifactId>ribbon-discovery-filter-spring-cloud-starter</artifactId>
<version>2.1.0</version>
</dependency>
Zuul服务开发
1 | private void fixGray(UserInfo userInfo) { |
下游服务开发
添加版本拦截器1
2
3
4
5
6
7
8
9
10
public class WebMvcConfig extends WebMvcConfigurerAdapter {
public void addInterceptors(InterceptorRegistry registry) {
super.addInterceptors(registry);
registry.addInterceptor(new VersionInterceptor());
}
}
实现拦截器1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class VersionInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//清除现有数据,防止干扰
RibbonFilterContextHolder.clearCurrentContext();
String prod = request.getHeader("prod");
String version = request.getHeader("version");
if (!StringUtils.isEmpty(prod)&&!StringUtils.isEmpty(version)) {
RibbonFilterContextHolder.getCurrentContext().add("prod", prod);
RibbonFilterContextHolder.getCurrentContext().add("version", version);
}
return true;
}
}
下游服务配置
1 | eureka: |
注意事项
- 通过以上配置,启动各服务,可以实现灰度测试和版本测试
- 在网关依据灰度和版本请求标识,Ribbon利用各服务的元信息进行匹配,以实现过滤和负载
- 服务中必须配置相应的请求标识,否则该请求无法负载,将会报错
- 关闭组件,ribbon.filter.metadata.enabled=false #默认true
源码及原理分析
元信息筛选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class MetadataAwarePredicate extends DiscoveryEnabledPredicate {
/**
* {@inheritDoc}
*/
protected boolean apply(DiscoveryEnabledServer server) {
//当前请求上下文
final RibbonFilterContext context = RibbonFilterContextHolder.getCurrentContext();
//当前请求属性
final Set<Map.Entry<String, String>> attributes = Collections.unmodifiableSet(context.getAttributes().entrySet());
//当前服务元信息
final Map<String, String> metadata = server.getInstanceInfo().getMetadata();
//服务元信息是否完全包含请求属性
return metadata.entrySet().containsAll(attributes);
}
}注册实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(DiscoveryEnabledNIWSServerList.class)
(RibbonClientConfiguration.class)
"ribbon.filter.metadata.enabled", matchIfMissing = true) (value =
public class RibbonDiscoveryRuleAutoConfiguration {
//在Spring application context注册DiscoveryEnabledRule
(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public DiscoveryEnabledRule metadataAwareRule() {
//使用自定义元信息过滤
return new MetadataAwareRule();
}
}配置请求信息
RibbonFilterContextHolder.getCurrentContext().add("version", "1.1").add("variant", "A");
在zuul中配置,以便调取下游
在下游拦截器中配置,以便当前服务继续调用下游服务
也可以在
RestTemplate
的ClientHttpRequestInterceptor
中配置