Skip to content

chenlingmin/server-diverter

Repository files navigation

服务分流组件

本组件参考了 ribbon-discovery-filter-spring-cloud-starter 的实现,实现了基于 spring-cloud-netflix 应用服务按照标签区分,根据流量的标签,进行服务的智能选择的效果,以达到灰度发布的效果。

用法

快速开始

在 zuul 网关、以及需要灰度的应用服务添加依赖 spring-boot-netflix-server-diverter-starter

<dependency>
    <groupId>com.chenlm.cloud</groupId>
    <artifactId>spring-boot-netflix-server-diverter-starter</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

不希望使用 spring-boot-starter 自动配置配置的功能,也可以依赖 netflix-server-diverter,使用 @EnableServerDiverter 注解。

<dependency>
    <groupId>com.chenlm.cloud</groupId>
    <artifactId>netflix-server-diverter</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

再配置 eureka.client.instance.matedata-map.env 给服务注册上标签,未配置默认会取 spring.profiles.active 的值,这样服务就获得了根据请求头路由不同标签服务的能力,在 samples 的样例项目中,使用了默认的根据请求头 x-env 选择服务的策略,运行结果如下:

curl -H x-env:gray localhost/server-a/test
server-a-gray -> server-b-gray%

curl -H x-env:prod localhost/server-a/test
server-a-prod -> server-b-prod%

curl -H x-env:gray localhost/server-a/async                                                                                                                                                                                                             
server-a-gray -> server-b-gray%

curl -H x-env:prod localhost/server-a/async                                                                                                                                                                                                             
server-a-prod -> server-b-prod%

当然,你也可以自定义服务策略,实现 ServerSelector 接口,将其注册成 Bean,目前已有的实现是 SimplerHeaderServerSelector

/**
 * 服务选择器
 * 用户可以自定义多个服务选择器,应该注意选择器之间的顺序
 */
public interface ServerSelector {
    /**
     * 表示该选择器是否支持此类请求
     */
    boolean support(HttpServletRequest request);

    /**
     * 选择标签服务
     */
    String select(HttpServletRequest request);
}

public class SimpleHeaderServerSelector implements ServerSelector{
    private final String headerName;
    public SimpleHeaderServerSelector(String headerName) {this.headerName = headerName;}
    @Override
    public boolean support(HttpServletRequest request) {
        return request.getHeader(headerName) != null;
    }
    @Override
    public String select(HttpServletRequest request) {
        return request.getHeader(headerName);
    }
}

例如配置从请求头 x-hello、或 x-world 中获取环境信息,如下配置。

@Configuration
public class TestConfiguration {
    @Bean
    public ServerSelector serverSelector1() {
        return new SimpleHeaderServerSelector("x-hello");
    }
    @Bean
    public ServerSelector serverSelector2() {
        return new SimpleHeaderServerSelector("x-world");
    }
}

配置项

  • server.diverter.enabled 是否启用服务分流,默认 true
  • server.diverter.server-mark-name 服务注册的 metadataMap 的 key,默认为 env
  • server.diverter.http-header-name 流量染色的http请求头,默认为 x-env

原理

服务自动打上标签

服务启动时,会自动向 eurake 注册的内容中,添加 metadataMap.env 标签,标签值取 spring.profiles.active 的值。

如果需要自定义,直接在服务中配置 eureka.client.instance.matedata-map.env 即可。

注意:上述的标签名称,以 server.diverter.server-mark-name 配置为准,默认为 env

按照标签选择服务

如图,基本原理是通过请求头区分流量,可用与灰度与生产的流量切分

标签不存在时选择服务

当流量标签所在的服务不存在时,则退化到原来的负载路由策略。下图中,a_server_2 宕机,prod 流量能正常走 zuul -> a_server_1 -> b_server1 路径;而 gray 流量由于 a_server_2 宕机,所以 zuul 先访问 a_server_1,再访问到 b_server_2 中,即 zuul -> a_server_1 -> b_server_2。

异步调用流量染色

  • 默认处理了 Spring 管理的 Executor,使其获得了父子线程传递 RequestAttributes 的能力。
  • 目前实现了 RestTemplateAsyncRestTemplateFeign 在 Spring 管理的线程池上流量染色的能力。
  • 手动 new Thread 中,无法获取 RequestAttributes,会导致流量染色无法传递,需要使用 AsyncDecorators.runnable 对任务进行包装,使其获得传递 RequestAttributes 的能力, 例如:
new Thread(AsyncDecorators.runnbale.decorate(new Runnable(){
    RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
    Assert.notNull(requestAttributes);
})).start();

异步线程无上下文,使用服务自身标签进行传递

异步线程无上下文,形成的原因可能是:

  • request 作用域未传递到子线程中,可能是使用了非 Spring 管理的线程池,或者手动 new Thread() 未进行包装;
  • 定时任务、MQ 等。

在这种情况下,会使用服务自身标签进行传递,也就是会选择与自身标签一样的服务,如图 a_server_1 选择 b_server_1, a_server_2 选择 b_server_2

About

基于 spring-cloud-netflix 的灰度方案

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages