目录
- sentinel准备
- 流控规则 qps
- pom.xml
- apllication.yml
- 启动类
- controller
- 查看结果
- 流控提示不太友好
- 流控规则 线程数
- 全局异常处理
- pom.xml
- application.yml
- 启动类
- 实体类
- controller类
- 异常类
- 测试
- 关联流控模式
- 关联
- jmeter
- 链路
- service
- controller
- 代码调整
- 流控效果
- Warm UP
- 熔断降级规则
- 慢调用比例
- 异常比例
- 异常数
- 整合openFeign
- stock项目
- order项目
- pom.xml
- application.yml
- openFeign降级报错友好处理
- application.yml
- 增加异常处理类
- openFeign消费者接口改造
- 热点参数流控
- 代码
- 系统保护规则
- cpu
- qps
- 规则持久化
- 原始模式
- 拉模式
- 推模式
- nacos设置
- pom.xml
- application.yml
sentinel官方中文文档
sentinel准备
sentinel控制台1.8.0
- 注意需要跟springboot cloud版本与之对应,不然会有很多问题
输入命令
java -jar sentinel-dashboard-1.8.0.jar
- 注意默认端口是8080,很容易冲突
- 账号和密码都是sentinel
流控规则 qps
创建一个maven模块,父类的包,可以查看第一篇文章
pom.xml
<?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>springcloudalibaba</artifactId>
<groupId>com.cxy.springcloud</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.cxy.ssentinelnew</groupId>
<artifactId>sentinel-demo</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--sentinel启动器-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
</dependencies>
</project>
- 导入sentinel启动包
apllication.yml
server:
port: 8010
spring:
application:
name: sentinel-demo
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:8080
- dashboard 是sentinel地址
- 记得启动sentinel控制台界面
启动类
package com.cxy.sentinel;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author wu
* @version 1.0
* @date 2024/2/26 15:52
*/
@SpringBootApplication
public class StartApplication {
public static void main(String[] args) {
SpringApplication.run(StartApplication.class, args);
}
}
controller
package com.cxy.sentinel.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author wu
* @version 1.0
* @date 2024/2/2 11:39
*/
@RestController
@RequestMapping("/order")
public class OrderController {
@RequestMapping("/add")
public String add(){
System.out.println("下单成功");
return "Hello Feign!";
}
}
查看结果
- 红色是项目里面的服务名
- 注意:需要访问接口后,再来查看,不然会显示空白,先访问下面接口
- 表示1秒钟之内超过2次就会流控
流控提示不太友好
我们来修改一下代码
@RequestMapping("/add")
@SentinelResource(value = "add",blockHandler = "addBlockHandler")
public String add(){
System.out.println("下单成功");
return "Hello Feign!";
}
public String addBlockHandler(BlockException exception){
return "流控";
}
- addBlockHandler这个方法,有几点需要注意
-
- 一定是public
- 2、返回值一定跟需要做流控的那个方法一样
- 3、BlockException 的包记得,一定是sentinel下面的
启动后,去访问http://localhost:8010/order/add接口,发现之前做的1秒2次流控不生效
why?
这是因为之前的规则是保存在内存中,重启服务器后, 就不存在,需要重新加一次
再来访问一下http://localhost:8010/order/add
-返回状态码也变成200,实际使用过程中,返回值,我们肯定会封装成一个返回类包装一下的
流控规则 线程数
package com.cxy.sentinel.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
/**
* @author wu
* @version 1.0
* @date 2024/2/2 11:39
*/
@RestController
@RequestMapping("/order")
public class OrderController {
/**
* 流控----qps
* @return
*/
@RequestMapping("/add")
@SentinelResource(value = "add",blockHandler = "addBlockHandler")
public String add(){
System.out.println("下单成功");
return "Hello Feign!";
}
public String addBlockHandler(BlockException exception){
return "流控";
}
/**
* 流控--线程控制方法
* @return
* @throws InterruptedException
*/
@RequestMapping("/addThread")
@SentinelResource(value = "addThread",blockHandler = "addBlockHandler")
public String addThread() throws InterruptedException {
System.out.println("下单成功");
TimeUnit.SECONDS.sleep(5);
return "Hello Feign!"+Thread.currentThread().getName();
}
}
- addThread 这个方法是新增加的,其他的代码,跟qps的代码一样
- 增加一个延迟,是为了测试方便测试线程数
启动两个浏览器,才能测出线程数流控的效果
- 搞不清楚为什么,同一个浏览器,我看了一下线程名称也不一样,为什么不走流控
全局异常处理
在之前写的代码中,会存在一个问题,每一个需要流控、降级处理的方法,都需要加上@sentinelResource注解,在家一个异常处理的方式,用起来什么不方便,看起来也十分的别扭。
那有全局处理sentinel异常的方案,有的
pom.xml
<?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>springcloudalibaba</artifactId>
<groupId>com.cxy.springcloud</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.cxy.ssentinelnew</groupId>
<artifactId>sentinel-demo</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--sentinel启动器-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
</dependencies>
</project>
application.yml
server:
port: 8010
spring:
application:
name: sentinel-demo
cloud:
sentinel:
transport:
dashboard: 127.0.0.1:8080
启动类
package com.cxy.sentinel;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author wu
* @version 1.0
* @date 2024/2/26 15:52
*/
@SpringBootApplication
public class StartApplication {
public static void main(String[] args) {
SpringApplication.run(StartApplication.class, args);
}
}
实体类
package com.cxy.sentinel.entity;
public enum ResponseCode {
SUCCESS(200, "success"),
FAILURE(201, "failure"),
EXCEPTION(500, "exception"),
INVALID_TOKEN(501, "invalidToken");
private int code;
private String message;
ResponseCode(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage(){
return message;
}
}
package com.cxy.sentinel.entity;
import lombok.Data;
import java.io.Serializable;
@Data
public class ResponseResult<T> implements Serializable {
private static final long serialVersionUID = 1L;
private int code;
private String message;
private T payload;
public ResponseResult() {
this.code = ResponseCode.SUCCESS.getCode();
this.message = ResponseCode.SUCCESS.getMessage();
}
public ResponseResult(int code, String message) {
this.code = code;
this.message = message;
}
public ResponseResult(int code, String message, T payload) {
this.code = code;
this.message = message;
this.payload = payload;
}
public static <T> ResponseResult<T> SUCCESS() {
return new ResponseResult<>(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getMessage(), null);
}
public static <T> ResponseResult<T> SUCCESS(T payload) {
return new ResponseResult<>(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getMessage(), payload);
}
public static <T> ResponseResult<T> FAILURE(String message) {
return new ResponseResult<>(ResponseCode.FAILURE.getCode(), message);
}
public static <T> ResponseResult<T> EXCEPTION(String message) {
return new ResponseResult<>(ResponseCode.EXCEPTION.getCode(), message, null);
}
public static <T> ResponseResult<T> EXCEPTION(ResponseCode resCode) {
ResponseResult<T> resResult = new ResponseResult<>();
resResult.setCode(resCode.getCode());
resResult.setMessage(resCode.getMessage());
return resResult;
}
public static <T> ResponseResult<T> INVALID_TOKEN(String message) {
return new ResponseResult<>(ResponseCode.INVALID_TOKEN.getCode(), message);
}
}
- 返回辅助类
controller类
package com.cxy.sentinel.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.cxy.sentinel.entity.ResponseResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
/**
* @author wu
* @version 1.0
* @date 2024/2/2 11:39
*/
@RestController
@RequestMapping("/order")
public class OrderController {
/**
* 流控--异常处理
* @return
* @throws InterruptedException
*/
@RequestMapping("/addException")
public ResponseResult addException() throws InterruptedException {
System.out.println("流控异常处理!");
return ResponseResult.SUCCESS();
}
}
异常类
package com.cxy.sentinel.config;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.cxy.sentinel.entity.ResponseResult;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component // 注册为Bean 让Spring管理
public class SentinelExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
String msg = "未知异常";
int status = 429;
// 通过判断异常的类型 来判断到底是限流还是熔断降级还是授权限制
if (e instanceof FlowException) {
msg = "请求被限流了";
} else if (e instanceof ParamFlowException) {
msg = "请求被热点参数限流";
} else if (e instanceof DegradeException) {
msg = "请求被降级了";
} else if (e instanceof AuthorityException) {
msg = "没有权限访问";
status = 401;
}
response.setContentType("application/json;charset=utf-8");
response.setCharacterEncoding("utf-8");
response.setStatus(status);
new ObjectMapper().writeValue(response.getWriter(), ResponseResult.EXCEPTION(msg));
}
}
- 试过用全局注解的方式来处理sentinel的异常,不知道为什么捕获不到,有知道的朋友可以解答一下,网上我看也有类似的方法,但是,测试过不行
测试
先访问http://localhost:8010/order/addException接口,再增加一条流控为1的规则,表示1秒钟之内只能访问一次
- 出现这个,表示设置成功
关联流控模式
流控模式,分为三种,直接、关联、链路
关联
类似场景,12306,如果下单人数过多,点击查询票的时候,就显示服务正在繁忙
当两个资源存在争取时,就会存在关联,例如,数据库的某个表的读写,写多,读少等等
/**
* 关联流控模式
* @return
*/
@RequestMapping("/addOrder")
public String addOrder(){
System.out.println("下单成功");
return "生成订单!";
}
/**
* 关联流控模式
* @return
*/
@RequestMapping("/get")
public String get(){
System.out.println("查询订单");
return "查询订单!";
}
- 在全局异常处理的controller类中,增加如上代码
启动项目,增加流控,点击关联,访问http://localhost:8010/order/get 查询接口时,关联下单接口,意思是,下单接口访问过多时,查询会流控
为了方便测试,需要借助一个工具jmeter用来模拟发送请求
jmeter
jmeter测试工具
- 表示100秒内,300个线程,1秒至少3次
访问http://localhost:8010/order/get接口
链路
跟全局异常处理一样的代码,增加如下代码
service
package com.cxy.sentinel.service;
/**
* @author wu
* @version 1.0
* @date 2024/2/28 14:26
*/
public interface OrderService {
/**
* 查询用户
* @return
*/
public String getUser();
}
package com.cxy.sentinel.service;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Service;
/**
* @author wu
* @version 1.0
* @date 2024/2/28 14:27
*/
@Service
public class OrderServiceImpl implements OrderService{
@Override
@SentinelResource(value = "getUser")
public String getUser() {
return "查询用户";
}
}
- 增加SentinelResource注解,说明是sentinel资源,在界面就可以进行设置
controller
-以前的controller增加如下代码
@Autowired
private OrderService orderService;
//关联流控 访问/add 触发/get
@RequestMapping("/test1")
public String test1(){
return orderService.getUser();
}
//关联流控 访问/add 触发/get
@RequestMapping("/test2")
public String test2(){
return orderService.getUser();
}
访问http://localhost:8010/order/test2,设置流控
继续访问http://localhost:8010/order/test2,三次,出现如下画面,说明,流控成功
== 为什么报错?==
这是因为service类里面增加@SentinelResource后,会导致,对应的接口,不走全局异常,只能自定义异常来处理
代码调整
- 配置里面需要调整一下这个
package com.cxy.sentinel.service;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.stereotype.Service;
/**
* @author wu
* @version 1.0
* @date 2024/2/28 14:27
*/
@Service
public class OrderServiceImpl implements OrderService{
@Override
@SentinelResource(value = "getUser",blockHandler="getUserHandler")
public String getUser() {
return "查询用户";
}
public String getUserHandler(BlockException ex) {
return "流控用户";
}
}
访问http://localhost:8010/order/test2,如下图,说明配置成功
总结起来:
两个坑点:
- 配置里面application.yml配置里面需要设置成false, 全局流控异常处理不生效,需要自定义异常处理
流控效果
- 流控效果分为三种
Warm UP
有一个预热的过程,长期处在一个低流量过程,突然一下子流量狂飙,很容易导致系统出问题,所以,通过冷启动,让通过的流量,缓慢的增加,在一定时间内,加到对应的阈值
设置快速失败为5
- 设置1秒10次,循环4次
- 定时休息5秒
- 设置http请求
-通过上图可以发现,蓝色的线和绿色的线有重合的地方,我们的目标就是让蓝色的线,变平缓
- 设置成排队等待5秒,效果如下图
- 标红的地方,有空闲,说明,我们之前在线程哪里设置的,1秒10次,对服务器的压力不大
熔断降级规则
说到熔断,降级,我想大部分的人,脑海中,顿时就飘过hystrix,今天主要是看看sentinel的熔断
慢调用比例
- 访问/order/addThread资源时,如果在1000毫秒内,请求数量超过5,并且这些数量中超过1000毫秒的请求数量的比例超过0.1则熔断1秒
代码和前面一样,在之前的基础上,增加
/**
* 熔断降级规则,----慢调用比例
* @return
* @throws InterruptedException
*/
@RequestMapping("/addLevel")
public String addLevel() throws InterruptedException {
System.out.println("下单成功");
TimeUnit.SECONDS.sleep(2);
return "Hello Feign!"+Thread.currentThread().getName();
}
三部曲:
1、访问接口http://localhost:8010/order/addLevel
2、添加熔断规则
3、jemter压测
再去访问,接口被熔断了
- 熔断后,只有有一次不是慢查询,就会恢复正常
异常比例
熔断策略异常比例是以请求异常数量的比例作为阈值,当单位统计时长(statIntervalMs)内请求数大于设置的最小请求数,并且异常请求数的比例大于比例阈值,则接下来的请求会自动熔断,熔断时间为设置的熔断时长。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若在HALF-OPEN状态下有一个请求正常响应 则结束熔断,否则继续熔断。
先访问http://localhost:8010/order/err
- 从第六次开始,就熔断降级
异常数
- 连续访问3次后,服务就进行了熔断,会熔断10s
整合openFeign
openFeign代码
在这个基础上做测试
- 主要是涉及两个项目
stock项目
/**
* 增加异常
* @return
*/
@RequestMapping("/reduct1")
public String reduct1(){
int a = 1/0;
System.out.println("扣减库存!");
return "扣减库存"+port;
}
order项目
/**
* 产生异常
* @return
*/
@RequestMapping("/reduct1")
public String reduct1(){
String msg = stockFeignService.reduct1();
return "Hello Feign!"+msg;
}
pom.xml
<?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>springcloudalibaba</artifactId>
<groupId>com.cxy.springcloud</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>order</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--Nacos做配置中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--添加openfeign依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!--sentinel启动器-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
</dependencies>
</project>
- 添加sentinel依赖
application.yml
- 红色部分,是新增代码
server:
port: 8015
spring:
application:
name: order-service
cloud:
nacos:
server-addr: 127.0.0.1:8848
discovery:
name: nacos
password: nacos
namespace: public
loadbalancer:
ribbon:
enabled: false
sentinel:
transport:
dashboard: 127.0.0.1:8080
web-context-unify: false #默认将调用链路收起来
####设置springboot级别
logging:
level:
com.cxy.order.feign.StockFeignService: debug
feign:
client:
config:
stock-servic: ###对应微服务
###链接超时时间 默认2s
connectTimeout: 5000
### 请求处理超时时间 默认5s
readTimeout: 10000
##添加feign对sentinel的兼容
sentinel:
enabled: true
访问http://localhost:8015/order/reduct1,直接报错,有点不友好
openFeign降级报错友好处理
1、增加openFeign对sentinel的兼容
application.yml
feign:
client:
config:
stock-servic: ###对应微服务
###链接超时时间 默认2s
connectTimeout: 5000
### 请求处理超时时间 默认5s
readTimeout: 10000
##添加feign对sentinel的兼容
sentinel:
enabled: true
增加异常处理类
package com.cxy.order.feign;
import org.springframework.stereotype.Component;
/**
* @author wu
* @version 1.0
* @date 2024/2/21 17:54
*/
@Component
public class StockFeignServiceFallback implements StockFeignService{
@Override
public String reduct() {
return "降级";
}
@Override
public String reduct1() {
return "降级";
}
}
- 返回异常处理提示
openFeign消费者接口改造
- 跟以前的hystric一样的写法
启动order项目,再来访问
到这里,openFeign降级就完成咯。
热点参数流控
热点即经常访问的数据,很多时候,我们需要针对一些频率很高的数据,对其使用限制。
代码
/**
* 热点规则,必须使用@SentinelResource
*
* @return
*/
@RequestMapping("/get/{id}")
@SentinelResource(value = "getById", blockHandler = "HotBlockHandler")
public String getById(@PathVariable("id") Integer id) {
System.out.println("正常访问:" + id);
return "正常访问:" + id;
}
public String HotBlockHandler(@PathVariable("id") Integer id, BlockException e) {
return "热点异常处理" + id;
}
- 还是在之前项目中,进行更改(Order项目)
- 单机阈值遵循一个原则,热点参数和普通参数,谁多,谁就是设置成单机阈值
例如: 某个商品平台,今天晚上进行白酒秒杀,其他的商品没有活动,就可以把普通商品设置成单机阈值,白酒作为参数特殊设置。 - 上面的效果,就是普通的商品,能1秒访问10次,商品id为1的,1秒钟只能访问2次。
直接访问http://localhost:8015/order/get/1 三次
系统保护规则
系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体 Load、RT、线程数、入口 QPS 和CPU使用率监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
cpu
- sentinel刚开始整的那个项目代码里面进行测试
package com.cxy.sentinel.config;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.cxy.sentinel.entity.ResponseResult;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component // 注册为Bean 让Spring管理
public class SentinelExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
String msg = "未知异常";
int status = 429;
// 通过判断异常的类型 来判断到底是限流还是熔断降级还是授权限制
if (e instanceof FlowException) {
msg = "请求被限流了";
} else if (e instanceof ParamFlowException) {
msg = "请求被热点参数限流";
} else if (e instanceof DegradeException) {
msg = "请求被降级了";
}else if (e instanceof SystemBlockException){
msg = "系统规则保护";
} else if (e instanceof AuthorityException) {
msg = "没有权限访问";
status = 401;
}
response.setContentType("application/json;charset=utf-8");
response.setCharacterEncoding("utf-8");
response.setStatus(status);
new ObjectMapper().writeValue(response.getWriter(), ResponseResult.EXCEPTION(msg));
}
}
- 之前的历史代码,少了一个SystemBlockException异常else判断的代码,这里补一下
- 为了方便测试,cpu使用率的值是0-1,所以这里的0.01表示,只要cpu超过1,就会走系统保护
qps
这里的1,表示所有接口的平均qps,而不是某个接口的阈值
规则持久化
原始模式
存在内存中,开发环境测试使用,服务一重启,配置就消失
拉模式
pull模式的数据源(如本地文件、RDBMS等)一般是可写入的。使用时需要在客户端注册数据源:将对应的读数据源注册至对应的 RuleManager,将写数据源注册至transport的WritableDataSourceRegistry中。
推模式
生产环境下一般更常用的是push模式的数据源。对于push模式的数据源,如远程配置中心(ZooKeeper, Nacos, Apollo等等),推送的操作不应由Sentinel客户端进行,而应该经控制台统一进行管理,直接进行推送,数据源仅负责获取配置中心推送的配置并更新到本地。因此推送规则正确做法应该是配置中心控制台/Sentinel控制台 → 配置中心 → Sentinel数据源 → Sentinel,而不是经Sentinel数据源推送至配置中心。这样的流程就非常清晰了:
nacos设置
- 先新增nacos对应的配置
pom.xml
<?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>springcloudalibaba</artifactId>
<groupId>com.cxy.springcloud</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>order</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--Nacos做配置中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--添加openfeign依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!--sentinel启动器-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--sentinel配置中心控制台推送-->
<!--以nacos作为sentinel数据源的依赖-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
</dependencies>
</project>
- 在以前的基础上,新增了该接口
application.yml
server:
port: 8015
spring:
application:
name: order-service
cloud:
# nacos:
# server-addr: 127.0.0.1:8848
# discovery:
# name: nacos
# password: nacos
# namespace: public
loadbalancer:
ribbon:
enabled: false
sentinel:
transport:
dashboard: 127.0.0.1:8080
web-context-unify: false #默认将调用链路收起来
datasource:
flow-ds:
nacos:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
namespace: public
dataId: ${spring.application.name}-flow
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
####设置springboot级别
logging:
level:
com.cxy.order.feign.StockFeignService: debug
feign:
client:
config:
stock-servic: ###对应微服务
###链接超时时间 默认2s
connectTimeout: 5000
### 请求处理超时时间 默认5s
readTimeout: 10000
##添加feign对sentinel的兼容
sentinel:
enabled: true
- flow-ds 是随便写的,其他的有讲究
支持很多的数据库,这里我们使用的nacos,所以用nacos的配置
ctrl+shift+\ 输入DataSourcePropertiesConfiguration,找到nacois得代码,打开
- 可以进行参考配置
有个问题:不知道为什么,需要先调用一次服务的接口后,才能看到,我们之前在nacos里面的配置,同步到sentinel中,怀疑是不是缓存
到这里我们就实现sentinel配置持久化了
存在几个问题:
1.在nacos配置很复杂
2、在sentinel中变更后,怎么同步到nacos里面来,有知道朋友,可以留言评论