Sentinel flow control
Sentinel Flow Control & Introduction to Service fuse Downgrading
Flow Control Introduction
Here I use the example of scenic spots to explain
A scenic spot receives 8K tourists a day, after 8K tourists can not buy tickets to enter the scenic spot.
For programming purposes, an interface has a maximum QPS (number of requests per second) of 100, after which we restrict access and give friendly hints.
An unlimited number of QPS can cause server downtime.
The service fuse is degraded
When the system is called, if a resource in the call link is unstable, requests will eventually pile up, resulting in cascading errors
And fusing the drop can solve this problem, the so-called fusing the drop is detected when calling a resource in the link appear unstable performance, such as the request and response time is long or abnormal ratio increases, the call of the resource constraints, make requests fail fast, avoid to affect other resources and cause cascading failure
Sentinel Flow control primer
Creating a Local Application
Overall process analysis
- Create a springBoot project
- Import the coordinates of Sentinel (used here as gradle)
- Create a Controller test interface, define and reference traffic limiting rules
Importing core dependencies
implementation("com.alibaba.cloud:spring-cloud-starter-alibaba-sentinel")
Copy the code
## Local Sentinel console
Download the Sentinel Console JAR package
Download address
### Start Sentinel console
JDK version 1.8 or later is required to start the Sentinel console.
Use the following command to start
Java -dserver. port= port number -jar sentinel-dashboard-1.8.0.jar
Access the console
The console can be accessed via the browser at http://localhost: port number. The default user name and password are both ‘sentinel’
Sentinel custom resource mode
- Resources are defined by the way exceptions are thrown
- Returns a boolean-defined resource
- Asynchronous invocation support
- Annotations define resources
- Default adaptation of mainstream frameworks
Resources are defined by the way exceptions are thrown
SphU of Sentinel species includes a try-catch style API. In this way, a BlockException is thrown when a resource is restricted.
At this time you can catch exceptions, after limiting the logical operation, in the entry case is the use of this way to achieve, the key code:
fun hello(a): String {
// Use traffic limiting rules
try {
SphU.entry("Hello")}catch (e: Exception) {
return "System busy, please try again later!!"
}
return "Hello Sentinel"
}
Copy the code
In particular, if a hotspot parameter is passed in entry, the corresponding parameter (exit(count, args)) must also be entered in exit. Otherwise, statistics errors may occur. You can’t use try-with-resources at this point. In addition, when using tracer.trace (ex) to collect exception information, the number of exceptions cannot be counted correctly because of the call order of catch in the try-with-resources syntax. Therefore, tracer.trace (ex) cannot be called in the catch block of try-with-resources to count exceptions.
Example of manual exit:
Entry entry = null;
// Ensure that finally is executed
try {
The resource name can be any string with business semantics. The number should not be too large (more than 1K). If the number exceeds several thousand, please pass it in as a parameter rather than as the resource name directly
// EntryType indicates the traffic type (inbound/outbound). System rules only apply to buried points of the IN type
entry = SphU.entry("Custom resource name");
// Protected business logic
// do something...
} catch (BlockException ex) {
// Resource access blocked, traffic restricted or degraded
// Perform the corresponding processing operation
} catch (Exception ex) {
// To configure degradation rules, record service exceptions in this way
Tracer.traceEntry(ex, entry);
} finally {
// Be sure to ensure exit. Be sure to pair each entry with exit
if(entry ! =null) { entry.exit(); }}Copy the code
Hotspot parameter burying point example:
Entry entry = null;
try {
// If you need to configure exceptions, only basic types are supported.
// EntryType indicates the traffic type. System rules take effect only for buried points of the IN type
// count in most cases is 1 to count a call.
entry = SphU.entry(resourceName, EntryType.IN, 1, paramA, paramB);
// Your logic here.
} catch (BlockException ex) {
// Handle request rejection.
} finally {
// Note: Exit must also be accompanied by the corresponding parameter, otherwise there may be statistical errors.
if(entry ! =null) {
entry.exit(1, paramA, paramB); }}Copy the code
Parameter descriptions of sphu.entry () :
Parameter names | type | explain | The default value |
---|---|---|---|
entryType | EntryType |
The traffic type of the resource invocation is the incoming traffic (EntryType.IN ) or outlet flow (EntryType.OUT ), note that the system rule applies only to IN |
EntryType.OUT |
count | int |
Token number of the resource invocation request | 1 |
args | Object[] |
Parameter passed in for hotspot parameter limiting | There is no |
Note: Sphu.entry (XXX) needs to be paired with the entry.exit() method to match the call, otherwise it will cause the call chain to record an exception, throwing an ErrorEntryFreeException. Common mistakes:
- Custom buried points are only called
SphU.entry()
, no callentry.exit()
- Out of order, for example:
entry1 -> entry2 -> exit1 -> exit2
, should beentry1 -> entry2 -> exit2 -> exit1
Returns a boolean-defined resource
The Sentinel SphO includes an IF-else style API. In this way, when a resource is curbed, it returns false, and the logical processing after curbed can be performed based on the return value.
-
Define resources in creating TestBooleanController in the project by returning booelan
@GetMapping("sentinel_boolean") fun hello(a): Boolean { // Configure the input-limiting interface. In this case, use the console to configure the traffic limiting rules return if (SphO.entry("Boolean")) { try {// Protected resources println("Hello Sentinel Boolean") true } finally { // Limit the current outlet SphO.exit() } } else { // Traffic limiting or degradation processing println("System busy, please try again later.") false}}Copy the code
** Configure flow control rules on the console **
Note that spho.entry (XXX) needs to be paired with the spho.exit () method, matching calls, and in the right place, otherwise it will cause the call chain to log an exception, throwing an ErrorEntryFreeException
### Asynchronous invocation support
Sentinel supports asynchronous call link statistics. In asynchronous calls, resources are defined through the sphu.asyncentry (XXX) method, and exit is usually called in an asynchronous callback function.
- The launch class enables asynchronous invocation
@EnableAsync
- Turn on asynchronous calls to methods
@Async
Sphu.asyncentry (XXX) does not affect the current (calling thread) Context, so the following two entries are flat on the call chain (at the same level) rather than nested:
// Call chain similar to:
// -parent
// ---asyncResource
// ---syncResource
asyncEntry = SphU.asyncEntry(asyncResource);
entry = SphU.entry(normalResource);
Copy the code
If you need to nest other resource calls (either Entry or asyncEntry) in an asynchronous callback, just use the context switch provided by Sentinel. Context transformation is performed using contextutil.runonContext (context, f) in the corresponding place, and the context at the corresponding resource invocation is switched to the generated asynchronous context to maintain the correct invocation link relationship. The following is an example:
public void handleResult(String result) {
Entry entry = null;
try {
entry = SphU.entry("handleResultForAsync");
// Handle your result here.
} catch (BlockException ex) {
// Blocked for the result handler.
} finally {
if(entry ! =null) { entry.exit(); }}}public void someAsync(a) {
try {
AsyncEntry entry = SphU.asyncEntry(resourceName);
// Asynchronous invocation.
doAsync(userId, result -> {
The AsyncEntry getAsyncContext method is used to get the async Context
ContextUtil.runOnContext(entry.getAsyncContext(), () -> {
try {
// Normal resource calls are nested here.
handleResult(result);
} finally{ entry.exit(); }}); }); }catch (BlockException ex) {
// Request blocked.
// Handle the exception (e.g. retry or fallback).}}Copy the code
The call chain looks like this:
-parent
---asyncInvocation
-----handleResultForAsync
Copy the code
For a more detailed example, see AsyncEntryDemo in Demo, which contains various nesting examples between normal and asynchronous resources.
Define resources with ### annotations
Sentinel supports the @SentinelResource annotation to define resources and configure blockHandler and fallback functions for post-limiting processing. The following dependencies need to be introduced when using the Sentinel Annotation AspectJ Extension
Implementation (" com. Alibaba. CSP: sentinel - the annotation - aspectj: 1.7.2 ")
@RestController
class TestAnnController {
/** * SentinelResource: define support * value: Set the name of the resource * blockHandler: set the function to degrade or limit traffic */
@SentinelResource(value = "sentinel_ann", blockHandler = "exceptionHandler")
@GetMapping("ann")
fun hello(a): String{
return "hello Sentinel"
}
/** * limit or degrade the function */
fun exceptionHandler(ex: BlockException) :String {
ex.printStackTrace()
return "System busy, please wait."}}Copy the code
@ SentinelResource annotations
Note: The annotation method does not support the private method.
@SentinelResource is used to define resources and provides optional exception handling and Fallback configuration items. The @sentinelResource annotation contains the following properties:
value
: Resource name, required (cannot be empty)entryType
: Entry type. This parameter is optionalEntryType.OUT
)blockHandler
/blockHandlerClass
:blockHandler
Corresponding processingBlockException
The optional function name of the The access range of the blockHandler function must bepublic
, the return type needs to match the original method, and the parameter type needs to match the original method and add an extra parameter at the end, of typeBlockException
. The blockHandler function needs to be in the same class as the original method by default. You can specify if you want to use a function from another classblockHandlerClass
Of the corresponding classClass
Object, note that the corresponding function must be static, otherwise it cannot be parsed.fallback
/fallbackClass
: The optional fallback function name that provides fallback handling logic when an exception is thrown. The fallback function is available for all types of exceptions (exceptexceptionsToIgnore
The type of exception that is excluded). Fallback function signature and position requirements:- The return value type must be the same as that of the original function;
- The method argument list needs to be the same as the original function, or it can be an extra one
Throwable
Type to receive the corresponding exception. - The fallback function needs to be in the same class as the original method by default. You can specify if you want to use a function from another class
fallbackClass
Of the corresponding classClass
Object, note that the corresponding function must be static, otherwise it cannot be parsed.
defaultFallback
(since 1.6.0) : Default fallback function name, optional, usually used for generic fallback logic (that is, can be used for many services or methods). The default fallback function can be used for all types of exceptions (exceptexceptionsToIgnore
The type of exception that is excluded). If both fallback and defaultFallback are configured, only fallback takes effect. DefaultFallback signature requirements:- The return value type must be the same as that of the original function;
- The method parameter list needs to be empty, or you can have an extra parameter
Throwable
Type to receive the corresponding exception. - DefaultFallback needs to be in the same class as the original method by default. You can specify if you want to use a function from another class
fallbackClass
Of the corresponding classClass
Object, note that the corresponding function must be static, otherwise it cannot be parsed.
exceptionsToIgnore
(since 1.6.0) : Specifies which exceptions are excluded, are not counted in the exception count, and are not included in fallback logic, but are thrown as is.
Starting with version 1.8.0, defaultFallback supports configuration at the class level.
Note: The fallback function before 1.6.0 only handles DegradeException, not service exception.
In particular, if blockHandler and Fallback are configured, only blockHandler processing logic will be entered when a BlockException is thrown due to traffic limiting demotion. If blockHandler, FallBack, and defaultFallback are not configured, BlockException thrown directly when they are current limiting the drop (if the method itself undefined throws BlockException packing layer would be JVM UndeclaredThrowableException).
Example:
public class TestService {
/ / function
@SentinelResource(value = "hello", blockHandler = "exceptionHandler", fallback = "helloFallback")
public String hello(long s) {
return String.format("Hello at %d", s);
}
// Fallback is a function with the same signature as the original function or with a Throwable argument.
public String helloFallback(long s) {
return String.format("Halooooo %d", s);
}
// Block exception handler (); // Block exception handler ();
public String exceptionHandler(long s, BlockException ex) {
// Do some log here.
ex.printStackTrace();
return "Oops, error occurred at " + s;
}
// blockHandlerClass is configured separately.
// The corresponding 'handleException' function needs to be in the 'ExceptionUtil' class and must be public static.
@SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})
public void test(a) {
System.out.println("Test"); }}Copy the code
Starting from version 1.4.0, annotated resources support automatic statistics of service exceptions. You do not need to manually call tracer.trace (ex) to record service exceptions. Sentinel versions prior to 1.4.0 required a call to tracer.trace (ex) to log service exceptions.
configuration
Spring Cloud Alibaba
If you are Sentinel connected through Spring Cloud Alibaba, you can use the @SentinelResource annotation without additional configuration.
Spring AOP
If your application uses Spring AOP (either Spring Boot or traditional Spring application), you need to register SentinelResourceAspect as a Spring Bean by configuration:
@Configuration
public class SentinelAspectConfiguration {
@Bean
public SentinelResourceAspect sentinelResourceAspect(a) {
return newSentinelResourceAspect(); }}Copy the code
We provide examples of Spring AOP, see Sentinel-Demo-annotation-spring-AOP.
AspectJ
If your application uses AspectJ directly, you need to introduce the corresponding Aspect in the AOP.xml file:
<aspects>
<aspect name="com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect"/>
</aspects>
Copy the code
### Default adaptation of mainstream frameworks
Document address: github.com/alibaba/Sen…
Types of rules
All Sentinel rules can be dynamically queried and modified in memory, and the changes take effect immediately. Sentinel also provides apis that allow you to customize your own rules policies.
Sentinel supports the following rules: flow control rules, fuse degrade rules, system protection rules, source access control rules, and hotspot parameter rules.
Flow Rules
Definition of traffic rules
Important attributes:
Field | instructions | The default value |
---|---|---|
resource | The resource name is the object of the traffic limiting rule | |
count | Current limiting threshold | |
grade | Flow limiting threshold type, QPS mode (1) or Number of concurrent threads mode (0) | QPS model |
limitApp | The source of the call for flow control | default , indicates that the call source is not distinguished |
strategy | Call relationship traffic limiting policies: direct, link, and association | According to the resource itself (direct) |
controlBehavior | Flow control effect (direct reject /WarmUp/ Constant speed + queuing), does not support traffic limiting by call relationship | Direct refused to |
clusterMode | Whether to restrict traffic in a cluster | no |
A resource can have multiple traffic limiting rules at the same time. The rules are checked one by one.
Define flow control rules through code
When we understand the rules of the above definition, we can by calling FlowRuleManager. LoadRules () method to use hard-coded way defined flow control rules, such as:
private void initFlowQpsRule(a) {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule(resourceName);
// set limit qps to 20
rule.setCount(20);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
Copy the code