在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;}@Overridepublic 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);@Overridepublic 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);@Overridepublic 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);}

}