1.限流之@SentinelResource
1.1 按资源名称限流+后续处理
启动Nacos成功
启动Sentinel成功
Module
1. 新建cloudalibaba-sentinel-service8401
2. pom.xml
1 2 3 4 5 6
| <dependency> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency>
|
3. application.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| server: port: 8401
spring: application: name: cloudalibaba-sentinel-service cloud: nacos: discovery: server-addr: localhost:8848 sentinel: transport: dashboard: localhost:8080 port: 8719
management: endpoints: web: exposure: include: '*'
|
4. 主启动类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.atguigu.springcloud.alibaba;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient @SpringBootApplication public class MainApp8401 { public static void main(String[] args) { SpringApplication.run(MainApp8401.class, args); }
}
|
5. 业务类RateLimitController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package com.atguigu.springcloud.alibaba.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.atguigu.springcloud.alibaba.entities.CommonResult; import com.atguigu.springcloud.alibaba.entities.Payment; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;
@RestController public class RateLimitController { @GetMapping("/byResource") @SentinelResource(value = "byResource",blockHandler = "handleException") public CommonResult byResource() { return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001")); } public CommonResult handleException(BlockException exception) { return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用"); }
|
配置流控规则

表示1秒钟内查询次数大于1,就跑到我们自定义的处流,限流
测试
1秒钟点击1下,OK

超过上述问题,疯狂点击,返回了自己定义的限流处理信息,限流发送

额外问题
此时关闭微服务8401看看
Sentinel控制台,流控规则消失了?????
1.2 按照Url地址限流+后续处理
**通过访问的URL来限流,会返回Sentinel自带默认的限流处理信息
**
业务类RateLimitController
1 2 3 4 5 6
| @GetMapping("/rateLimit/byUrl") @SentinelResource(value = "byUrl") public CommonResult byUrl() { return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002")); }
|
Sentinel控制台配置

疯狂点击http://localhost:8401/rateLimit/byUrl

1.3上面兜底方法面临的问题

1.4 客户自定义限流处理逻辑
创建customerBlockHandler类用于自定义限流处理逻辑
1 2 3 4 5 6 7 8 9 10
| public class CustomerBlockHandler {
public static CommonResult handlerException(BlockException exception) { return new CommonResult(444,"按照客户自定义的Glogal 全局异常处理 ---- 1",new Payment(2020L,"serial003")); }
public static CommonResult handlerException2(BlockException exception) { return new CommonResult(444,"按照客户自定义的Glogal 全局异常处理 ---- 2",new Payment(2020L,"serial003")); } }
|
RateLimitController
1 2 3 4 5 6 7 8
| @GetMapping("/rateLimit/customerBlockHandler") @SentinelResource(value = "customerBlockHandler", blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handlerException2") public CommonResult customerBlockHandler() { return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003")); }
|
启动微服务后先调用一次

疯狂点击

进一步说明

2. 服务熔断功能
2.1 sentinel整合ribbon+openFeign+fallback
2.2 Ribbon系列
2.2.1 启动nacos和sentinel
2.2.2 提供者9003/9004
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.atguigu.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>
|
application.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| server: port: 9003
spring: application: name: nacos-payment-provider cloud: nacos: discovery: server-addr: localhost:8848
management: endpoints: web: exposure: include: '*'
|
主启动类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package com.atguigu.springcloud.alibaba;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication @EnableDiscoveryClient public class PaymentMain9003 { public static void main(String[] args) { SpringApplication.run(PaymentMain9003.class, args); } }
|
业务类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| package com.atguigu.springcloud.alibaba.controller;
import com.atguigu.springcloud.alibaba.entities.CommonResult; import com.atguigu.springcloud.alibaba.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;
@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; } }
|
测试地址:http://localhost:9003/paymentSQL/1
2.2.3 消费者84
新建cloudalibaba-consumer-nacos-order84
pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| <?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>cloud2020</artifactId> <groupId>com.atguigu.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.atguigu.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>
|
application.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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
|
主启动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com.atguigu.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;
@EnableDiscoveryClient @SpringBootApplication @EnableFeignClients public class OrderNacosMain84 { public static void main(String[] args) { SpringApplication.run(OrderNacosMain84.class, args); } }
|
业务类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| package com.atguigu.springcloud.alibaba.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.atguigu.springcloud.alibaba.entities.CommonResult; import com.atguigu.springcloud.alibaba.entities.Payment; import com.atguigu.springcloud.alibaba.service.PaymentService;
import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; 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;
@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",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,非法参数异常...."); }else if (result.getData() == null) { throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常"); }
return result; } public CommonResult handlerFallback(@PathVariable Long id,Throwable e) { Payment payment = new Payment(id,"null"); return new CommonResult<>(444,"兜底异常handlerFallback,exception内容 "+e.getMessage(),payment); } public CommonResult blockHandler(@PathVariable Long id,BlockException blockException) { Payment payment = new Payment(id,"null"); return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException "+blockException.getMessage(),payment); }
}
|
没有任何配置
给客户error页面,不友好
只配置fallback
1
| @SentinelResource(value = "fallback",fallback ="handlerFallback")
|


只配置blockHandler
1
| @SentinelResource(value = "fallback",blockHandler = "blockHandler")
|

第一次点击时

快速点击时

fallback和blockHandler都配置


2.3 Feign系列
修改84模块
pom.xml
1 2 3 4 5
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
|
application.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| 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
feign: sentinel: enabled: true
|
主启动类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 添加@EnableFeignClients启动Feign的功能 package com.atguigu.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;
@EnableDiscoveryClient @SpringBootApplication @EnableFeignClients public class OrderNacosMain84 { public static void main(String[] args) { SpringApplication.run(OrderNacosMain84.class, args); } }
|
业务类
带@FeignClient注解的业务接口
fallback = PaymentFallbackService.class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.atguigu.springcloud.alibaba.service;
import com.atguigu.springcloud.alibaba.entities.CommonResult; import com.atguigu.springcloud.alibaba.entities.Payment; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class) public interface PaymentService { @GetMapping(value = "/paymentSQL/{id}") public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id); }
|
PaymentFallbackService实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.atguigu.springcloud.alibaba.service;
import com.atguigu.springcloud.alibaba.entities.CommonResult; import com.atguigu.springcloud.alibaba.entities.Payment; import org.springframework.stereotype.Component;
@Component public class PaymentFallbackService implements PaymentService { @Override public CommonResult<Payment> paymentSQL(Long id) { return new CommonResult<>(44444,"服务降级返回,---PaymentFallbackService",new Payment(id,"errorSerial")); } }
|
Controller
1 2 3 4 5 6 7 8
| @Resource private PaymentService paymentService;
@GetMapping(value = "/consumer/paymentSQL/{id}") public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) { return paymentService.paymentSQL(id); }
|
测试84调用9003,此时故意关闭9003微服务提供者,看84消费侧自动降级,不会被耗死
2.4 熔断框架比较


3. 规则持久化
是什么
一旦我们重启应用,Sentinel规则将消失,生产环境需要将配置规则进行持久化
怎么玩
将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上Sentinel上的流控规则持续有效
3.1步骤
修改cloudalibaba-sentinel-service8401
pom.xml
1 2 3 4 5
| <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency>
|
添加Nacos数据源配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| server: port: 8401
spring: application: name: cloudalibaba-sentinel-service cloud: nacos: discovery: server-addr: localhost:8848 sentinel: transport: dashboard: localhost:8080 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: '*'
feign: sentinel: enabled: true
|
** 添加Nacos业务规则配置**

内容解析
1 2 3 4 5 6 7 8 9 10 11 12
| [ { "resource": "/retaLimit/byUrl", "limitApp": "default", "grade": 1, "count": 1, "strategy": 0, "controlBehavior": 0, "clusterMode": false } ]
|

启动8401后刷新sentinel发现业务规则有了

**快速访问测试接口:**http://localhost:8401/rateLimit/byUrl

停止8401再看sentinel

重新启动8401再看sentinel