0%

Spring Cloud Gateway 灰度负载均衡

  1. 创建自定义负载均衡拦截器
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    public class GrayscaleLoadBalancerClientFilter extends LoadBalancerClientFilter {

    private static final String VERSION = "version";
    private final DiscoveryClient discoveryClient;
    private final AtomicInteger nextServerCyclicCounter;

    public GrayscaleLoadBalancerClientFilter(LoadBalancerClient loadBalancer, DiscoveryClient discoveryClient) {
    super(loadBalancer);
    this.discoveryClient = discoveryClient;
    this.nextServerCyclicCounter = new AtomicInteger(0);
    }

    @Override
    protected ServiceInstance choose(ServerWebExchange exchange) {
    URI uri = (URI) exchange.getAttributes().get(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
    List<ServiceInstance> list = discoveryClient.getInstances(uri.getHost());
    if (CollectionUtils.isEmpty(list)) {
    return null;
    }
    List<String> listHeaders = exchange.getRequest().getHeaders().get(VERSION);
    String version = CollectionUtils.isEmpty(listHeaders)
    ? null : (StringUtils.isBlank(listHeaders.get(0)) ? null : listHeaders.get(0));
    if (Objects.nonNull(version)) {
    list = list.stream().
    filter(serviceInstance -> version.equals(serviceInstance.getMetadata().get(VERSION)))
    .collect(Collectors.toList());
    if (!CollectionUtils.isEmpty(list)) {
    return list.get(this.incrementAndGetModulo(list.size()));
    }
    }
    list = list.stream().
    filter(serviceInstance -> !serviceInstance.getMetadata().containsKey(VERSION))
    .collect(Collectors.toList());
    return list.isEmpty() ? null : list.get(this.incrementAndGetModulo(list.size()));
    }

    private int incrementAndGetModulo(int modulo) {
    int current;
    int next;
    do {
    current = this.nextServerCyclicCounter.get();
    next = (current + 1) % modulo;
    } while(!this.nextServerCyclicCounter.compareAndSet(current, next));

    return next;
    }
    }
  2. 注入自定义负载均衡拦截器
    1
    2
    3
    4
    5
    6
    @Bean
    @Profile("dev")
    public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client,
    DiscoveryClient discoveryClient) {
    return new GrayscaleLoadBalancerClientFilter(client, discoveryClient);
    }
  3. 配置服务元数据

    可以在bootstrap.yml 中配置,或者在注册中心中设置

    1
    2
    3
    4
    5
    6
    spring:
    cloud:
    nacos:
    discovery:
    metadata:
    version: 1