1. Introduction

At present, the most used in the enterprise is HTTP interface and dubbo interface traffic limiting, this article will introduce to you a complete HTTP interface traffic limiting and dubbo interface traffic limiting principle, as well as their source code for a detailed analysis, How Sentinel is a perfect fit for this efficient and non-intrusive code.


2. sentinel-adapter

As you can see here, Sentinel has given us a lot of adaptors in good conscience, so what do they do?

2.1 Functions of the adapter

If you have read the previous article, you will know that the key entry for calling sentinel to implement traffic limiting is “sphu.entry ()”. The core of traffic limiting is to call the core method of SphU to determine whether the request can pass the link, as shown in the following figure:

We sometimes use annotations to specify limiting the flow of an interface, as in the following form

@sentinelResource (value = “resource name “, blockHandler =” Stream limiting callback method name “)

However, these methods can be intrusive, so Sentinel provides an adapter that allows users to limit HTTP or Dubbo traffic without being aware of it, simply by importing the corresponding JAR package.


3. Traffic limiting on the HTTP interface

3.1 Process of USING HTTP traffic Limiting

  1. Using HTTP limiting first, the project needed to introduce the Sentinel-Web-servlet JAR package for Sentinel. At the same time, since we were using dashboard during the demo, I also needed to introduce the Sentinel-transport-simple-HTTP JAR package, depending on the following
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-web-servlet</artifactId>
    <version>${sentinel.version}</version>
</dependency>

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-apache-dubbo-adapter</artifactId>
    <version>${sentinel.version}</version>
</dependency>

Copy the code

Of course, if it is a Spring Boot project, spring-Cloud-starter-Alibaba-Sentinel can be directly introduced. Version optional

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> < version > 0.2.0. RELEASE < / version > < / dependency >Copy the code
  1. Note that the resource name must be the path name of the HTTP interface (the reason will be explained later in the source code analysis). Click Add and the rule will take effect. Is it quite easy? (Dashboard access has been described in the previous article, you can check it out for yourself)

3.2 HTTP Traffic limiting and Logical registration Degradation

The next step is to write the flow-limiting callback logic. The adapter provides us with a default set of flow-limiting callbacks, as shown in the figure below.

We can also write our own logic, which we recommend to write in the main method of Spring Boot (it doesn’t matter where we write it, this is a static callback method, as long as it is loaded after boot).

WebCallbackManager. SetUrlBlockHandler ((request, response, the ex) - > {System. Out. Println (" current limit processing business logic "); });Copy the code

3.3 Source code Analysis of Http Traffic Limiting

3.3.1 Project structure

3.3.2 Core source code analysis

In fact, through the above project structure, we can suddenly find that the main core idea of the HTTP adapter is to carry out a filter operation to intercept requests, filtering.

For the filter, here but more introduction, interested can consult information. What it does is that all HTTP requests go through the filter, so we can do traffic limiting on the filter side.

The filter will filter the HTTP request, and then read the suffix of the path or method from the request, pass it as the resource name “sphu.entry ()”, and monitor the traffic of the resource, etc. Therefore, this is why you need to enter the correct HTTP interface path name before creating the rule. If the resource name does not match, it will cause the problem of loss limiting effect because the corresponding rules cannot be read. (The source code of Sentinel core stream limiting is omitted here and will be explained in full in the future). The key source code is as follows: HTTP request interception, and obtain the path, set the entry of the call chain. Enable the flow limiting judgment.


4. Traffic limiting on the Dubbo interface

4.1 DuBBO Traffic Limiting Process

  1. In the same way, before using Dubbo limiting, the project needs to import the JAR package of Sentinel’s Sentinel-Apache-Dubbo-Adapter (the higher version of the Dubbo adapter, the lower version references the other one).
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-transport-simple-http</artifactId>
    <version>${sentinel.version}</version>
</dependency>

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-apache-dubbo-adapter</artifactId>
    <version>${sentinel.version}</version>
</dependency>

Copy the code

Similarly, if it is a Spring Boot project, spring-Cloud-starter-Alibaba-Sentinel can be directly introduced. Version optional

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> < version > 0.2.0. RELEASE < / version > < / dependency >Copy the code
  1. The resource name must be the fully qualified name of the interface if traffic restriction is applied to the service interface of a dubbo, or the fully qualified name of the interface if traffic restriction is applied to a method of the interface: method signature, for example: Buguniao. UserService: getUserById (Java. Lang. Long) after click on add, the rules will take effect, don’t put the screenshots here, in addition to the resource name need to pay attention to, the rest and HTTP basic same, relaxed after the explosion.

4.2 Dubbo Traffic limiting and logical registration degradation

The next step is to write the flow-limiting callback logic. The Dubbo adapter does not have a default flow-limiting callback, as shown below. So we need to write our own logic, which also needs to be loaded at boot time.

  • Sentinel can only register global callback logic, so it is necessary to distinguish between limiting logic and degrading logic in the callback method
  • Because Sentinel Dubbo current limiting fuse is implemented based on Dubbo filter, an RpcResult needs to be returned in the final return result. Please refer to the following template to modify the logic part of current limiting and degrade the logic part

The code is as follows:

DubboFallbackRegistry.setConsumerFallback(new DubboFallback() { @Override public Result handle(Invoker<? > invoker,Invocation invocation,BlockException ex) { RpcResult rs = new RpcResult(); String r = null; Try {if(ex instanceof FlowException){r=" FlowException "; Else if(ex instanceof DegradeException){r=" downgrade logic "; }}catch (Exception e){r=" other error "; rs.setException(e); // Business exception injection to throw an exception on the consumer side} rs.setValue(r); // Set the service return value return rs; }});Copy the code

4.3 Dubbo stream limiting source code analysis

4.3.1 Project structure

4.3.2 Core source code analysis

The implementation of the dubbo interface is based on the Dubbo filter. How to configure the Dubbo filter is not described here. We will only talk about the traffic limiting aspect.

First, the adapter performs a layer of interception on the Dubbo consumer side, essentially taking the consumer’s application name from the URL and adding it to the context of the Dubbo so that the provider can perform a stream limiting on the source application. The code is as follows:

@Activate(group = CONSUMER) public class DubboAppContextFilter implements Filter { @Override public Result invoke(Invoker<? > invoker, Invocation invocation) throws RpcException { String application = invoker.getUrl().getParameter(CommonConstants.APPLICATION_KEY); if (application ! = null) { RpcContext.getContext().setAttachment(DubboUtils.SENTINEL_DUBBO_APPLICATION_KEY, application); } return invoker.invoke(invocation); }Copy the code

Consummer side has a layer of EntryType set to OUT limit, here is omitted, will be introduced in the core source code analysis, part of the source code is as follows:

try {
    interfaceEntry = SphU.entry(interfaceResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT);
    methodEntry = SphU.entry(methodResourceName, ResourceTypeConstants.COMMON_RPC, EntryType.OUT,
        invocation.getArguments());
    Result result = invoker.invoke(invocation);
    if (result.hasException()) {
        Tracer.traceEntry(result.getException(), interfaceEntry);
        Tracer.traceEntry(result.getException(), methodEntry);
    }
    return result;
} catch{
/ /...
}
Copy the code

The main function of the filter on the provider side is to determine whether traffic limiting is required when EntryType is set to IN. The filter on the provider side is used to determine whether traffic limiting is required. The consumer application name of Dubbo mentioned above is used to limit traffic for applications from a specified source. The dashboard interface is as follows:

The source code is as follows:

@Activate(group = "provider")
public class SentinelDubboProviderFilter extends AbstractDubboFilter implements Filter {

    public SentinelDubboProviderFilter(a) {
        RecordLog.info("Sentinel Dubbo provider filter initialized");
    }

    @Override
    public Result invoke(Invoker
        invoker, Invocation invocation) throws RpcException {
        // Get origin caller.
        // Get the name of the source application from the context
        String application = DubboUtils.getApplication(invocation, "");

        Entry interfaceEntry = null;
        Entry methodEntry = null;
        try {
            // Get the resource name (interface name)
            String resourceName = getResourceName(invoker, invocation);
            // Gets the specified method name of the interface
            String interfaceName = invoker.getInterface().getName();
            // A call chain entry with the resource name and the source application name
            ContextUtil.enter(resourceName, application);
            // Traffic limiting on the interface is enabled
            interfaceEntry = SphU.entry(interfaceName, EntryType.IN);
            // Method current limiting is enabled
            methodEntry = SphU.entry(resourceName, EntryType.IN, 1, invocation.getArguments());
            // Return RpcResult
            Result result = invoker.invoke(invocation);
            if (result.hasException()) {
                Tracer.trace(result.getException());
            }
            return result;
        } catch (BlockException e) {
            return DubboFallbackRegistry.getProviderFallback().handle(invoker, invocation, e);
        } catch (RpcException e) {
            Tracer.trace(e);
            throw e;
        } finally {
            if(methodEntry ! =null) {
                methodEntry.exit(1, invocation.getArguments());
            }
            if(interfaceEntry ! =null) { interfaceEntry.exit(); } ContextUtil.exit(); }}}Copy the code

Note: In most business scenarios, the service provider needs to limit the flow, so the consumer will not access Sentinel, but this will be a small bug. If the Dubbo consumer does not access Sentinel’s Dubbo adapter, it cannot intercept the dubboName and throw it into the context. Therefore, No matter how Dashboard is set, the source will fail. The solution is to pass through dubboName, using the rpcContext.getContext ().setAttachment() method to add a parameter to the corequest header at the consumer side.


5. To summarize

The HTTP and Dubbo interface traffic limiting, in other words, intercepts the request, starts and determines whether to proceed with the traffic limiting, so it should not be too difficult to understand. A future article will explain how Sentinel can monitor and determine traffic limiting.