15. Spring cloud Alibaba sentinel realizes fusing and current limiting
15.1 general
15.1.1 official website
english: https://github.com/alibaba/Sentinel
chinese: https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
15.1.2 introduction
In one sentence, we explained the Hystrix before
15.1.3 where to go
https://github.com/alibaba/Sentinel/releases
15.1.4 what can I do
15.1.5 how to play
Official website: https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_sentinel
Various problems in service use:
- Service avalanche
- service degradation
- Service fuse
- Service current limiting
15.2 installation of Sentinel console
15.2.1 sentinel assembly consists of two parts
15.2.2 installation steps
1. Download
https://github.com/alibaba/Sentinel/releases
2. Run command
Premise:
-
java8 environment OK
-
Port 8080 cannot be occupied. There is Tomcat inside sentinel
Start:
java -jar sentinel-dashboard-1.7.0.jar
If the port is occupied, you can: Java - dserver port=8888 -jar sentinel-dashboard-1.7.0. jar
3. Access sentinel management interface
visit: http://localhost: The port number, login account and password are sentinel
15.3 initialization demonstration project
15.3.1 preconditions
Start Nacos and access http://192.168.174.128:8848/nacos/#/login Visit successful
15.3.2 establishment of sentinel8041
- Build Module - cloudalibaba-sentinel-service8401
- POM
<dependencies> <!--SpringCloud ailibaba nacos --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--SpringCloud ailibaba sentinel-datasource-nacos For subsequent persistence--> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency> <!--SpringCloud ailibaba sentinel --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <!--openfeign--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!-- SpringBoot integration Web assembly+actuator --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--Daily general jar Package configuration--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>4.6.3</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
- YML
server: port: 8401 spring: application: name: cloudalibaba-sentinel-service cloud: nacos: discovery: server-addr: 192.168.174.128:8848 #Nacos service registry address sentinel: transport: dashboard: localhost:8080 #Configure Sentinel dashboard address port: 8719 #The default port is 8719. If it is occupied, it will automatically start + 1 scanning from 8719 until the unoccupied port is found management: endpoints: web: exposure: include: '*'
- Main start
@EnableDiscoveryClient @SpringBootApplication public class MainApp8401 { public static void main(String[] args) { SpringApplication.run(MainApp8401.class, args); } }
- Business class FlowLimitController
@RestController public class FlowLimitController { @GetMapping("/testA") public String testA() { return "------testA"; } @GetMapping("/testB") public String testB() { return "------testB"; } }
15.3.3 test results
- Start Sentinel8888
- Start microservice 8401
- Start 8401 microservice and view sentienl console
Empty, nothing
The reason is that Sentinel uses lazy loading
Perform one visit: http://localhost:8401/testA And http://localhost:8401/testB
Conclusion: sentinel 8080 is monitoring microservice 8401
15.4 flow control rules
15.4.1 basic introduction
Further explanation
Difference between QPS and number of threads
QPS: resist the enemy outside the country, that is, there can only be QPS requests at a time
Number of threads: after entering, close the door and beat the dog. Only a few threads can be processed at a time, and the redundant tasks will not be processed
15.4.2 flow control mode
1. Direct (default)
Direct - > quick failure
- Configuration and Description:
It means that one query within one second is OK. If it exceeds one, it will fail directly - quickly and report a default error
- Test:
Quick click access http://localhost:8401/testA
Result: Blocked by Sentinel (flow limiting)
- reflection
Directly call the default error message, which is technically OK. but, should we have our own follow-up processing? Similar to a fallback method?
2. Association
- What is it?
When the associated resource reaches the threshold, it limits itself
When the resource B associated with A reaches the threshold, it limits the flow of A itself
B gets into trouble and A hangs up. For example, the payment interface reaches the threshold limit and the interface for placing orders
- Configuration A
When the qps threshold of the associated resource / testB exceeds 1, the Rest access address of the current / testA is limited. When the associated resource reaches the threshold, the configured resource name is limited
- postman simulates concurrent intensive access to testB
Normal access to testB succeeded
Create a new multithreaded collection group in postman
Add access address to new thread group
RUN
- Click to visit http://localhost:8401/testA , test
Results: due to the high concurrency of a large number of threads accessing B, it was found that testA hung
3. Link
Multiple requests call the same microservice
15.4.3 flow control effect
1. Direct - > quick failure (default flow control processing)
Direct failure, throw an exception: Blocked by Sentinel (flow limiting)
Source code: com alibaba. csp. sentinel. slots. block. flow. controller. DefaultController
2. Preheating
-
Formula: divide the threshold value by coldfactor (the default value is 3), and the threshold value will not be reached until it is preheated for a long time
-
Official website: https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6
The default coldFactor is 3, that is, the requested QPS starts from threshold / 3 and gradually rises to the set QPS threshold after preheating.
Current limiting cold start: https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81 —%E5%86%B7%E5%90%AF%E5%8A%A8
- Source code
com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController
- WarmUp configuration
The default coldfactor (threshold value of system initialization) is 3, that is, how long it takes to warm up the QPS from (threshold / 3) to the set QPS threshold.
In case, the threshold value is 10 and the preheating time is set to 5 seconds.
The threshold value of system initialization is 10 / 3, which is about 3, that is, the threshold value is 3 at the beginning; Then it took 5 seconds for the threshold to rise slowly and return to 10
- test
Visit: multiple clicks http://localhost:8401/testB , not at the beginning, but gradually OK in the follow-up
- Application scenario
For example, when the second kill system is turned on, there will be a lot of flow, which is likely to kill the system. The preheating method is to slowly put the flow in to protect the system and slowly increase the threshold to the set threshold.
3. Wait in line
- Queue at a uniform speed to allow requests to pass at a uniform speed. The threshold type must be set to QPS, otherwise it is invalid.
Setting Meaning: / testA requests once per second. If it exceeds, it will queue up and wait. The waiting timeout is 20000 milliseconds
- Official website:
https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6
- Source code
com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController
- test
In the background print log, you can see that the 1s request is executed once
15.5 degradation rules
15.5.1 official website
https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7
15.5.2 basic introduction
RT (average response time in seconds)
The average response time exceeds the threshold and the request passed within the time window > = 5. The degradation is triggered after the two conditions are met at the same time
Close the circuit breaker after the window period
RT maximum 4900 (larger ones can only take effect through - DCSP. Sentinel. Statistical. Max.rt = XXXX)
Abnormal ratio column (in seconds)
When QPS > = 5 and the abnormal proportion (second level statistics) exceeds the threshold, the degradation is triggered; When the time window is over, turn off the downgrade
Different constant (minute level)
When the abnormal constant (minute Statistics) exceeds the threshold, the degradation is triggered; After the demotion window is closed
- Further explanation
Sentinel degradation will limit the call of a resource when it is in an unstable state in the call link (for example, the call timeout or the abnormal proportion increases), so as to make the request fail quickly and avoid affecting other resources and causing cascading errors.
When a resource is downgraded, calls to the resource will automatically fuse within the next downgrade time window (the default behavior is to throw DegradeException).
- Sentinel's circuit breaker is not half open
In the half open state, the system will automatically detect whether there is any abnormality. If there is no abnormality, close the circuit breaker and resume use. If there is any abnormality, continue to open the circuit breaker and it is unavailable. For details, please refer to Hystrix
15.5.3 actual combat of degradation strategy
1.RT
- What is it?
- test
Controller code addition
@GetMapping("/testD") public String testD() { //Pause the thread for a few seconds try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } log.info("testD test RT"); return "------testD"; }
to configure
jmeter pressure measurement
Access testD
Conclusion:
According to the above configuration, always call 10 threads (more than 5) to call testD in one second. We hope to finish this task in 200 milliseconds,
If the process is not completed for more than 200 milliseconds, the circuit breaker opens (fuse trips), the microservice is unavailable and the fuse trips and de energizes within the next 1-second time window Subsequently, I stopped jmeter and there was no such a large number of visits. The circuit breaker was closed (the fuse was restored) and the microservice was restored to OK
2. Abnormal proportion
- What is it?
- test
Code modification:
@GetMapping("/testD") public String testD() { log.info("testD test RT"); int age = 10/0; return "------testD"; }
to configure
jmeter
Conclusion:
According to the above configuration, if you access it alone, you must report an error once (int age = 10/0) and adjust it once;
After jmeter is enabled, the request is sent directly with high concurrency, and the multiple calls meet our configuration conditions. When the circuit breaker is opened (the fuse trips), the microservice is unavailable, and the error is no longer reported, but the service is degraded.
3. Different constants
- What is it?
The time window must be greater than or equal to 60 seconds.
- test
code:
@GetMapping("/testE") public String testE() { log.info("testE Abnormal test proportion"); int age = 10/0; return "------testE Test exception ratio"; }
to configure:
Conclusion:
visit: http://localhost:8401/testE , the first access will definitely report an error because the divisor cannot be zero,
We see the error window, but after five times of error reporting, we enter the fuse and degrade.
15.6 current limiting
15.6.1 basic introduction
What are hot spots
Hot spots are frequently accessed data. Many times, we want to count or limit the TopN data with the highest access frequency in a hot spot data, and limit its access or other operations
15.6.2 official website
https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81
15.6.3 connecting the preceding and the following review start
There are two ways to find out the details: system default and customer customization
-
In the previous case s, the default prompt of sentinel system is Blocked by Sentinel (flow limiting)
-
Can we decide for ourselves? Similar to hystrix, if there is a problem with a certain method, find the corresponding downgrading method?
Conclusion: from HystrixCommand to @ SentinelResource
15.6.4 modifying Controller
@GetMapping("/testHotKey") @SentinelResource(value = "testHotKey",blockHandler = "dealHandler_testHotKey") public String testHotKey(@RequestParam(value = "p1",required = false) String p1, @RequestParam(value = "p2",required = false) String p2){ return "------testHotKey"; } public String dealHandler_testHotKey(String p1,String p2,BlockException exception) { return "-----dealHandler_testHotKey"; }
Sentinel system default prompt: Blocked by Sentinel (flow limiting)
Bottom source code: com alibaba. csp. sentinel. slots. block. BlockException
15.6.5 configuration
Current limiting mode only supports QPS mode, which is fixed and dead. (this is the hot spot)
@The method parameter index of SentinelResource annotation. 0 represents the first parameter, 1 represents the second parameter, and so on
The single machine threshold and the duration of the statistical window indicate that the current is limited when the time in this window exceeds the threshold.
The picture above is that if the first parameter has a value, the QPS of one second is 1, exceeding the current limit, and calling dealHandler_ after the current limit. Testhotkey supports methods.
Compare before and after using blockHandler:
- @SentinelResource(value = "testHotKey"): the exception hits the foreground user interface, which is unfriendly
- @SentinelResource(value = "testHotKey", blockHandler = "dealHandler_testHotKey"), the first parameter in the method testHotKey will be degraded as soon as the QPS exceeds 1 time per second And it uses our own definition, which is more flexible
15.6.6 testing
The following visits are non-stop
-
visit http://localhost:8401/testHotKey?p1=abc ===> error ×
-
visit http://localhost:8401/testHotKey?p1=abc&p2=33 ===> error ×
-
visit http://localhost:8401/testHotKey?p2=abc ===> right √
Conclusion: the first parameter p1 is current limited immediately after one click of QPS for more than 1 second
15.6.7 parameter exceptions
1. The above case demonstrates the first parameter p1. When the QPS is clicked once for more than 1 second, the current is limited immediately
2. Special cases
Generally, the current will be limited immediately after reaching the threshold value of 1 second
We expect that when p1 parameter is a special value, its current limit value is not the same as usual
If the value of p1 is equal to 5, its threshold can reach 200
3. Configuration
Click the Add button
4. Test
visit: http://localhost:8401/testHotKey?p1=5 , the system does not report an error no matter whether the mode exceeds 1s once
visit: http://localhost:8401/testHotKey?p1=3 , when the mode exceeds 1s once, an error is reported
Reason: when p1 equals 5, the threshold becomes 200 When p1 is not equal to 5, the threshold is the usual 1
5. Preconditions
Note that the hotspot parameter must be a basic type or String
15.6.8 others - add exceptions (described in detail later)
@SentinelResource
It deals with the violation of Sentinel console configuration, including the bottom handling configured by blockHandler method;
RuntimeException
int age = 10/0. This is the runtime exception RunTimeException reported by java runtime, regardless of @ SentinelResource
summary
@SentinelResource supervisor has an error in configuration and operation. This is an exception
15.7 system rules
Because global configuration is effective for all requests of the system, there are few scenarios used in this chapter
15.7.1 what is it
https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81
Sentinel system's adaptive flow restriction controls the application inlet flow from the overall dimension. Combined with the monitoring indicators of application Load, CPU utilization, overall average RT, inlet QPS and the number of concurrent threads, the system inlet flow and system Load are balanced through adaptive flow control strategy, Let the system run at the maximum throughput as far as possible while ensuring the overall stability of the system.
15.7.2 description of various configuration parameters
15.7.3 configure global QPS
... slightly
15.8 @SentinelResource
15.8.1 current limiting by resource name + subsequent processing
1. Modify Module - cloudalibaba sentinel service8401
- POM
<dependency><!-- Introduce self defined api General package, you can use Payment payment Entity --> <groupId>com.rg.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency>
- Business class RateLimitController
@RestController public class RateLimitController { @GetMapping("/byResource") @SentinelResource(value = "byResource",blockHandler = "handleException") public CommonResult byResource(){ return new CommonResult(200, "Current limit test by resource name OK", new Payment(2020L, "serial001")); } public CommonResult handleException(BlockException exception){ return new CommonResult(444, exception.getClass().getCanonicalName() + "\t Service Unavailable"); }
2. Configure flow control rules
- Configuration steps
- Graphic configuration and code relationship
- It means that if the number of queries is greater than 1 in one second, we will run to our customized method to limit the current
3. Test
- Click once in 1 second, OK
- Beyond the above, click madly and return the self-defined current limit processing information, and the current limit occurs
4. Additional issues
At this time, close the query service 8401 and see that the sentinel console shows that the flow control rules disappear = = = > indicating that the configuration on sentinel is temporary
15.8.2 current limiting according to Url address + subsequent processing
If you limit the flow by accessing the URL, the default flow limiting processing information of Sentinel will be returned
- Business class RateLimitController:
@GetMapping("/rateLimit/byUrl") @SentinelResource(value = "byUrl") public CommonResult byUrl() { return new CommonResult(200,"Press url Current limiting test OK",new Payment(2020L,"serial002")); }
- to configure:
- test
Crazy Click http://localhost:8401/rateLimit/byUrl
The current limiting processing result of Sentinel will be returned
15.8.3 problems faced by the above scheme
1. The system is default and does not reflect our own business requirements.
2 according to the existing conditions, our customized processing method is coupled with the business code, which is not intuitive.
3 each business method adds a bottom-up, which aggravates the code inflation.
4. The overall unified processing method is not reflected.
15.8.4 customer defined current limiting processing logic
- Create a CustomerBlockHandler class to customize the flow limiting processing logic
public class CustomerBlockHandler { public static CommonResult handleException(BlockException exception){ return new CommonResult(2020,"Customized current limiting processing information......CustomerBlockHandler"); } }
- Modify RateLimitController
/** * Customize the general current limiting processing logic, blockHandlerClass = CustomerBlockHandler.class blockHandler = handleException2 The above configuration: find the handleException2 method in the CustomerBlockHandler class for bottom handling */ /** * Custom general current limiting processing logic */ @GetMapping("/rateLimit/customerBlockHandler") @SentinelResource(value = "customerBlockHandler", blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handleException2") public CommonResult customerBlockHandler() { return new CommonResult(200,"Customized current limiting processing logic by customer"); }
- Sentinel console configuration:
- Test:
Crazy access: http://localhost:8401/rateLimit/customerBlockHandler , we customized it after the test
- Further explanation
15.8.5 more annotation attribute descriptions
1.Sentinel mainly has three core APIs
- SphU define resources
- Tracer definition statistics
- ContextUtil defines the context
2. Customize Resource
All code should be processed in a try catch finally manner, o(╥﹏╥) o
15.9 service fuse function
15.9.1 sentinel integration + Ribbon+fallback
1. Start nacos and sentinel
2. Build provider 9003 / 9004
- Build Module - cloudalibaba provider payment9003 / 9004
- POM
<dependencies> <!--SpringCloud ailibaba nacos --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency><!-- Introduce self defined api General package, you can use Payment payment Entity --> <groupId>com.rg.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <!-- SpringBoot integration Web assembly --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--Daily general jar Package configuration--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
- YML
server: port: 9003 spring: application: name: nacos-payment-provider cloud: nacos: discovery: server-addr: 192.168.174.128:8848 #Configure Nacos address management: endpoints: web: exposure: include: '*'
- Main start
@SpringBootApplication @EnableDiscoveryClient public class PaymentMain9003 { public static void main(String[] args) { SpringApplication.run(PaymentMain9003.class, args); } }
- Business class
@RestController public class PaymentController { @Value("${server.port}") private String serverPort; public static HashMap<Long,Payment> hashMap = new HashMap<>(); static { hashMap.put(1L,new Payment(1L,"28a8c1e3bc2742d8848569891fb42181")); hashMap.put(2L,new Payment(2L,"bba8c1e3bc2742d8848569891ac32182")); hashMap.put(3L,new Payment(3L,"6ua8c1e3bc2742d8848569891xt92183")); } @GetMapping(value = "/paymentSQL/{id}") public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) { Payment payment = hashMap.get(id); CommonResult<Payment> result = new CommonResult(200,"from mysql,serverPort: "+serverPort,payment); return result; } }
- Test address: http://localhost:9003/paymentSQL/1 , can be accessed normally
3. Consumers 84
- Build Module - cloudalibaba-consumer-nacos-order84
- POM
<dependencies> <!--SpringCloud ailibaba nacos --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--SpringCloud ailibaba sentinel --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <!-- Introduce self defined api General package, you can use Payment payment Entity --> <dependency> <groupId>com.rg.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <!-- SpringBoot integration Web assembly --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--Daily general jar Package configuration--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
- YML
server: port: 84 spring: application: name: nacos-order-consumer cloud: nacos: discovery: server-addr: 192.168.174.128:8848 sentinel: transport: #Configure Sentinel dashboard address dashboard: localhost:8888 #The default port is 8719. If it is occupied, it will automatically start + 1 scanning from 8719 until the unoccupied port is found port: 8719 ##The name of the micro service that the consumer will visit (the micro service provider that has successfully registered into nacos) service-url: nacos-user-service: http://nacos-payment-provider
- Main start
@EnableDiscoveryClient @SpringBootApplication public class OrderNacosMain84 { public static void main(String[] args) { SpringApplication.run(OrderNacosMain84.class, args); } }
- Business class
ApplicationContextConfig
@Configuration public class ApplicationContextConfig { @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } }
4.CircleBreakerController + test
Purpose: to verify that the fallback tube runs abnormally and the blockHandler tube configuration is illegal
- Write basic code
@RestController @Slf4j public class CircleBreakerController { public static final String SERVICE_URL = "http://nacos-payment-provider"; @Resource private RestTemplate restTemplate; @RequestMapping("/consumer/fallback/{id}") @SentinelResource(value = "fallback") public CommonResult <Payment> fallback(@PathVariable Long id){ CommonResult result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id); if(id==4){ System.out.println("44444444444"); throw new IllegalArgumentException("IllegalArgumentException,Illegal parameter exception..."); }else if(result.getData()==null){ System.out.println("111111111111111"); throw new NullPointerException("NullPointerException,Should ID No corresponding record,Null pointer exception..."); } return result; } }
- visit: http://localhost:84/consumer/fallback/1 Test, test successful! visit http://localhost:84/consumer/fallback/4 Jump to the error page But the error page is not user-friendly
- Configure fallback only
code:
@RequestMapping("/consumer/fallback/{id}") @SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback is responsible for business exceptions public CommonResult <Payment> fallback(@PathVariable Long id){ CommonResult result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id); if(id==4){ throw new IllegalArgumentException("IllegalArgumentException,Illegal parameter exception..."); }else if(result.getData()==null){ throw new NullPointerException("NullPointerException,Should ID No corresponding record,Null pointer exception..."); } return result; } public CommonResult handlerFallback(@PathVariable Long id,Throwable e){ Payment payment = new Payment(id, "null"); return new CommonResult(444, "Fundus abnormality handlerFallback,exception content:" + e.getMessage(), payment); }
result:
Illustration:
- Configure blockHandler only
code:
@RequestMapping("/consumer/fallback/{id}") //@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback is responsible for business exceptions @SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler is responsible for the degraded current limit configured in sentinel public CommonResult <Payment> fallback(@PathVariable Long id){ CommonResult result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id); if(id==4){ throw new IllegalArgumentException("IllegalArgumentException,Illegal parameter exception..."); }else if(result.getData()==null){ throw new NullPointerException("NullPointerException,Should ID No corresponding record,Null pointer exception..."); } return result; } public CommonResult handlerFallback(@PathVariable Long id,Throwable e){ Payment payment = new Payment(id, "null"); return new CommonResult(444, "Fundus abnormality handlerFallback,exception content:" + e.getMessage(), payment); } public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) { Payment payment = new Payment(id,"null"); return new CommonResult<>(445,"blockHandler-sentinel Current limiting,No such flow: blockException "+blockException.getMessage(),payment); }
In this example, sentinel needs to be configured:
After the abnormality exceeds 2 times, the circuit breaker is opened, the power is cut off and the system is protected
result:
Illustration:
- Both fallback and blockHandler are configured
code:
@RequestMapping("/consumer/fallback/{id}") //@SentinelResource(value = "fallback") //@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback is responsible for business exceptions //@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler is responsible for the degraded current limit configured in sentinel @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler") public CommonResult <Payment> fallback(@PathVariable Long id){ CommonResult result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id); if(id==4){ System.out.println("44444444444"); throw new IllegalArgumentException("IllegalArgumentException,Illegal parameter exception..."); }else if(result.getData()==null){ System.out.println("111111111111111"); throw new NullPointerException("NullPointerException,Should ID No corresponding record,Null pointer exception..."); } return result; } public CommonResult handlerFallback(@PathVariable Long id,Throwable e){ Payment payment = new Payment(id, "null"); return new CommonResult(444, "Fundus abnormality handlerFallback,exception content:" + e.getMessage(), payment); } public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) { Payment payment = new Payment(id,"null"); return new CommonResult<>(445,"blockHandler-sentinel Current limiting,No such flow: blockException "+blockException.getMessage(),payment); }
In this example, sentinel needs to be configured:
result:
If both blockHandler and fallback are configured, it will only enter the blockHandler processing logic when being degraded by current limiting and throwing BlockException. If the current limit rule is not exceeded, the fallback logic is followed
Illustration:
- Ignore attribute - exceptionsToIgnore
code:
@RequestMapping("/consumer/fallback/{id}") //@SentinelResource(value = "fallback") //@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback is responsible for business exceptions //@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler is responsible for the degraded current limit configured in sentinel @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler",exceptionsToIgnore = {IllegalArgumentException.class}) public CommonResult <Payment> fallback(@PathVariable Long id){ CommonResult result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id); if(id==4){ System.out.println("44444444444"); throw new IllegalArgumentException("IllegalArgumentException,Illegal parameter exception..."); }else if(result.getData()==null){ System.out.println("111111111111111"); throw new NullPointerException("NullPointerException,Should ID No corresponding record,Null pointer exception..."); } return result; } public CommonResult handlerFallback(@PathVariable Long id,Throwable e){ Payment payment = new Payment(id, "null"); return new CommonResult(444, "Fundus abnormality handlerFallback,exception content:" + e.getMessage(), payment); } public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) { Payment payment = new Payment(id,"null"); return new CommonResult<>(445,"blockHandler-sentinel Current limiting,No such flow: blockException "+blockException.getMessage(),payment); }
In this example, sentinel is not configured
Illustration:
Result: the program exception hit the front desk and was not friendly to users
15.9.2 sentinel integration + Feign+fallback
1. Modify module 84: 84 consumers call provider 9003, and feign components are generally on the consumer side
2. Modify code
- POM
<!--SpringCloud openfeign --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
- YML - activate Sentinel support for Feign
server: port: 84 spring: application: name: nacos-order-consumer cloud: nacos: discovery: server-addr: 192.168.174.128:8848 sentinel: transport: #Configure Sentinel dashboard address dashboard: localhost:8888 #The default port is 8719. If it is occupied, it will automatically start + 1 scanning from 8719 until the unoccupied port is found port: 8719 ##The name of the micro service that the consumer will visit (the micro service provider that has successfully registered into nacos) service-url: nacos-user-service: http://nacos-payment-provider # Activate Sentinel support for Feign management: endpoints: web: exposure: include: '*' feign: sentinel: enabled: true
- Business class
Business interface with @ FeignClient annotation
@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)//Close 9003 service provider in call public interface PaymentService { @GetMapping(value = "/paymentSQL/{id}") public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id); }
PaymentFallbackService class
@Component public class PaymentFallbackService implements PaymentService { @Override public CommonResult<Payment> paymentSQL(Long id) { return new CommonResult<>(444,"Service degradation return,There is no such flow information",new Payment(id, "errorSerial......")); } }
controller
@RestController @Slf4j public class CircleBreakerController { //========================Sentinel combined with OpenFeign @Resource private PaymentService paymentService; @GetMapping(value = "/consumer/paymentSQL/{id}") public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id){ // if(id==4){ // throw new RuntimeException("no such id"); // } return paymentService.paymentSQL(id); } }
- Main startup - add @ EnableFeignClients to launch the function of Feign
@EnableDiscoveryClient @SpringBootApplication @EnableFeignClients public class OrderNacosMain84 { public static void main(String[] args) { SpringApplication.run(OrderNacosMain84.class, args); } }
3. Test
visit: http://localhost:84/consumer/paymentSQL/1
Test 84 calls 9003. At this time, the 9003 micro service provider is deliberately closed. You can see that the 84 consumer side is automatically degraded and will not be consumed
15.9.3 comparison of fuse frames
15.10 rule persistence
15.10.1 what is it
Once we restart the application, sentinel rules will disappear, and the production environment needs to persist the configuration rules
15.10.2 how to play
Persist the flow restriction configuration rules into Nacos and save them. As long as you refresh a rest address of 8401, you can see the flow control rules on sentinel console. As long as the configuration in Nacos is not deleted, the flow control rules on sentinel on 8401 will remain valid
15.10.3 implementation steps
- Modify cloudalibaba-sentinel-service8401
- POM
<!--SpringCloud ailibaba sentinel-datasource-nacos --> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency>
- YML - add Nacos data source configuration
- Add Nacos business rule configuration
Content analysis:
[ { "resource": "/rateLimit/byUrl", "limitApp": "default", "grade": 1, "count": 1, "strategy": 0, "controlBehavior": 0, "clusterMode": false } ] resource: Resource name; limitApp: Source application; grade: Threshold type, 0 indicates the number of threads and 1 indicates the number of threads QPS; count: Single machine threshold; strategy: Flow control mode, 0 indicates direct, 1 indicates association, and 2 indicates link; controlBehavior: Flow control effect, 0 indicates rapid failure, 1 indicates Warm Up,2 Indicates waiting in line; clusterMode: Cluster or not.
- After starting 8401, refresh sentinel and find that the business rules have changed
15.10.4 testing
- Fast access test interface, http://localhost:8401/rateLimit/byUrl , display: Blocked By Sentinel(flow limiting) error, indicating that the configuration file is effective
- Stop 8401 and look at sentinel
-
Restart 8401 and see sentinel again
Not at first glance. Just a moment Multiple calls http://localhost:8401/rateLimit/byUrl The reconfiguration occurred and the persistence verification passed