当前位置:   article > 正文

Springboot应用整合Sentinel实现限流、熔断、降级笔记_springboot sentinel

springboot sentinel

可以使用官方的sentinel

也可使用进行持久化改造后的Sentinel ,本文基于此进行记录。Sentinel持久化到Nacosicon-default.png?t=N2N8https://blog.csdn.net/chenjian723122704/article/details/130098896

Sentinel版本为 1.8.6 

Nacos版本为 2.2.0

关于网关限流、限流和熔断,我自己总结出来了一套规则,有更好的意见希望大家指正。

  1. 网关只做限流,不做熔断。
  2. 普通服务被请求,比如客户请求我们的api服务,此时做限流。
  3. 普通服务调用内部服务,比如API服务,调用账单查询服务,需要做两部操作。1)在api服务的配置文件打开 feign.sentinel.enable=true;2)账单查询服务需要配置熔断规则。  当api的请求账单服务的接口达到熔断的阈值时,api下次再有请求,就会直接进入降级方法,或者抛出异常。

1.启动 Sentinel 服务

java -jar sentinel-dashboard-1.8.6.jar --server.port=8800

2.普通应用的限流策略

新建一个Springboot应用,创建一个用于测试的Controller

  1. /**
  2. * 测试
  3. * @author chenjian
  4. * @date 2022/12/30
  5. * @version 1.0
  6. */
  7. @Slf4j
  8. @RefreshScope
  9. @RestController
  10. @RequestMapping("/test")
  11. public class Test {
  12. @GetMapping("/test")
  13. public R test() {
  14. return R.ok();
  15. }
  16. }
  17. /**
  18. * 返回数据
  19. *
  20. * @author jianchene0
  21. */
  22. @Slf4j
  23. public class R extends HashMap<String, Object> {
  24. private static final long serialVersionUID = 1L;
  25. public R() {
  26. put("code", 0);
  27. put("msg", "success");
  28. }
  29. public static R error() {
  30. return error(500, "未知异常,请联系管理员");
  31. }
  32. public static R error(String msg) {
  33. return error(500, msg);
  34. }
  35. public static R error(int code, String msg) {
  36. R r = new R();
  37. r.put("code", code);
  38. r.put("msg", msg);
  39. log.error("失败信息: "+ code + " ---- " + msg);
  40. return r;
  41. }
  42. public static R ok(String msg) {
  43. R r = new R();
  44. r.put("msg", msg);
  45. return r;
  46. }
  47. public static R ok(Map<String, Object> map) {
  48. R r = new R();
  49. r.putAll(map);
  50. return r;
  51. }
  52. public static R ok() {
  53. return new R();
  54. }
  55. @Override
  56. public R put(String key, Object value) {
  57. super.put(key, value);
  58. return this;
  59. }
  60. /**
  61. * 检查是否OK
  62. * @return
  63. */
  64. public boolean isOk() {
  65. return (int)this.get("code") == 0;
  66. }
  67. }

pom文件中引入依赖

  1. <!-- Sentinel流量监控、限流、熔断降级处理 -->
  2. <dependency>
  3. <groupId>com.alibaba.cloud</groupId>
  4. <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  5. </dependency>

若使用改造的支持持久化的Sentinel,还需要引入依赖

  1. <!-- 引入Nacos数据源 -->
  2. <dependency>
  3. <groupId>com.alibaba.csp</groupId>
  4. <artifactId>sentinel-datasource-nacos</artifactId>
  5. <version>${sentinel.version}</version>
  6. </dependency>

 yaml引入sentinel配置、nacos配置及其他配置

  1. # Tomcat
  2. server:
  3. tomcat:
  4. uri-encoding: UTF-8
  5. port: 9803
  6. servlet:
  7. context-path: /
  8. spring:
  9. application:
  10. name: api
  11. cloud:
  12. nacos:
  13. # nacos.core.auth.enabled=true 开启权限验证
  14. discovery:
  15. # nacos地址
  16. server-addr: 127.0.0.1:8848
  17. username: nacos
  18. password: nacos
  19. namespace:
  20. group: DEFAULT_GROUP
  21. metadata:
  22. management:
  23. context-path: ${server.servlet.context-path}/actuator
  24. config:
  25. server-addr: 127.0.0.1:8848
  26. username: nacos
  27. password: nacos
  28. #data-id后缀
  29. file-extension: yaml
  30. # 分组名称
  31. namespace:
  32. group: DEFAULT_GROUP
  33. encode: UTF-8
  34. # 修改后自动加载
  35. refresh-enabled: true
  36. # 允许nacos服务端向本地同步配置
  37. enable-remote-sync-config: true
  38. sentinel:
  39. eager: true #是否开启网关限流,默认true
  40. transport:
  41. # 添加sentinel的控制台地址
  42. dashboard: 127.0.0.1:8800
  43. #指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer
  44. # port: 8719
  45. web-context-unify: false # 默认将调用链路收敛,导致链路流控效果无效
  46. # 持久化配置
  47. datasource:
  48. flow-rule: # 唯一名称可自定义
  49. nacos:
  50. # 设置Nacos的连接地址、命名空间和Group ID
  51. server-addr: ${spring.cloud.nacos.discovery.server-addr}
  52. username: ${spring.cloud.nacos.discovery.username}
  53. password: ${spring.cloud.nacos.discovery.password}
  54. namespace: # 为空,使用默认的public
  55. # 设置Nacos中配置文件的命名规则
  56. dataId: ${spring.application.name}-flow-rules
  57. groupId: SENTINEL_GROUP
  58. data-type: json
  59. # 必填的重要字段,指定当前规则类型是"限流"
  60. rule-type: flow
  61. degrade-rule: # 唯一名称可自定义
  62. nacos:
  63. # 设置Nacos的连接地址、命名空间和Group ID
  64. server-addr: ${spring.cloud.nacos.discovery.server-addr}
  65. username: ${spring.cloud.nacos.discovery.username}
  66. password: ${spring.cloud.nacos.discovery.password}
  67. namespace: # 为空,使用默认的public
  68. # 设置Nacos中配置文件的命名规则
  69. dataId: ${spring.application.name}-degrade-rules
  70. groupId: SENTINEL_GROUP
  71. data-type: json
  72. # 必填的重要字段,指定当前规则类型是"限流"
  73. rule-type: degrade
  74. system-rule: # 唯一名称可自定义
  75. nacos:
  76. # 设置Nacos的连接地址、命名空间和Group ID
  77. server-addr: ${spring.cloud.nacos.discovery.server-addr}
  78. username: ${spring.cloud.nacos.discovery.username}
  79. password: ${spring.cloud.nacos.discovery.password}
  80. namespace: # 为空,使用默认的public
  81. # 设置Nacos中配置文件的命名规则
  82. dataId: ${spring.application.name}-system-rules
  83. groupId: SENTINEL_GROUP
  84. data-type: json
  85. # 必填的重要字段,指定当前规则类型是"限流"
  86. rule-type: system
  87. param-flow-rule: # 唯一名称可自定义
  88. nacos:
  89. # 设置Nacos的连接地址、命名空间和Group ID
  90. server-addr: ${spring.cloud.nacos.discovery.server-addr}
  91. username: ${spring.cloud.nacos.discovery.username}
  92. password: ${spring.cloud.nacos.discovery.password}
  93. namespace: # 为空,使用默认的public
  94. # 设置Nacos中配置文件的命名规则
  95. dataId: ${spring.application.name}-param-flow-rules
  96. groupId: SENTINEL_GROUP
  97. data-type: json
  98. # 必填的重要字段,指定当前规则类型是"限流"
  99. rule-type: param-flow
  100. authority-rule: # 唯一名称可自定义
  101. nacos:
  102. # 设置Nacos的连接地址、命名空间和Group ID
  103. server-addr: ${spring.cloud.nacos.discovery.server-addr}
  104. username: ${spring.cloud.nacos.discovery.username}
  105. password: ${spring.cloud.nacos.discovery.password}
  106. namespace: # 为空,使用默认的public
  107. # 设置Nacos中配置文件的命名规则
  108. dataId: ${spring.application.name}-authority-rules
  109. groupId: SENTINEL_GROUP
  110. data-type: json
  111. # 必填的重要字段,指定当前规则类型是"限流"
  112. rule-type: authority
  113. feign:
  114. sentinel:
  115. enabled: true #sentinel是不会对feign进行监控的,需要开启配置

此外,定义Sentinel的异常处理器,使得当被限流、降级时,可以同一返回异常信息

  1. import com.ah.ums.common.constants.ResCodeEnum;
  2. import com.ah.ums.common.utils.R;
  3. import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
  4. import com.alibaba.csp.sentinel.slots.block.BlockException;
  5. import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
  6. import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
  7. import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
  8. import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
  9. import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
  10. import com.alibaba.fastjson.JSON;
  11. import com.fasterxml.jackson.databind.ObjectMapper;
  12. import org.springframework.stereotype.Component;
  13. import javax.servlet.http.HttpServletRequest;
  14. import javax.servlet.http.HttpServletResponse;
  15. /**
  16. * sentinel 限流降级后异常处理
  17. * @author jianchen
  18. */
  19. @Component
  20. public class SentinelExceptionHandler implements BlockExceptionHandler {
  21. @Override
  22. public void handle(HttpServletRequest request, HttpServletResponse response, BlockException ex) throws Exception {
  23. ResCodeEnum resCodeEnum = null;
  24. if (ex instanceof FlowException) {
  25. resCodeEnum = ResCodeEnum.SENTINEL_FLOW_ERROR;
  26. } else if (ex instanceof DegradeException) {
  27. resCodeEnum = ResCodeEnum.SENTINEL_DEGRADE_ERROR;
  28. } else if (ex instanceof ParamFlowException) {
  29. resCodeEnum = ResCodeEnum.SENTINEL_PARAM_FLOW_ERROR;
  30. } else if (ex instanceof SystemBlockException) {
  31. resCodeEnum = ResCodeEnum.SENTINEL_SYSTEM_ERROR;
  32. } else if (ex instanceof AuthorityException) {
  33. resCodeEnum = ResCodeEnum.SENTINEL_AUTHORITY_ERROR;
  34. }
  35. // http状态码
  36. response.setCharacterEncoding("utf-8");
  37. response.setHeader("Content-Type", "application/json;charset=utf-8");
  38. response.setContentType("application/json;charset=utf-8");
  39. String errJson = JSON.toJSONString(R.error(resCodeEnum.getCode(), resCodeEnum.getMsg()));
  40. new ObjectMapper().writeValue(response.getWriter(), errJson);
  41. }
  42. }
  43. /**
  44. * 返回码枚举
  45. *
  46. * @author chenjian
  47. * @version 1.0
  48. * @date 2022/11/11
  49. */
  50. public enum ResCodeEnum {
  51. ok(0, "成功"),
  52. NO_PARAM(201, "传入参数缺失,请检查"),
  53. ERR_PARAM(202, "传入参数异常,请检查"),
  54. VALID_FAIL_PARAM(203, "参数校验异常"),
  55. SENTINEL_FLOW_ERROR(427, "请求过于频繁,被限流了"),
  56. SENTINEL_DEGRADE_ERROR(428, "请求过于频繁,被降级了"),
  57. SENTINEL_PARAM_FLOW_ERROR(429, "热点数据请求过于频繁"),
  58. SENTINEL_SYSTEM_ERROR(430, "请求过于频繁,触发系统限制"),
  59. SENTINEL_AUTHORITY_ERROR(431, "授权规则不通过"),
  60. UNKNOWN(999, "操作失败!!");
  61. private Integer code;
  62. private String msg;
  63. ResCodeEnum(Integer code, String msg) {
  64. this.code = code;
  65. this.msg = msg;
  66. }
  67. public Integer getCode() {
  68. return code;
  69. }
  70. public String getMsg() {
  71. return msg;
  72. }
  73. public static ResCodeEnum getByCode(Integer code) {
  74. if (code == null) {
  75. return null;
  76. }
  77. for (ResCodeEnum resMsgEnum : values()) {
  78. if(resMsgEnum.code.equals(code)) {
  79. return resMsgEnum;
  80. }
  81. }
  82. return UNKNOWN;
  83. }
  84. }

至此,普通服务改造完成,可以使用Sentinel进行监控了

3.测试

1.分别启动 nacos sentinel 以及SpringBoot应用程序。

2.首先访问Springboot的controller 

http://localhost:9803/test/test

 

访问成功后 ,会在Sentinel的控制台看到有api的请求进来了

3.点击流控新增一条流控规则

 

 此时会发现nacos中会自动增肌了一条配置,里面记录了api的流控规则

 

 我们接着测试,在浏览器不停刷新刚刚的链接,会出现限流的提示,此时,我们的url就被限流了

 

 3.熔断规则

假设有两个服务,都是按照第2节配置了Sentinel的依赖、yaml。:

  • API 服务是对外服务,供第三方调研;
  • service 服务是内部服务,供内部调用;

一般的规则时 API服务通过openFeign调用service提供的服务。使用feign注意的是 API 一定要配置  feign.sentinel.enable=true ,否则熔断效果不会生效

在 Feign定义处,加上fallback。

 对应的fallback

 

在Sentinel增加一条熔断规则,2秒内溢出比例达到0.2就进行熔断。

 

 

我们在服务内部加上 int a = 10/0;然后再让API请求查询用户分页数据。就会出发熔断,进入回调方法。

 

4.网关限流

网关限流与第2节中的配置基本类似,不过需要增加网关相关的依赖和配置,以及增加启动参数。

4.1 网关限流的依赖,增加了一个依赖

  1. <!-- 引入Nacos数据源 -->
  2. <dependency>
  3. <groupId>com.alibaba.csp</groupId>
  4. <artifactId>sentinel-datasource-nacos</artifactId>
  5. <version>${sentinel.version}</version>
  6. </dependency>
  7. <!-- Sentinel流量监控、限流、熔断降级处理 -->
  8. <dependency>
  9. <groupId>com.alibaba.cloud</groupId>
  10. <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  11. </dependency>
  12. <!-- gateway网关整合sentinel进行限流降级 -->
  13. <dependency>
  14. <groupId>com.alibaba.cloud</groupId>
  15. <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
  16. </dependency>

4.2 网关需要增加网关规则的持久化依赖

网关持久化依赖

  1. spring:
  2. cloud:
  3. sentinel:
  4. datasource:
  5. gw-flow-rule: # 唯一名称可自定义
  6. nacos:
  7. # 设置Nacos的连接地址、命名空间和Group ID
  8. server-addr: ${spring.cloud.nacos.discovery.server-addr}
  9. username: ${spring.cloud.nacos.discovery.username}
  10. password: ${spring.cloud.nacos.discovery.password}
  11. namespace: # 为空,使用默认的public
  12. # 设置Nacos中配置文件的命名规则
  13. dataId: ${spring.application.name}-gw-flow-rules
  14. groupId: SENTINEL_GROUP
  15. data-type: json
  16. # 必填的重要字段,指定当前规则类型是"限流"
  17. rule-type: gw-flow
  18. gw-api-group: # 唯一名称可自定义
  19. nacos:
  20. # 设置Nacos的连接地址、命名空间和Group ID
  21. server-addr: ${spring.cloud.nacos.discovery.server-addr}
  22. username: ${spring.cloud.nacos.discovery.username}
  23. password: ${spring.cloud.nacos.discovery.password}
  24. namespace: # 为空,使用默认的public
  25. # 设置Nacos中配置文件的命名规则
  26. dataId: ${spring.application.name}-gw-api-groups
  27. groupId: SENTINEL_GROUP
  28. data-type: json
  29. # 必填的重要字段,指定当前规则类型是"限流"
  30. rule-type: gw-api-group

完整的网关yaml配置

  1. # Tomcat
  2. server:
  3. tomcat:
  4. uri-encoding: UTF-8
  5. port: 9803
  6. servlet:
  7. context-path: /
  8. spring:
  9. application:
  10. name: api
  11. cloud:
  12. gateway:
  13. # 路由数组:指当请求满足什么样的断言时,转发到哪个服务上
  14. routes:
  15. # 配置断言路由到 API 服务中
  16. # 路由标识,要求唯一,名称任意
  17. - id: api
  18. uri: lb://api # 使用了lb形式,从注册中心负载均衡的获取uri
  19. # 设置断言
  20. predicates:
  21. # 断言,满足 /api/** 路径的请求都会被路由到 API 服务中
  22. - Path=/api/**
  23. filters:
  24. - StripPrefix=1 # 去除url的第一个前缀,本规则是去除/api
  25. nacos:
  26. # nacos.core.auth.enabled=true 开启权限验证
  27. discovery:
  28. # nacos地址
  29. server-addr: 127.0.0.1:8848
  30. username: nacos
  31. password: nacos
  32. namespace:
  33. group: DEFAULT_GROUP
  34. metadata:
  35. management:
  36. context-path: ${server.servlet.context-path}/actuator
  37. config:
  38. server-addr: 127.0.0.1:8848
  39. username: nacos
  40. password: nacos
  41. #data-id后缀
  42. file-extension: yaml
  43. # 分组名称
  44. namespace:
  45. group: DEFAULT_GROUP
  46. encode: UTF-8
  47. # 修改后自动加载
  48. refresh-enabled: true
  49. # 允许nacos服务端向本地同步配置
  50. enable-remote-sync-config: true
  51. sentinel:
  52. eager: true #是否开启网关限流,默认true
  53. #配置限流之后的响应内容
  54. scg:
  55. fallback:
  56. # 两种模式:一种是response返回文字提示信息,一种是redirect,重定向跳转
  57. mode: response
  58. # 响应的状态
  59. response-status: 426
  60. # 响应体
  61. response-body: '{"code": 426,"message": "限流了,稍后重试!"}'
  62. transport:
  63. # 添加sentinel的控制台地址
  64. dashboard: 127.0.0.1:8800
  65. #指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer
  66. # port: 8719
  67. web-context-unify: false # 默认将调用链路收敛,导致链路流控效果无效
  68. # 持久化配置
  69. datasource:
  70. flow-rule: # 唯一名称可自定义
  71. nacos:
  72. # 设置Nacos的连接地址、命名空间和Group ID
  73. server-addr: ${spring.cloud.nacos.discovery.server-addr}
  74. username: ${spring.cloud.nacos.discovery.username}
  75. password: ${spring.cloud.nacos.discovery.password}
  76. namespace: # 为空,使用默认的public
  77. # 设置Nacos中配置文件的命名规则
  78. dataId: ${spring.application.name}-flow-rules
  79. groupId: SENTINEL_GROUP
  80. data-type: json
  81. # 必填的重要字段,指定当前规则类型是"限流"
  82. rule-type: flow
  83. degrade-rule: # 唯一名称可自定义
  84. nacos:
  85. # 设置Nacos的连接地址、命名空间和Group ID
  86. server-addr: ${spring.cloud.nacos.discovery.server-addr}
  87. username: ${spring.cloud.nacos.discovery.username}
  88. password: ${spring.cloud.nacos.discovery.password}
  89. namespace: # 为空,使用默认的public
  90. # 设置Nacos中配置文件的命名规则
  91. dataId: ${spring.application.name}-degrade-rules
  92. groupId: SENTINEL_GROUP
  93. data-type: json
  94. # 必填的重要字段,指定当前规则类型是"限流"
  95. rule-type: degrade
  96. system-rule: # 唯一名称可自定义
  97. nacos:
  98. # 设置Nacos的连接地址、命名空间和Group ID
  99. server-addr: ${spring.cloud.nacos.discovery.server-addr}
  100. username: ${spring.cloud.nacos.discovery.username}
  101. password: ${spring.cloud.nacos.discovery.password}
  102. namespace: # 为空,使用默认的public
  103. # 设置Nacos中配置文件的命名规则
  104. dataId: ${spring.application.name}-system-rules
  105. groupId: SENTINEL_GROUP
  106. data-type: json
  107. # 必填的重要字段,指定当前规则类型是"限流"
  108. rule-type: system
  109. param-flow-rule: # 唯一名称可自定义
  110. nacos:
  111. # 设置Nacos的连接地址、命名空间和Group ID
  112. server-addr: ${spring.cloud.nacos.discovery.server-addr}
  113. username: ${spring.cloud.nacos.discovery.username}
  114. password: ${spring.cloud.nacos.discovery.password}
  115. namespace: # 为空,使用默认的public
  116. # 设置Nacos中配置文件的命名规则
  117. dataId: ${spring.application.name}-param-flow-rules
  118. groupId: SENTINEL_GROUP
  119. data-type: json
  120. # 必填的重要字段,指定当前规则类型是"限流"
  121. rule-type: param-flow
  122. authority-rule: # 唯一名称可自定义
  123. nacos:
  124. # 设置Nacos的连接地址、命名空间和Group ID
  125. server-addr: ${spring.cloud.nacos.discovery.server-addr}
  126. username: ${spring.cloud.nacos.discovery.username}
  127. password: ${spring.cloud.nacos.discovery.password}
  128. namespace: # 为空,使用默认的public
  129. # 设置Nacos中配置文件的命名规则
  130. dataId: ${spring.application.name}-authority-rules
  131. groupId: SENTINEL_GROUP
  132. data-type: json
  133. # 必填的重要字段,指定当前规则类型是"限流"
  134. rule-type: authority
  135. gw-flow-rule: # 唯一名称可自定义
  136. nacos:
  137. # 设置Nacos的连接地址、命名空间和Group ID
  138. server-addr: ${spring.cloud.nacos.discovery.server-addr}
  139. username: ${spring.cloud.nacos.discovery.username}
  140. password: ${spring.cloud.nacos.discovery.password}
  141. namespace: # 为空,使用默认的public
  142. # 设置Nacos中配置文件的命名规则
  143. dataId: ${spring.application.name}-gw-flow-rules
  144. groupId: SENTINEL_GROUP
  145. data-type: json
  146. # 必填的重要字段,指定当前规则类型是"限流"
  147. rule-type: gw-flow
  148. gw-api-group: # 唯一名称可自定义
  149. nacos:
  150. # 设置Nacos的连接地址、命名空间和Group ID
  151. server-addr: ${spring.cloud.nacos.discovery.server-addr}
  152. username: ${spring.cloud.nacos.discovery.username}
  153. password: ${spring.cloud.nacos.discovery.password}
  154. namespace: # 为空,使用默认的public
  155. # 设置Nacos中配置文件的命名规则
  156. dataId: ${spring.application.name}-gw-api-groups
  157. groupId: SENTINEL_GROUP
  158. data-type: json
  159. # 必填的重要字段,指定当前规则类型是"限流"
  160. rule-type: gw-api-group

启动网关应用,访问一次路由地址 http://localhost/api/test/test?params=1

在Sentinel的控制台能到网关的请求。

 点击流控,

  • 根据Route Id (也就是yaml中定义的routes下的id)进行限流
  • 根据API 分组进行限流,可以更细化的管理网关的限流

测试根据Route Id进行限流,先设置限流规则

刷新页面,会提示限流 http://localhost/api/test/test?params=1

 

根据API分组限流,首先需要在API管理中设置

 在流控设置中可以选择对应的分组

 删除原来的网关限流规则,使用新的规则,测试限流

 

 

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号