Springboot2.3+Dubbo2.7.3实现灰度跳转

1、jar包依赖

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- Aapche Dubbo相关 start  -->
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
            <version>2.7.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-recipes</artifactId>
            <version>2.13.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.101tec</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.11</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-log4j12</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- Aapche Dubbo相关 end -->
</dependencies>  

2、自定义LoadBalance

package com.pacmp.config.balance;



import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.cluster.loadbalance.AbstractLoadBalance;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ThreadLocalRandom;

@Slf4j
@Component
public class GrayLoadBalance extends AbstractLoadBalance {

    public static final String NAME = "gray";

    public GrayLoadBalance() {
        log.info("初始化GrayLoadBalance成功!");
    }

    @Override
    protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
        List<Invoker<T>> list = new ArrayList<>();
        for (Invoker invoker : invokers) {
            list.add(invoker);
        }
        Map<String, String> map = invocation.getAttachments();
        String ifGary = map.get("ifGary");
        String userId = map.get("userId");
        log.info("userId:"+userId+"=====ifGary:"+ifGary);
        Iterator<Invoker<T>> iterator = list.iterator();
        while (iterator.hasNext()) {
            Invoker<T> invoker = iterator.next();
            String providerStatus = invoker.getUrl().getParameter("status", "prod");
            if (Objects.equals(providerStatus, NAME)) {
                if ("1".equals(ifGary)) {
                    log.info("userId:"+userId+"=====ifGary:"+ifGary+"=====去灰度服务");
                    return invoker;
                } else {
                    log.info("userId:"+userId+"=====ifGary:"+ifGary+"=====去正常服务");
                    iterator.remove();
                }
            }
        }
        return this.randomSelect(list, url, invocation);
    }


    /**
     * 重写了一遍随机负载策略
     *
     * @param invokers
     * @param url
     * @param invocation
     * @param <T>
     * @return
     */
    private <T> Invoker<T> randomSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
        int length = invokers.size();
        boolean sameWeight = true;
        int[] weights = new int[length];
        int firstWeight = this.getWeight((Invoker) invokers.get(0), invocation);
        weights[0] = firstWeight;
        int totalWeight = firstWeight;

        int offset;
        int i;
        for (offset = 1; offset < length; ++offset) {
            i = this.getWeight((Invoker) invokers.get(offset), invocation);
            weights[offset] = i;
            totalWeight += i;
            if (sameWeight && i != firstWeight) {
                sameWeight = false;
            }
        }

        if (totalWeight > 0 && !sameWeight) {
            offset = ThreadLocalRandom.current().nextInt(totalWeight);

            for (i = 0; i < length; ++i) {
                offset -= weights[i];
                if (offset < 0) {
                    return (Invoker) invokers.get(i);
                }
            }
        }
        return (Invoker) invokers.get(ThreadLocalRandom.current().nextInt(length));
    }
}

3、在resources加配置文件,路径如下图(路径必须一致)

文件名:org.apache.dubbo.rpc.cluster.LoadBalance

添加GrayLoadBalance类的路径

4、application.yml配置

消费者配置:

# dubbo
dubbo:
  application:
    name: dubbo_consumer
  registry:
    address: zookeeper://127.0.0.1:2181
  scan:
    base-packages: com.pacmp.controller
  consumer:
    version: 2.0.0
  provider:
    loadbalance: gray
  protocol:
    port: 10000

生产者配置:

loadbalance: gray   表示加载自定义loadbalance:com.pacmp.config.balance.GrayLoadBalance。
parameters:
      status: gray  表示这个生产者(服务),是否为灰度。如果不是灰度可以不用配置。
## Dubbo配置
dubbo:
  application:
    name: dubbo_provider
  registry:
    address: zookeeper://127.0.0.1:2181
  protocol:
    name: dubbo
    port: -1
  scan:
    base-packages: com.pacmp
  provider:
    loadbalance: gray
    version: 2.0.0
    parameters:
      status: gray

5、调用示例

package com.pacmp.controller;


import com.pacmp.service.DemoService;
import lombok.extern.slf4j.Slf4j;


import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.rpc.RpcContext;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.*;

/**
 * @Author xxx
 * @Date 2020/05/26 9:52
 * @Version 1.0
 * @Description 接入层
 */
@Slf4j
@RestController
@RequestMapping("/api")
public class ApiController {

    @Reference(check = false)
    private DemoService demoService;

    @GetMapping("/testUser")
    public String testUser(int userId, String version) {
        //ifGary=1代表灰度用户,0代表普通用户
        int ifGary = 0;
        if(userId<10){
            ifGary = 1;
        }
        RpcContext.getContext().setAttachment("ifGary", String.valueOf(ifGary));
        RpcContext.getContext().setAttachment("userId", String.valueOf(userId));
        return demoService.testUser(userId, version);
    }

}

6、测试

启2个生产者服务,1个消费者服务。可根据userId的不同来调用生产服务/灰度服务。

原文地址:https://www.cnblogs.com/penghq/p/13093812.html