Public search “code road mark”, point of concern not lost!

In the last article “Remember the first reflection application practice”, gray scale judgment logic only uses random numbers to simulate. Because the sample Demo uses Dubbo+Nacos technology, Nacos can also be used as a configuration hub. So I went ahead and tried to incorporate Nacos to make our Demo more functional.

Gray level design

Let’s go back to the question itself. For large systems, the alternation of old and new systems means the introduction of changes, which may bring risks. In order to make the risk controllable when the alternation of old and new systems, the new system needs to support grayscale release and gradually increase volume.

Batch gray scale is a commonly used method. For example, in the business system with the user dimension, users can be divided into 100 copies by taking the model of 100 user IDS. We can open the new function to 10% of users first, gray scale after a period of time, if the system runs normally, can refer to gradually open to 20%, 50% and 100%; And gray scale should support dynamic modification, one can dynamically achieve gray scale batch expansion or reduction without online release, and two can be found in the new system bug immediately turn off gray switch, timely hemostasis. In addition, the new system needs to have the stage of joint investigation and testing, especially the online system needs to select individual test users for trial, so it needs to open special channels through the whitelist function; Similarly, if certain users cannot use the new function for some reason, the blacklist function can be used to shield these users.

To sum up, batch gray can be achieved by gray batch percentage, whitelist, blacklist, the priority between the three whitelist > blacklist > gray percentage, the following code reflects this logic.

/** * Percentage grayscale configuration * < P > * Priority: Whitelist > Blacklist > Grayscale rule **@author raysonxin
 * @since2021/1/23 * /
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PercentGrayModel {

    /** * Percentage, integer. Value range: [0,100], 0 indicates disabled, and 100 indicates full */
    private Integer percent;

    /** * Whitelist */
    private List<Long> whiteList;

    /** ** blacklist */
    private List<Long> blackList;

    /** * Check if the target matches grayscale **@paramThe target goal *@returnTrue - hit, false- missed */
    public boolean hitGray(Long target) {
        // Data is abnormal
        if (null == target || target < 0L) {
            return false;
        }

        // Match whitelist, return true
        if(! ObjectUtils.isEmpty(whiteList) && whiteList.contains(target)) {return true;
        }

        // If the blacklist matches, false is returned
        if(! ObjectUtils.isEmpty(blackList) && blackList.contains(target)) {return false;
        }

        // No percentage grayscale rule
        if (percent == null || percent < 0) {
            return false;
        }

        // Greater than or equal to 100, equivalent to full
        if (percent >= 100) {
            return true;
        }

        // Calculate whether a match is made according to the gray percentage
        return target % 100< percent; }}Copy the code

Nacos configuration management

The new configuration

For convenience, I directly used the Docker version of Nacos. After installing Docker CE, you can download and run it directly from this address. The browser type http://localhost:8848/nacos, the default user name and password are nacos. Click “Configuration Management – Configuration List -➕” to add a configuration, and then publish it (as shown below) :

  • Data ID: com. Rsxtech. Demo. Consumer: gray – rule. Json
  • Group: DEFAULT_GROUP
  • Configuration content: The following figure shows the Json structure.

Code integration

Nacos provides Java SDK as well as Spring, Spring Boot and Spring Cloud support. I wanted to use the Spring Boot version of the API, but I kept having problems and had to use the Java SDK instead. Java SDK integration is also relatively simple, you can see the SDK usage posture here.

We mainly use two apis for Nacos configuration management:

  • Get configuration: Actively get configuration content from Nacos when the application starts;
  • Monitor configuration modification: When the Nacos configuration is modified, the latest configuration can be received in real time and take effect.

Add the configuration item nacos.server-addr to the application.properties file, and then add the configuration management class TransferGray as follows:

/** * Grayscale configuration get **@author raysonxin
 * @since2021/1/23 * /
@Component
@Slf4j
public class TransferGray {

    @Value("${nacos.server-addr}")
    private String nacosServer;

    private static final String dataId = "com.rsxtech.demo.consumer:gray-rule.json";
    private static final String group = "DEFAULT_GROUP";

    /** * Configure the content */
    public static PercentGrayModel grayConfig;

    @PostConstruct
    public void init(a) throws NacosException, JsonProcessingException {
        Properties properties = new Properties();
        properties.put("serverAddr", nacosServer);

        ConfigService configService = NacosFactory.createConfigService(properties);

        // After startup, actively pull configuration.
        String content = configService.getConfig(dataId, group, 5000);
        log.info("TransferGrayConfig get config={}", content);
        if (ObjectUtils.isEmpty(content)) {
            return;
        }

        ObjectMapper objectMapper = new ObjectMapper();
        grayConfig = objectMapper.readValue(content, PercentGrayModel.class);

        // When configuration changes in Nacos, new content can be received.
        configService.addListener(dataId, group, new Listener() {
            @Override
            public Executor getExecutor(a) {
                return null;
            }

            @Override
            public void receiveConfigInfo(String s) {
                log.info("TransferGrayConfig get config={}", s);
                try {
                    ObjectMapper objectMapper = new ObjectMapper();
                    grayConfig = objectMapper.readValue(content, PercentGrayModel.class);
                } catch (Exception ex) {
                    log.error("TransferGrayConfig parse config error", ex); }}}); }}Copy the code

Configuration for

Make a breakpoint in the code, start the application, and see that we have the configuration content.

Configure publishing and listening

Make a breakpoint in the receiveConfigInfo method, then open the new configuration item and go to the edit page. Modify the percent value and click Publish to see that our breakpoint hit and get the latest configuration. As shown in the following two figures:

Gray level access

You can now modify the previous needTransfer method. Here, I added userId to the original interface parameters to facilitate judging according to the gray strategy.

@Data
@ToString
public class HelloRequestCmd implements Serializable {

    private static final long serialVersionID = 1L;

    /** * user id ** /
    private Long userId;

    /** * name */
    private String name;

    /** ** greeting */
    private String greeting;
}
Copy the code

For simplicity, interface forwarding converts and judges the current method parameters, as shown below:

    /** * grayscale judgment logic **@returnTrue - Matching gray scale, perform forwarding; False - Do not forward */
    private boolean needTransfer(Object[] args) {
        // In the actual situation, we need to write a method to analyze gray parameters according to parameter characteristics.
        // For example, in our old system, all interfaces contain a user request object, you can find a parameter, and then perform gray judgment.
        HelloRequestCmd cmd = (HelloRequestCmd) args[0];
        PercentGrayModel percentGrayModel = TransferGray.grayConfig;
        return percentGrayModel.hitGray(cmd.getUserId());
    }
Copy the code

In practice, to determine whether the interface is to forward or not, an appropriate parsing method needs to be written according to the parameter characteristics of each method. Because the method parameters to forward are known, we have a way to get them. Often in our system, in order to uniformly encapsulate the request parameters, some common parameters will be put into the parameter base class or HTTP request header, which will greatly increase our processing convenience.

The test results

Now I’m ready to test. Here I use the HTTP test tool that comes with IDEA. The screenshots of the corresponding whitelist, blacklist, and gray test results are as follows:

Whitelist test

Blacklist test

Normal grayscale test

Public search “code road mark”, point of concern not lost!