# 熔断限流

通过学习Jboot的熔断限流实现,本人总结了主要有以下几种限流:

  1. Jboot限流:Jboot本身自定义实现的限流方案,没有用到Sentinel限流方案
  2. Sentinel限流:配合Sentinel客户端实现系统资源访问的限流方案
  3. 网关限流:配置合Sentinel客户端实现网关代理的限流方案

# Jboot限流

这是Jboot自实现的限流方案,不依赖其它第三方限流框架。

在 Jboot 中,我们可以对某个url请求进行限流,也可以对某个java方法进行限流。 Jboot 提供了两种限流类型:

  1. TOKEN BUCKET: 令牌桶,它可以配置1秒钟内,允许执行(或请求)多少次。
  2. CONCURRENCY: 并发量,可以配置为某个url地址或者某个方法名的并发量支持多少。

注意

当要作用于某个方法名时,方法所在类对象必须在JFinal AOP的依赖注入范围内。即对象是通过AOP依赖注入的才行,否则不行。
详情AOP使用方法,请参考JFinal AOP (opens new window)Jboot AOP (opens new window)

# 如何使用

  1. 注解方式:通过在相应的方法上注解@EnableLimit来实现访问限流,示例:
@RequestMapping("/")
public class IndexController extends JbootController {

    @EnableLimit(rate = 1,fallback = "fallbackMethod")
    public void index() {
        renderText("index...." );
    }

    public void fallbackMethod(){
        renderText("fallback...");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

其中@EnableLimit参数如下: resource : 资源名称(不配置的时候默认为方法名,Controller 默认为对应的 url 映射) type:限流的类型,默认为令牌桶。 rate:限流的数值,必须配置 fallback:降级方法,若配置,此方法必须在当前的类下定义。

  1. 配置方式:通过在jboot.properties文件中配置的方法来实现访问限流,示例:
#--------Jboot 限流配置 start--------
# 是否开启限流配置,这个的开启或关闭对注解的限流配置不影响
jboot.limit.enable = true
# 限流规则,多个规则用英文逗号隔开。
# 格式:资源1:限流类型:限流值,资源2:限流类型:限流值,...
# 限流类型:
# 1. cc:并并发量,可以配置为某个url地址或者某个方法名的并发量支持多少。
# 2. tb:令牌桶,它可以配置1秒钟内,允许执行(或请求)多少次。
jboot.limit.rule = /user*:tb:1,io.jboot.aop*.get*(*):tb:1
#--------Jboot 限流配置 end--------
1
2
3
4
5
6
7
8
9
10

更多配置

# 默认的降级处理器(被限流后的处理器),默认为LimitFallbackProcesserDefault
jboot.limit.fallbackProcesser
# 被限流后,默认的http code ,默认为200
jboot.limit.defaultHttpCode = 200
# 被限流后,当ajax请求的时候,返回默认的json值
jboot.limit.defaultAjaxContent
# 被限流后,当http请求的时候,默认渲染的html文件
jboot.limit.defaultHtmlView
1
2
3
4
5
6
7
8

注意

通过查看Jboot源码 (opens new window)发现,Controller下方法限流配置只能配置url,不能配置包名方法名。否则无法生效!

# Sentinel限流

该限流方式,利用Sentinel客户端实现对系统种调用接口方法等资源的限流。结合Sentinel控制台实现面板实时配置修改限流资源的限流配置,并实时生效。

# Sentinel控制台

参考官方文档启动Sentinel控制台 (opens new window)

# 配置文件

在jboot.properties中配置:

jweb.serviceName = demo

#--------jboot sentinel限流配置 start--------
# 需要配合sentinel.properties 熔断限流配置一起配置
jboot.sentinel.enable = true
# 是否对 http 请求启用限流,默认值为 true,启用后还需要去 sentinel 后台配置
jboot.sentinel.reqeustEnable = true
# 数据源类型:redis,zookeeper,nacos,apollo
jboot.sentinel.datasource =nacos
jboot.sentinel.datasource.nacos.serverAddress=http://localhost:8848
jboot.sentinel.datasource.nacos.groupId=SENTINEL_GROUP
jboot.sentinel.datasource.nacos.dataId=${jweb.serviceName}-flow-rules
# 如果 http 被限流后跳转的页面
#jboot.sentinel.requestBlockPage=/403
# 如果 http 被限流后渲染的 json 数据,requestBlockPage 配置优先于此项
# jboot.sentinel.requestBlockJsonMap;
# 规则文件名
# jboot.sentinel.ruleFile=sentinel-rule.json
#--------jboot sentinel限流配置 end--------



#-------- sentinel.properties 熔断限流配置 start--------
# 原配置文件为 classpath:sentinel.properties,这里启动统一重定向到jboot.properties
# 注意:该配置从sentinel.properties转移到这里,所有不支持jboot的${key}值替换
# 指定项目名称,String	null,非必需,
project.name=demo
# 指定应用的类型	int	0 (APP_TYPE_COMMON)	否	1.6.0 引入
# csp.sentinel.app.type
# 单个监控日志文件的大小	long	52428800 (50MB)	否
# csp.sentinel.metric.file.single.size
# 监控日志文件的总数上限	int	6	否
# csp.sentinel.metric.file.total.count
# 最大的有效响应时长(ms),超出此值则按照此值记录	int	4900	否	1.4.1 引入
# csp.sentinel.statistic.max.rt
# SPI 加载时使用的 ClassLoader,默认为给定类的 ClassLoader	String	default	否	若配置 context 则使用 thread context ClassLoader。1.7.0 引入
# csp.sentinel.spi.classloader
# Sentinel控制台服务地址
csp.sentinel.dashboard.server=localhost:8080
# 心跳包发送周期,单位毫秒 long,默认 null,非必需,若不进行配置,则会从相应的 HeartbeatSender 中提取默认值
# csp.sentinel.heartbeat.interval.ms=
# 本地启动 HTTP API Server 的端口号,int,默认值:8719,非必需,若端口冲突会自动向下探测可用的端口。
csp.sentinel.api.port=8720
# 指定心跳包中本机的 IP,String	- 默认值:空, 若不指定则通过 HostNameUtil 解析;该配置项多用于多网卡环境
# csp.sentinel.heartbeat.client.ip=
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

其中为了支持一机多网卡时准确识别出ip地址,特fork了官方代码 (opens new window),添加网卡过滤功能,更新后的Sentinel为:https://github.com/imlzw/Sentinel (opens new window),添加的配置如下:

# 指定心跳包中本机IP获取时忽略的网口关键字(忽略大小写)
csp.sentinel.heartbeat.client.net.ignoredInterfaces=veth,docker,virtual
# 指定心跳包中本机IP获取时优先网段配置
csp.sentinel.heartbeat.client.net.preferredNetworks=192.168.2,192.168,172.27
#-------- sentinel.properties 熔断限流配置 end--------
1
2
3
4
5

注意

sentinel.properties配置在jboot.properties中时,需要在启动JVM参数上加上-Dcsp.sentinel.config.file=classpath:jboot.properties

# URL资源

jboot.sentinel.reqeustEnable = true时,自动将URL标志为资源,所有访问的url都会被记录到Sentinel控制台上,可进行降级限流配置。 非url访问,可以通过注解方法配置资源。

# 注解资源

在项目的任意目录下,使用注解 @SentinelResource 给方法进行配置,代码如下:

@RequestMapping("/sentinel")
public class SentinelController extends JbootController {

    @SentinelResource
    public void index(){
        renderText("sentinel index...");
    }
}
1
2
3
4
5
6
7
8

或者在 Service 中

public class UserService{

    // 原本的业务方法.
    @SentinelResource(blockHandler = "blockHandlerForGetUser")
    public User getUserById(String id) {
        throw new RuntimeException("getUserById command failed");
    }

    // blockHandler 函数,原方法调用被限流/降级/系统保护的时候调用
    public User blockHandlerForGetUser(String id, BlockException ex) {
        return new User("admin");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 官方接口

可以使用Sentinel的官方接口进行代码级别使用。如:

SphU.entry(targetResource, ResourceTypeConstants.COMMON_WEB, EntryType.IN);
1

# 网关限流

# Sentinel控制台

参考官方文档启动Sentinel控制台 (opens new window)

# 配置文件

在jboot.properties中配置Sentinel相关配置项:

#-------- sentinel.properties 熔断限流配置 start--------
# 原配置文件为 classpath:sentinel.properties,这里启动统一重定向到jboot.properties
# 注意:该配置从sentinel.properties转移到这里,所有不支持jboot的${key}值替换
# 指定项目名称,String	null,非必需,
project.name=gateway
# 指定应用的类型	int	0 (APP_TYPE_COMMON)	否	1.6.0 引入
# csp.sentinel.app.type
# 单个监控日志文件的大小	long	52428800 (50MB)	否
# csp.sentinel.metric.file.single.size
# 监控日志文件的总数上限	int	6	否
# csp.sentinel.metric.file.total.count
# 最大的有效响应时长(ms),超出此值则按照此值记录	int	4900	否	1.4.1 引入
# csp.sentinel.statistic.max.rt
# SPI 加载时使用的 ClassLoader,默认为给定类的 ClassLoader	String	default	否	若配置 context 则使用 thread context ClassLoader。1.7.0 引入
# csp.sentinel.spi.classloader
# Sentinel控制台服务地址
csp.sentinel.dashboard.server=localhost:8080
# 心跳包发送周期,单位毫秒 long,默认 null,非必需,若不进行配置,则会从相应的 HeartbeatSender 中提取默认值
# csp.sentinel.heartbeat.interval.ms=
# 本地启动 HTTP API Server 的端口号,int,默认值:8719,非必需,若端口冲突会自动向下探测可用的端口。
csp.sentinel.api.port=8720
# 指定心跳包中本机的 IP,String	- 默认值:空, 若不指定则通过 HostNameUtil 解析;该配置项多用于多网卡环境
# csp.sentinel.heartbeat.client.ip=
# 指定心跳包中本机IP获取时忽略的网口关键字(忽略大小写)
csp.sentinel.heartbeat.client.net.ignoredInterfaces=veth,docker,virtual
# 指定心跳包中本机IP获取时优先网段配置
csp.sentinel.heartbeat.client.net.preferredNetworks=192.168.2,192.168,172.27
#-------- sentinel.properties 熔断限流配置 end--------

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

注意

sentinel.properties配置在jboot.properties中时,需要在启动JVM参数上加上-Dcsp.sentinel.config.file=classpath:jboot.properties

然后在网关配置区添加对应的限流配置即可

# 是否启用 Sentinel 限流
jweb.gateway.{configName}.sentinelEnable = true
# Sentinel 被限流后跳转地址
jweb.gateway.{configName}.sentinelBlockPage=/block
# Sentinel 被渲染的json内容,如果配置 sentinelBlockPage,则 sentinelBlockJsonMap 配置无效
jweb.gateway.{configName}.sentinelBlockJsonMap={"block":true}
1
2
3
4
5
6

详情网关配置,请前往网关服务

然后访问网关服务地址代理地址,之后url资源信息就会同步到SentinelDashboard控制台上。进而可进行限流降级配置。

进阶-规则存储

默认Sentinel控制台配置的限流规则没有实际存储,重启Sentinel控制台后会消失。 若要持久化限流规则,可参考Sentinel动态规则扩展 (opens new window)