目录
sentinel 下载安装:
初始化监控:
流量控制:
服务降级:
热点规则:
sentinel系统规则(系统自适应限流):
@SentinelResource的配置:
Sentinel服务熔断:
exceptionsToIgnore:
Sentinel服务熔断OpenFeign:
sentinel持久化规则:
sentinel 下载安装: 访问管理页面 localhost:8080
初始化监控:
建module导入POM
org.springframework.cloud
spring-cloud-starter-config
com.alibaba.csp
sentinel-datasource-nacos
org.springframework.cloud
spring-cloud-starter-stream-rabbit
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
org.springframework.cloud
spring-cloud-starter-openfeign
com.ljw.springcloudstudy
cloud-api-commons
${project.version}
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-starter-alibaba-nacos-discovery
0.2.1.RELEASE
YML
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
# 默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
port: 8719
management:
endpoints:
web:
exposure:
include: "*" 主启动
@SpringBootApplication
@EnableDiscoveryClient
public class MainApp8401 {
public static void main(String[] args) {
SpringApplication.run(MainApp8401.class,args);
}
}
controller
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA() {
return "-------testA";
}
@GetMapping("/testB")
public String testB() {
return "-------testB";
}
}
执行一次访问后访问控制台(懒加载),可以看到该服务
org.springframework.cloud spring-cloud-starter-configcom.alibaba.csp sentinel-datasource-nacosorg.springframework.cloud spring-cloud-starter-stream-rabbitcom.alibaba.cloud spring-cloud-starter-alibaba-sentinelorg.springframework.cloud spring-cloud-starter-openfeigncom.ljw.springcloudstudy cloud-api-commons${project.version} org.springframework.boot spring-boot-starter-weborg.springframework.boot spring-boot-starter-actuatororg.springframework.cloud spring-cloud-starter-alibaba-nacos-discovery0.2.1.RELEASE
YML
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
# 默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
port: 8719
management:
endpoints:
web:
exposure:
include: "*" 主启动
@SpringBootApplication
@EnableDiscoveryClient
public class MainApp8401 {
public static void main(String[] args) {
SpringApplication.run(MainApp8401.class,args);
}
}
controller
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA() {
return "-------testA";
}
@GetMapping("/testB")
public String testB() {
return "-------testB";
}
}
执行一次访问后访问控制台(懒加载),可以看到该服务
流量控制:
流控模式为直接,流控效果为快速失败时:流控模式为关联时,当关联资源达到阈值时,限流自己;当testB访问达到阈值后,testA:流控效果为warm up(预热)时:一开始阈值为设定阈值/cold Factor,经过预热时长后,变为设定的阈值流控效果为排队等待时:使得请求匀速通过
服务降级: 首先是慢调用比例:
@GetMapping("/testD")
public String testD() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "-------testD";
}
}
配置:
测试后发现熔断
@GetMapping("/testD")
public String testD() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "-------testD";
}
}
配置:
测试后发现熔断
异常比例:
@GetMapping("/testE")
public String testE() {
//异常
int age=10/0;
return "-------testE";
}
异常数:
@GetMapping("/testF")
public String testF() {
int age=10/0;
return "-------testF";
}
热点规则:
针对热点参数进行限流;
@GetMapping("/testHotKey")
// 作为唯一标识,一般和url统一,也就是资源名称
@SentinelResource(value = "testHotKey", blockHandler = "dealTestHotKey")
public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
@RequestParam(value = "p2", required = false) String p2) {
return "-----testHotKey";
}
//兜底方法,如果发现了热点参数,就会走这里
public String dealTestHotKey(String p1, String p2, BlockException exception) {
return "------dealTestHotKey";
}
}
制定热点规则:第一个参数在一秒钟内QPS超过了阈值,则立刻进行降级处理,携带p1也会按照这个规则进行;参数例外项:当热点参数为特殊值的时候,会有不同于其他的限流阈值;如果是运行异常,那么@SentinelResource不负责,不走该兜底方法,@SentinelResource只负责违背控制台配置的异常。
@GetMapping("/testHotKey")
// 作为唯一标识,一般和url统一,也就是资源名称
@SentinelResource(value = "testHotKey", blockHandler = "dealTestHotKey")
public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
@RequestParam(value = "p2", required = false) String p2) {
// 模拟运行时异常
int age =10/0;
return "-----testHotKey";
}
//兜底方法,如果发现了热点参数,就会走这里
public String dealTestHotKey(String p1, String p2, BlockException exception) {
return "------dealTestHotKey/(ㄒoㄒ)/~~";
}
针对热点参数进行限流;
@GetMapping("/testHotKey")
// 作为唯一标识,一般和url统一,也就是资源名称
@SentinelResource(value = "testHotKey", blockHandler = "dealTestHotKey")
public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
@RequestParam(value = "p2", required = false) String p2) {
return "-----testHotKey";
}
//兜底方法,如果发现了热点参数,就会走这里
public String dealTestHotKey(String p1, String p2, BlockException exception) {
return "------dealTestHotKey";
}
}
制定热点规则:第一个参数在一秒钟内QPS超过了阈值,则立刻进行降级处理,携带p1也会按照这个规则进行;参数例外项:当热点参数为特殊值的时候,会有不同于其他的限流阈值;如果是运行异常,那么@SentinelResource不负责,不走该兜底方法,@SentinelResource只负责违背控制台配置的异常。
@GetMapping("/testHotKey")
// 作为唯一标识,一般和url统一,也就是资源名称
@SentinelResource(value = "testHotKey", blockHandler = "dealTestHotKey")
public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
@RequestParam(value = "p2", required = false) String p2) {
// 模拟运行时异常
int age =10/0;
return "-----testHotKey";
}
//兜底方法,如果发现了热点参数,就会走这里
public String dealTestHotKey(String p1, String p2, BlockException exception) {
return "------dealTestHotKey/(ㄒoㄒ)/~~";
}
sentinel系统规则(系统自适应限流):
从整体维度对应用入口流量进行控制;以入口QPS举例:、
@SentinelResource的配置:
按资源名称进行限流+后续处理;首先在8401中引入自定义jar包:
com.ljw.springcloudstudy
cloud-api-commons
${project.version}
新加一个业务类:
@RestController
public class ReTeLimitController {
@GetMapping("/byResource")
@SentinelResource(value = "byResource",blockHandler = "handleException")
public CommonResult byResource(){
return new CommonResult(200,"按资源名称进行限流测试",new Payment(2020L,"serial001"));
}
public CommonResult handleException(BlockException exception){
return new CommonResult(444,exception.getClass().getCanonicalName()+"t","服务不可用");
}
}
添加限流条件:
测试:
关闭服务后,流控规则会消失(非持久化);
如果没有自定义blockHandler方法,则会用系统自带的。
按资源url进行限流+后续处理;
@GetMapping("/byUrl")
// 没有自定义blockHandler方法,将会使用默认的
@SentinelResource(value = "byUrl")
public CommonResult byUrl(){
return new CommonResult(200,"按资源url进行限流测试",new Payment(2020L,"serial002"));
}
} 测试:
自定义限流处理+解耦:创建自定义限流处理类: public class CustomerBlockHandler {
public static CommonResult handlerException(BlockException exception){
return new CommonResult(444,"自定义限流处理,global",new Payment(2020L,"serial003"));
}
public static CommonResult handlerException2(BlockException exception){
return new CommonResult(444,"自定义限流处理,global",new Payment(2020L,"serial003"));
}
}
@GetMapping("/customerBlockHandler")
//调用限流处理的方法2
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class,
blockHandler = "handlerException2")
public CommonResult customerBlockHandler() {
return new CommonResult(200, "自定义限流处理", new Payment(2020L, "serial003"));
}
} 需要使用资源名进行限流;测试:
com.ljw.springcloudstudy
cloud-api-commons
${project.version}
新加一个业务类:
@RestController
public class ReTeLimitController {
@GetMapping("/byResource")
@SentinelResource(value = "byResource",blockHandler = "handleException")
public CommonResult byResource(){
return new CommonResult(200,"按资源名称进行限流测试",new Payment(2020L,"serial001"));
}
public CommonResult handleException(BlockException exception){
return new CommonResult(444,exception.getClass().getCanonicalName()+"t","服务不可用");
}
}
添加限流条件:
测试:
关闭服务后,流控规则会消失(非持久化);
如果没有自定义blockHandler方法,则会用系统自带的。
按资源url进行限流+后续处理;
@GetMapping("/byUrl")
// 没有自定义blockHandler方法,将会使用默认的
@SentinelResource(value = "byUrl")
public CommonResult byUrl(){
return new CommonResult(200,"按资源url进行限流测试",new Payment(2020L,"serial002"));
}
} 测试:
public class CustomerBlockHandler {
public static CommonResult handlerException(BlockException exception){
return new CommonResult(444,"自定义限流处理,global",new Payment(2020L,"serial003"));
}
public static CommonResult handlerException2(BlockException exception){
return new CommonResult(444,"自定义限流处理,global",new Payment(2020L,"serial003"));
}
}
@GetMapping("/customerBlockHandler")
//调用限流处理的方法2
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class,
blockHandler = "handlerException2")
public CommonResult customerBlockHandler() {
return new CommonResult(200, "自定义限流处理", new Payment(2020L, "serial003"));
}
} 需要使用资源名进行限流;测试:
Sentinel服务熔断:
新建payment服务9003,9004,消费者84服务端YML: server:
port: 9003
spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848
management:
endpoints:
web:
exposure:
include: "*" 服务端controller: @RestController
public class PaymentController {
@Value("${server.port}")
public String serverPort;
public static HashMap hashMap=new HashMap<>();
static {
hashMap.put(1L,new Payment(1L, UUID.randomUUID().toString()));
hashMap.put(2L,new Payment(2L, UUID.randomUUID().toString()));
hashMap.put(3L,new Payment(3L, UUID.randomUUID().toString()));
}
@GetMapping("/paymentSQL/{id}")
public CommonResult paymentSQL(@PathVariable("id") Long id){
Payment payment = hashMap.get(id);
CommonResult result = new CommonResult<>(200, "from sql,serverPort" + serverPort, payment);
return result;
}
}
消费端主启动:
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class OrderMain84 {
public static void main(String[] args) {
SpringApplication.run(OrderMain84.class,args);
}
}
消费端service:
@FeignClient(value ="nacos-payment-provider")
public interface PaymentFeignService {
@GetMapping("/paymentSQL/{id}")
public CommonResult paymentSQL(@PathVariable("id") Integer id);
}
消费端controller
@RestController
public class OrderController {
private static final String SERVICE_NAME="nacos-payment-provider";
@Resource
private PaymentFeignService paymentFeignService;
@GetMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback")
public CommonResult paymentSQL(@PathVariable("id") Long id){
CommonResult result = paymentFeignService.paymentSQL(id);
if (id == 4){
throw new IllegalArgumentException("IllegalArgumentException,非法参数异常");
}else if (result.getData()==null){
throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
}
return result;
}
}
fallback负责处理运行时异常,blockhandler负责配置违规;
server:
port: 9003
spring:
application:
name: nacos-payment-provider
cloud:
nacos:
discovery:
server-addr: localhost:8848
management:
endpoints:
web:
exposure:
include: "*" 服务端controller: @RestController
public class PaymentController {
@Value("${server.port}")
public String serverPort;
public static HashMap hashMap=new HashMap<>();
static {
hashMap.put(1L,new Payment(1L, UUID.randomUUID().toString()));
hashMap.put(2L,new Payment(2L, UUID.randomUUID().toString()));
hashMap.put(3L,new Payment(3L, UUID.randomUUID().toString()));
}
@GetMapping("/paymentSQL/{id}")
public CommonResult paymentSQL(@PathVariable("id") Long id){
Payment payment = hashMap.get(id);
CommonResult result = new CommonResult<>(200, "from sql,serverPort" + serverPort, payment);
return result;
}
}
消费端主启动:
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class OrderMain84 {
public static void main(String[] args) {
SpringApplication.run(OrderMain84.class,args);
}
}
消费端service:
@FeignClient(value ="nacos-payment-provider")
public interface PaymentFeignService {
@GetMapping("/paymentSQL/{id}")
public CommonResult paymentSQL(@PathVariable("id") Integer id);
}
消费端controller
@RestController
public class OrderController {
private static final String SERVICE_NAME="nacos-payment-provider";
@Resource
private PaymentFeignService paymentFeignService;
@GetMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback")
public CommonResult paymentSQL(@PathVariable("id") Long id){
CommonResult result = paymentFeignService.paymentSQL(id);
if (id == 4){
throw new IllegalArgumentException("IllegalArgumentException,非法参数异常");
}else if (result.getData()==null){
throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
}
return result;
}
}
fallback负责处理运行时异常,blockhandler负责配置违规;
如果没有配fallback,那么将直接报错;
只配置fallback时:
@GetMapping("/consumer/fallback/{id}")
// 配置fallback方法
@SentinelResource(value = "fallback",fallback = "handlerFallBack")
public CommonResult paymentSQL(@PathVariable("id") Long id){
CommonResult result = paymentFeignService.paymentSQL(id);
if (id == 4){
throw new IllegalArgumentException("IllegalArgumentException,非法参数异常");
}else if (result.getData()==null){
throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
}
return result;
}
public CommonResult handlerFallBack(@PathVariable("id") Long id,Throwable e){
Payment payment = new Payment(id, "null");
return new CommonResult(444,"兜底异常handlerFallBack,exception内容"+e.getMessage(),payment);
} 只配置blockhandler,不处理运行时异常,只处理配置违规,但是可以在配置中设置异常比例和异常数来处理运行时异常;
同时配置fallback和blockHandler:
@GetMapping("/consumer/fallback/{id}")
// 配置fallback方法
@SentinelResource(value = "fallback",fallback = "handlerFallBack",blockHandler = "blockHandler")
public CommonResult paymentSQL(@PathVariable("id") Long id){
CommonResult result = paymentFeignService.paymentSQL(id);
if (id == 4){
throw new IllegalArgumentException("IllegalArgumentException,非法参数异常");
}else if (result.getData()==null){
throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
}
return result;
}
public CommonResult handlerFallBack(@PathVariable("id") Long id,Throwable e){
Payment payment = new Payment(id, "null");
return new CommonResult(444,"兜底异常handlerFallBack,exception内容"+e.getMessage(),payment);
}
public CommonResult blockHandler(@PathVariable("id") Long id, BlockException blockException){
Payment payment = new Payment(id, null);
return new CommonResult<>(445,"blockHandler限流,blockException"+blockException.getMessage(),payment);
}
}
同时违反配置和运行报错:
走blockHandler;
exceptionsToIgnore: 也就是发生该异常的时候,不再走fallback方法,没有降级效果; @GetMapping("/consumer/fallback/{id}")
// 配置fallback方法
@SentinelResource(value = "fallback",
fallback = "handlerFallBack",
blockHandler = "blockHandler",
// 也就是发生该异常的时候,不再走fallback方法,没有降级效果
exceptionsToIgnore = {IllegalArgumentException.class})
public CommonResult paymentSQL(@PathVariable("id") Long id){
CommonResult result = paymentFeignService.paymentSQL(id);
if (id == 4){
throw new IllegalArgumentException("IllegalArgumentException,非法参数异常");
}else if (result.getData()==null){
throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
}
return result;
}
public CommonResult handlerFallBack(@PathVariable("id") Long id,Throwable e){
Payment payment = new Payment(id, "null");
return new CommonResult(444,"兜底异常handlerFallBack,exception内容"+e.getMessage(),payment);
}
public CommonResult blockHandler(@PathVariable("id") Long id, BlockException blockException){
Payment payment = new Payment(id, null);
return new CommonResult<>(445,"blockHandler限流,blockException"+blockException.getMessage(),payment);
}
Sentinel服务熔断OpenFeign: 消费者端YML server:
port: 84
spring:
application:
name: nacos-payment-order
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
# 默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
port: 8719
management:
endpoints:
web:
exposure:
include: "*"
#开启sentinel对feign的支持
feign:
sentinel:
enabled: true
主启动:
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class OrderMain84 {
public static void main(String[] args) {
SpringApplication.run(OrderMain84.class,args);
}
}
service:
@FeignClient(value ="nacos-payment-provider",fallback = PaymentFeignServiceImpl.class)
public interface PaymentFeignService {
@GetMapping("/paymentSQL/{id}")
public CommonResult paymentSQL(@PathVariable("id") Long id);
}
通配服务降级,处理服务端宕机,服务调用失败的情况;
@Component
public class PaymentFeignServiceImpl implements PaymentFeignService {
@Override
public CommonResult paymentSQL(Long id) {
return new CommonResult(444, "服务降级访问,------PaymentFeignServiceImpl",
new Payment(id, "errorSerial"));
}
}
sentinel持久化规则:
需要导入POM
com.alibaba.csp
sentinel-datasource-nacos
YML
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
# 默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
port: 8719
# 持久化sentinel规则的配置
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: "*" 在nacos中新建配置:
其中,resource:资源名称;limitApp:来源应用; grade:阀值类型,0表示线程数,1表示QPS,count:单机阈值,strategy:流控模式,0表示直接,1表示关联,2表示链路;controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;clusterMode:是否集群;
创建成功,测试:
服务重启后,该规则依旧存在。
com.alibaba.csp sentinel-datasource-nacos
YML
server:
port: 8401
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
# 默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
port: 8719
# 持久化sentinel规则的配置
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: "*" 在nacos中新建配置:
其中,resource:资源名称;limitApp:来源应用; grade:阀值类型,0表示线程数,1表示QPS,count:单机阈值,strategy:流控模式,0表示直接,1表示关联,2表示链路;controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;clusterMode:是否集群;
创建成功,测试:
服务重启后,该规则依旧存在。



