preface

Hello everyone, today we start to share – Dubbo topic Dubbo routing rules tag routing. In the previous chapter, we introduced the Dubbo label routing routing rules, and we also illustrates common usage scenarios and source code analysis to analyses the implementation principle, at the same time know Dubbo label routing in its essence is through the filter to the service provider list of rule matching, if can’t match the filter service provider. So let’s talk about tag routing. What is tag routing? What are the usage scenarios? Let’s get started quickly!

1. Introduction to label routing

What is a routing rule? Here we mainly discuss what tag routing is:

In the figure above, we can see that there are two machine rooms: Machine room A and machine room B. Machine room A can only access Service A and Service B, while machine room B can only access Service C and Service D. To implement this scenario we need to use tag routing. The call from room A carries labels TAG_A to access Service A and Service B, while the call from room B carries labels TAG_B Service C and Service D. So what is tag routing?

  • Label routing: Configure routing rules based on the granularity of service provider applications. By grouping one or more service providers into the same group, traffic is restricted to the specified group and traffic is isolated. It can be used as the basis for blue-green and grayscale advertising. Labels are used to group application instances on the Provider. You can group instance instances in either of the following waysDynamic rule markingandStatic regular marking, dynamic rules have a higher priority than static rules. When two rules exist and conflict occurs, dynamic rules prevail.

2. Usage

Let’s briefly discuss the use of tag routing:

2.1 Label Routing

  • Dynamic rule marking. Label grouping rules can be delivered from the service governance console at any time
# Demo-Provider adds two tag groups, TAG1 and tag2
  # tag1 contains an instance of 127.0.0.1:20880
  # tag2 contains an instance 127.0.0.1:20881
  ---
    force: false
    runtime: true
    enabled: true
    key: demo-provider
    tags:
      - name: tag1
        addresses: ["127.0.0.1:20880"]
      - name: tag2
      addresses: ["127.0.0.1:20881"]
Copy the code
  • Static marking
 <dubbo:provider tag="tag1"/>
Copy the code

or

 <dubbo:service tag="tag1"/>
Copy the code

or

 java -jar xxx-provider.jar -Ddubbo.provider.tag={the tag you want, may come from OS ENV}
Copy the code

* * Tips: ** The consumer uses rpcContext.getContext ().setAttachment(CommonConstants.TAG_KEY,”TAG_A”) programmatically. The scope of the request tag is every invocation, Use the attachment to pass the request tag. Note that the value stored in the attachment will be passed continuously in a complete remote call. Thanks to this feature, we only need to set a line of code at the beginning of the call to achieve the continuous pass of the tag.

  • Field Description:
Serial number The field names instructions mandatory
1 scope Granularity of routing rules. The value of scope determines the value of key.

Service Service granularity Application Application granularity.
mandatory
2 Key Specify which interface service or application the rule body applies to. The scope = service,

When key is the combination of [{group}:]{service}[:{version}] scope=application,

Key is the application name.
mandatory
3 enabled enabled=trueIndicates whether the current routing rule takes effect. Don’t fill in
4 force force=falseWhen the route result is empty, whether to force the route. If not,

The routing rule whose route result is empty is invalid automatically. The default value isfalse.
Don’t fill in
5 runtime runtime=falseWhether routing rules are executed on each invocation,

Otherwise, only pre-execute and cache the results when the provider address list changes,

Call directly from the cache to get the routing result. If parametric routing is used, this parameter must be set totrue.

Note that this parameter affects the performance of the call. The default value isfalse.
Don’t fill in
6 priority priority=1The priority of a routing rule is used for sorting. The higher the priority is, the earlier the rule is executed. The default value is0. Don’t fill in
7 tags Define specific tag grouping contents. You can define any N (n>=1) tags and specify a list of instances for each tag. Name indicates the label name mandatory

2.2 Degrade Convention

  • request.tag=tag1Time to select the tag firsttag=tag1provider. If no service corresponding to the request tag exists in the cluster, the request tag is degraded to empty by defaultprovider; If you want to change this default behavior, no match is foundtag1theproviderReturn exception, need to setrequest.tag.force=true.
  • request.tagIf this parameter is not set, only matchestagIs emptyprovider. Even if there are available services in the cluster, the tag cannot be invoked if it does not match. Unlike convention 1, a request with a tag can degrade access to a service without a tag, but a request without a tag or a request with a tag of another kind can never access a service with another tag.

Tips: For 2.6.x and earlier versions, use routing rules of earlier versions to customize route reference route extension

3. Application scenarios

From the above brief introduction, we can roughly understand that label routing implements traffic isolation by grouping one or more service providers into the same group and restricting traffic to flow only in the specified group. The common scenes in our daily work are: blue-green release, grayscale release and other scenes of ability basis.

4. Example demonstration

In the example of getting a book list, we will start two service providers to configure two ports: 20880 and 20881, and then specify two service labels: TAG_A and TAG_B respectively. The project structure diagram is as follows:

Here we use dynamic marking. All the configuration in XML remains the same as in the previous example. Let’s focus on the configuration in Dubbo Admin:

# Demo-Provider adds two tag groups TAG_A and TAG_B
# TAG_A contains an instance 127.0.0.1:20880
# TAG_B contains an instance 127.0.0.1:20881
force: true
enabled: true
runtime: false
tags:
 - name: TAG_A
   addresses: [192.168. 01.: 20880]
 - name: TAG_B
   addresses: [192.168. 02.: 20881]
Copy the code

The preceding dynamic marking configuration indicates that the 127.0.0.1:20880 service provider is invoked when the label is TAG_A and 127.0.0.1:20881 service is invoked when the label is TAG_B.

Tips: You can dynamically switch between TAG_A and TAG_A on the consumer side to check the effect. The server only needs to start a service with port 20880.

5. Implementation principle

According to the previous introduction, we know that the consumer side calls the remote service through the routing rules for service filtering, so we through the source code simple analysis of this process. Here we see the routing rules directly call the core code org. Apache. Dubbo. RPC. Cluster. RouterChain# route core method is as follows:

    public List<Invoker<T>> route(URL url, Invocation invocation) {
        List<Invoker<T>> finalInvokers = invokers;
        for (Router router : routers) {
            finalInvokers = router.route(finalInvokers, url, invocation);
        }
        return finalInvokers;
    }
Copy the code

Here are the routing rules we run:

Where TagRouter is our tag routing core code is as follows:

/** ** Label routing **@author liyong
     * @date 4:48 PM 2020/11/29
     * @param invokers
     * @param url
     * @param invocation
     * @exception
     * @return java.util.List<org.apache.dubbo.rpc.Invoker<T>>
     **/
    @Override
    public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
        if (CollectionUtils.isEmpty(invokers)) {
            return invokers;
        }

        // Because the configuration center may update the configuration, use another constant reference (similar to replication).
        final TagRouterRule tagRouterRuleCopy = tagRouterRule;
        // If the dynamic rule does not exist or is invalid or not active, use static labels
        if (tagRouterRuleCopy == null| |! tagRouterRuleCopy.isValid() || ! tagRouterRuleCopy.isEnabled()) {// Handle static tags
            return filterUsingStaticTag(invokers, url, invocation);
        }

        List<Invoker<T>> result = invokers;
        // Gets the Attachment label parameter in the context, which is written when the client calls it
        String tag = StringUtils.isEmpty(invocation.getAttachment(TAG_KEY)) ? url.getParameter(TAG_KEY) :
                invocation.getAttachment(TAG_KEY);

        // If there is a pass tag
        if (StringUtils.isNotEmpty(tag)) {
            // Find the service address corresponding to the dynamic configuration by passing the label
            List<String> addresses = tagRouterRuleCopy.getTagnameToAddresses().get(tag);
            // Filter by label group
            if (CollectionUtils.isNotEmpty(addresses)) {
                // Get the service that matches the address
                result = filterInvoker(invokers, invoker -> addressMatches(invoker.getUrl(), addresses));
                // If the result is not null or if the result is null but force=true is configured, the result will be returned directly
                if (CollectionUtils.isNotEmpty(result) || tagRouterRuleCopy.isForce()) {
                    returnresult; }}else {
                // Check static tags
                result = filterInvoker(invokers, invoker -> tag.equals(invoker.getUrl().getParameter(TAG_KEY)));
            }
            If the provider does not have a tag configured, the default force-tag = false means that any provider can be accessed unless we display a disallow
            if (CollectionUtils.isNotEmpty(result) || isForceUseTag(invocation)) {
                return result;
            }
            else {
                // Return all providers without arbitrary labels
                List<Invoker<T>> tmp = filterInvoker(invokers, invoker -> addressNotMatches(invoker.getUrl(),
                        tagRouterRuleCopy.getAddresses()));
                // Find provider label is empty
                returnfilterInvoker(tmp, invoker -> StringUtils.isEmpty(invoker.getUrl().getParameter(TAG_KEY))); }}else {
            // Return all addresses
            List<String> addresses = tagRouterRuleCopy.getAddresses();
            if (CollectionUtils.isNotEmpty(addresses)) {
                result = filterInvoker(invokers, invoker -> addressNotMatches(invoker.getUrl(), addresses));
                // 1. all addresses are in dynamic tag group, return empty list.
                if (CollectionUtils.isEmpty(result)) {
                    returnresult; }}// Continue to use static label filtering
            return filterInvoker(result, invoker -> {
                String localTag = invoker.getUrl().getParameter(TAG_KEY);
                return StringUtils.isEmpty(localTag) || !tagRouterRuleCopy.getTagNames().contains(localTag);
            });
        }
    }
Copy the code

Note the main process in the above code, please check the code debugging by yourself.

6. Summary

In this section, we mainly learn the label routing of Dubbo routing rules and how to use them. At the same time, the implementation principle of label routing rules is analyzed: if the consumer passes the label, it matches the configured dynamic and static rules; if the consumer does not pass the label, it matches the locally configured static and dynamic configured labels of the service provider.

Tips: Dynamic rules take precedence over static rules. When two rules exist and conflict occurs, dynamic rules prevail.

The highlights of this lesson are as follows:

  1. Understand Dubbo tag routing

  2. You have learned how to use label routing

  3. Understand the implementation principle of label routing

  4. This section describes the application scenarios of label routing

The author

Personally engaged in the financial industry, I have worked in chongqing’s first-class technical team of Yiji Pay, Sijian Technology and an online car hailing platform, and now I am working in a bank responsible for the construction of unified payment system. I have a strong interest in the financial industry. It also practices big data, data storage, automated integration and deployment, distributed microservices, responsive programming, and artificial intelligence. At the same time, he is also keen on technology sharing, creating public accounts and blog sites to share knowledge system. Concern public number: young IT male get latest technical article push!

Blog: Youngitman.tech