1. Basic introduction
Official website
https://github.com/alibaba/Sentinel/wiki/ Hot spot parameter current limiting
2. @SentinelResource
Bottom covering method
There are two types: system default and customer defined
In the previous case s, the default prompt of sentinel system is used after the outflow problem is limited
Use @ SentinelResource to customize the degradation method
code
Add controller method
@GetMapping("/testHotKey") @SentinelResource(value = "testHotKey", blockHandler = "deal_testHotKey") public String testHotKey(@RequestParam(value = "p1", required = false) String p1, @RequestParam(value = "p2", required = false) String p2) { return "------testHotKey"; } public String deal_testHotKey(String p1, String p2, BlockException execetion) { return "------deal_testHotKey";// The default prompt of sentinel system: Blocked by sentinel (flow limiting) }
com.alibaba.csp.sentinel.slots.block.BlockException
to configure
@SentinelResource(value = "testHotKey")
@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
The above case demonstrates the first parameter p1. When the QPS is clicked once for more than 1 second, the current is limited immediately
exceptional case
Normal: after more than one second, the current will be limited immediately after reaching the threshold of 1
We expect that when p1 parameter is a special value, its current limit value is not the same as usual
Special case: if the value of p1 is equal to 5, its threshold can reach 200
test
http://localhost:8401/testHotKey?p1=1
http://localhost:8401/testHotKey?p1=5
When p1 is equal to 5, the threshold becomes 200. When p1 is not equal to 5, the threshold is the usual 1
Note that the hotspot parameter must be a basic type or String
other
Add exception
int i = 10/0;
3. System rules
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
3.1 configure global QPS
Description of various configuration parameters
4. Current limit by resource name + subsequent processing
Nacos started successfully
Sentinel started successfully
Module
Business class RateLimitController
package com.lele.springcloud.alibaba.controller; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.lele.springcloud.entities.CommonResult; import com.lele.springcloud.entities.Payment; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * @author: lele * @date: 2021/4/10 19:15 * @description: */ @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"); } }
Configure flow control rules
Configuration steps
It means that if the number of queries is greater than 1 in one second, it will run to our custom flow and limit the current.
test
Additional questions
At this time, close the microservice 8401, and the flow control rules disappear, temporarily.
5. Limit current 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 add
@GetMapping("/rateLimit/byUrl") @SentinelResource(value = "byUrl") public CommonResult byUrl() { return new CommonResult(200, "Press url Current limiting test OK", new Payment(2020L, "serial002")); }
Sentinel console configuration:
Return the self-contained current limiting processing result
Problems faced by the above method
5.1 customer defined current limiting processing logic
Create a customerBlockHandler class to customize the flow limiting processing logic
Custom current limiting processing class
package com.lele.springcloud.alibaba.myhandler; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.lele.springcloud.entities.CommonResult; /** * @author: lele * @date: 2021/4/10 21:55 * @description: */ public class CustomerBlockHandler { public static CommonResult handleException(BlockException exception) { return new CommonResult(2020, "Custom current limiting processing information....CustomerBlockHandler"); } }
RateLimitController add method
@GetMapping("/rateLimit/customerBlockHandler") @SentinelResource(value = "customerBlockHandler", blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handleException") public CommonResult customerBlockHandler() { return new CommonResult(200, "Customized by customer", new Payment(2020L, "serial003")); }
Call the microservice once after starting it
http://localhost:8401/rateLimit/customerBlockHandler
Sentinel console configuration
Further explanation
Sentinel mainly has three core API s
- SphU define resources
- Tracer definition statistics
- ContextUtil defines the context
6. Service fuse function
6.1 Ribbon series
Start nacos and sentinel
Provider 9003 / 9004
Create a new cloudalibaba provider payment9003 / 9004
pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>spring-cloud-demo</artifactId> <groupId>com.lele.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloudalibaba-provider-payment9003</artifactId> <dependencies> <!--SpringCloud ailibaba nacos --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.lele.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> </project>
yml
server: port: 9003 spring: application: name: nacos-payment-provider cloud: nacos: discovery: server-addr: localhost:8848 #Configure Nacos address management: endpoints: web: exposure: include: '*'
Main start:
package com.lele.springcloud.alibaba; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; /** * @author: lele * @date: 2021/4/11 6:42 * @description: */ @SpringBootApplication @EnableDiscoveryClient public class PaymentMain9003 { public static void main(String[] args) { SpringApplication.run(PaymentMain9003.class, args); } }
Business class:
package com.lele.springcloud.alibaba.controller; import com.lele.springcloud.entities.CommonResult; import com.lele.springcloud.entities.Payment; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; /** * @author: lele * @date: 2021/4/11 6:44 * @description: */ @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; } }
Refer to 9003 to create a new 9004 module
Test address
http://localhost:9003/paymentSQL/1
Consumer 84
Create a new cloudalibaba-consumer-nacos-order84
pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>spring-cloud-demo</artifactId> <groupId>com.lele.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloudalibaba-consumer-nacos-order84</artifactId> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>com.lele.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <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> <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> </project>
yml
server: port: 84 spring: application: name: nacos-order-consumer cloud: nacos: discovery: server-addr: localhost:8848 sentinel: transport: dashboard: localhost:8080 port: 8719 service-url: nacos-user-service: http://nacos-payment-provider
Main startup class
package com.lele.springcloud.alibaba; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; /** * @author: lele * @date: 2021/4/11 7:01 * @description: */ @SpringBootApplication @EnableDiscoveryClient @EnableFeignClients public class OrderNacosMain84 { public static void main(String[] args) { SpringApplication.run(OrderNacosMain84.class, args); } }
ApplicationContextConfig
package com.lele.springcloud.alibaba.config; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; /** * @author: lele * @date: 2021/4/11 7:03 * @description: */ public class ApplicationContextConfig { @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } }
Business class
package com.lele.springcloud.alibaba.controller; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.lele.springcloud.entities.CommonResult; import com.lele.springcloud.entities.Payment; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; /** * @author: lele * @date: 2021/4/11 7:05 * @description: */ @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") / / not configured //@SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback is only responsible for business exceptions //@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler is only responsible for sentinel console configuration violations @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler", exceptionsToIgnore = {IllegalArgumentException.class}) public CommonResult<Payment> fallback(@PathVariable Long id) { CommonResult<Payment> 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; } //fallback 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); } //blockHandler 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); } }
objective
fallback tube runs abnormally
blockHandler pipe configuration violation
Test address: http://localhost:84/consumer/fallback/1
6.2 Feign series
Modify module 84
yml
PaymentFallbackService implementation class
package com.lele.springcloud.alibaba.feign; import com.lele.springcloud.alibaba.service.PaymentService; import com.lele.springcloud.entities.CommonResult; import com.lele.springcloud.entities.Payment; import org.springframework.stereotype.Component; /** * @author: lele * @date: 2021/4/11 7:16 * @description: */ @Component public class PaymentFallbackService implements PaymentService { @Override public CommonResult<Payment> paymentSQL(Long id) { return new CommonResult<>(44444,"Service degradation return,---PaymentFallbackService",new Payment(id,"errorSerial")); } }
Business interface with @ FeignClient annotation
package com.lele.springcloud.alibaba.service; import com.lele.springcloud.alibaba.feign.PaymentFallbackService; import com.lele.springcloud.entities.CommonResult; import com.lele.springcloud.entities.Payment; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; /** * @author: lele * @date: 2021/4/11 7:14 * @description: */ @FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class) public interface PaymentService { @GetMapping(value = "/paymentSQL/{id}") public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id); }
controller
http://lcoalhost:84/consumer/openfeign/1
http://lcoalhost:84/consumer/paymentSQL/1
Test 84 calls 9003. At this time, the 9003 micro service provider is deliberately closed to see that the 84 consumer side is automatically degraded and will not be consumed
7. Comparison of fuse frames
8. Rule persistence
Once we restart the application, Sentinel rules will disappear, and the production environment needs to persist the configuration rules
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
Modify cloudalibaba-sentinel-service8401
yml
server: port: 8401 spring: application: name: cloudalibaba-sentinel-service cloud: nacos: discovery: #nacos service registry address server-addr: localhost:8848 sentinel: transport: #Configure sentinel dashboard address dashboard: localhost:8080 #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 datasource: ds1: nacos: server-addr: localhost:8848 dataId: cloudalibaba-sentinel-service groupId: DEFAULT_GROUP data-type: json rule-type: flow management: endpoints: web: exposure: include: '*'
Add Nacos business rule configuration:
[ { "resource": "/retaLimit/byUrl", "limitApp": "default", "grade": 1, "count": 1, "strategy": 0, "controlBehavior": 0, "clusterMode": false } ]
After starting 8401, refresh sentinel and find that the business rules have changed
Stop 8401 and look at sentinel
Multiple calls http://localhost:8401/rateLimit/byUrl
The reconfiguration occurred and the persistence verification passed