在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的服务,一般是指服务消费方。

灰度管控端 负责灰度信息的管理、持久化等维护工作。

灰度客户端会从灰度管控端拉取一份灰度信息的清单,并在内存中维护这份清单信息,清单中包含服务,服务实例,灰度策略,灰度追踪字段等。当请求达到网关时,网关就会在灰度追踪中将需要透传的信息记录下来,并将传递给转发的服务实例,后面的接口调用也会按照同样的逻辑将追踪信息透传下去,从而保证所有一个请求在微服务调用链中的灰度路由。

image

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);
}

}


Steven
21 声望3 粉丝

对酒当歌,人生几何,美景之中,举杯畅饮,放下心中的执念,醉一回,痛快一回;一本樱花酒,醉了春风醉了酒。