在Spring Cloud Gray 由spring-cloud-gray-client(角色灰度客户端),spring-cloud-gray-client-netflix 和 spring-cloud-tray-server,spring-cloud-gray-webui组成。
spring-cloud-gray-client定义了一套灰度路由决策模型,灰度信息追踪模型,以及和spring-cloud-gray-server的基本通信功能。
spring-cloud-gray-client-netflix在spring-cloud-gray-client的基础上集成了微服务注册中心eureka,扩展ribbon的负载均衡规则,提供了对zuul,feign,RestTemplate的灰度路由能力,并且无缝支持hystrix线程池隔离。
spring-cloud-gray-server负责灰度决策、灰度追踪等信息的管理以及持久化。
注册中心 负责服务的注册和发现。
灰度客户端 灰度的客户端是指依赖了spring-cloud-gray-client的服务,一般是指服务消费方。
灰度管控端 负责灰度信息的管理、持久化等维护工作。
灰度客户端会从灰度管控端拉取一份灰度信息的清单,并在内存中维护这份清单信息,清单中包含服务,服务实例,灰度策略,灰度追踪字段等。当请求达到网关时,网关就会在灰度追踪中将需要透传的信息记录下来,并将传递给转发的服务实例,后面的接口调用也会按照同样的逻辑将追踪信息透传下去,从而保证所有一个请求在微服务调用链中的灰度路由。
public class CustomMetadataRule extends ZoneAvoidanceRule {
// 检测灰度开关是否启动
private HttpResult checkGraySwitch() {
String url = "http://127.0.0.1:6015/eureka/apps/switch";
HttpResult result = new HttpResult();
result.statusCode = 500;
try {
result = HttpClient.get(url, null);
} catch (Exception e1) {
e1.printStackTrace();
}
return result;
}
@Override
public Server choose(Object key) {
// 获取是否存在存活的服务可调用
List<Server> serverList = this.getPredicate().getEligibleServers(this.getLoadBalancer().getAllServers());
// 获取不到服务
if (CollectionUtils.isEmpty(serverList)) {
return null;
}
// 获取灰度开关是否启动
HttpResult result = checkGraySwitch();
// 灰度开关被设置成关闭状态,默认走空metadata或者是特定标识是正常的服务,轮询访问
Boolean isOpen = Boolean.parseBoolean(JSONObject.parseObject(result.content).getString("errorMsg"));
if (result.statusCode == 200 && !isOpen) {
isOpen = true;
return RoundRobinRuleBySelf.getInstance().choose(this.getLoadBalancer(), key,isOpen);
}
// 灰度发布启动状态,未被设置成灰度对象,默认走空metadata或者是特定标识是正常的服务,轮询访问
if (StringUtils.isEmpty(CoreHeaderInterceptor.label.get())) {
isOpen = false;
return RoundRobinRuleBySelf.getInstance().choose(this.getLoadBalancer(), key,isOpen);
}
// 灰度发布启动状态,被设置成灰度对象,走空特定标识的服务,轮询访问
return RoundRobinRuleBySelf.getInstance().choose(this.getLoadBalancer(), key,!isOpen);
}
}
feignClient 调用flag位透传的问题
public class CoreFeignRequestInterceptor implements RequestInterceptor {
private static final Logger logger = LoggerFactory.getLogger(CoreHttpRequestInterceptor.class);
@Override
public void apply(RequestTemplate template) {
String header = StringUtils.collectionToDelimitedString(CoreHeaderInterceptor.label.get(),CoreHeaderInterceptor.HEADER_LABEL_SPLIT);
String tag = CoreHeaderInterceptor.tag.get();
template.header(CoreHeaderInterceptor.HEADER_LABEL, header).header(CoreHeaderInterceptor.HEADER_TAG, tag);
logger.info("label: " + header + " tag : " + tag);
}
}
HttpRequest 调用flag位透传的问题
public class CoreHttpRequestInterceptor implements ClientHttpRequestInterceptor {
private static final Logger logger = LoggerFactory.getLogger(CoreHttpRequestInterceptor.class);
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
HttpRequestWrapper requestWrapper = new HttpRequestWrapper(request);
String header = StringUtils.collectionToDelimitedString(CoreHeaderInterceptor.label.get(), CoreHeaderInterceptor.HEADER_LABEL_SPLIT);
String tag = CoreHeaderInterceptor.tag.get();
logger.info("label: "+header + " tag : " + tag);
HttpHeaders headers = requestWrapper.getHeaders();
headers.add(CoreHeaderInterceptor.HEADER_LABEL, header);
headers.add(CoreHeaderInterceptor.HEADER_TAG, tag);
return execution.execute(requestWrapper, body);
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。