1、Sentinel 控制台配合项目实战
1.1 尝试对访问路径限流
1.打开刚才的“簇点链路”菜单,尝试对访问路径限流:
资源名:唯一名称,默认请求路径。
针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)。阈值类型
QPS(Query Per Second):每秒请求数,就是说服务器在一秒的时间内处理了多少个请求。
线程数:当调用该api的线程数达到阈值的时候,进行限流。
流控模式
直接:api达到限流条件时,直接限流。
关联:当关联的资源达到阈值时就限流自己。A接口与B接口关联,当B接口到达阈值,让A接口限流起到保护B接口的作用。 例如支付接口与下单接口,当支付接口到达阈值,让下单接口限流,起到保护支付接口的作用。
链路:只记录指定链路上的流量(指定资源入口资源进来的流量,如果达到阈值,就进行限流)。
流控效果
快速失败:是默认的流量控制方式,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。
Warm up:即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
排队等候:会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。
2.我设置的 QPS的值是1,直接api,快速失败,所以 1秒内去多次请求 /api/member/service:
#### 请求测试
GET http://localhost:10801/api/member/service
Accept: */*
Cache-Control: no-cache
请求得到结果:
Blocked by Sentinel (flow limiting)
事实证明已经被 Sentinel 限制访问,直接快速失败了。
1.2. 尝试对服务资源限流
首先,为了防止多规则的干扰,将刚才设置的 访问路径限流规则 删去。
1.打开刚才的“簇点链路”菜单,尝试对服务资源限流:
QPS(Query Per Second):每秒请求数,就是说服务器在一秒的时间内处理了多少个请求。
2.我设置的 QPS的值是1,直接api,快速失败,所以 1秒内去多次调用 memberService.sayHello():
请求测试
GET http://localhost:10801/api/member/service
Accept: /
Cache-Control: no-cache
请求得到结果:
I am sorry, Member!
结果为什么没有报错?居然能正常返回?仔细的同学会发现都是我设置了降级方法 sayHelloFail() 的功劳:
@SentinelResource(value = "sayHello", fallback = "sayHelloFail")
public String sayHello() {
return "Hello, Member! ";
}
public String sayHelloFail() {
return "I am sorry, Member! ";
}
1.3 尝试对异常服务熔断
1.打开刚才的“簇点链路”菜单,尝试对异常服务熔断:
熔断策略
慢调用比例:选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
异常比例:当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
异常数:当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
2.我们对代码进行一点小改造,并且重启项目:
@RequestMapping("/service")
public String service(String name) throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(400);
return memberService.sayHello(name);
}
3.我设置的 最大容忍响应时间是 200ms,比例是 50%,代码中强制延迟 400ms,也就是 100% 超时,并且设置了在单位时间内 5 次请求有 50% 是这种情况才会熔断,所以 1 秒内去超过 5 次请求 /api/member/service:
#### 请求测试
GET http://localhost:10801/api/member/service
Accept: */*
Cache-Control: no-cache
请求得到结果:
Blocked by Sentinel (flow limiting)
事实证明已经被 Sentinel 限制访问,异常服务熔断了。
4.我设置的 熔断时间为 2 秒,在 2 秒后再去请求 2 次 /api/member/service:
#### 请求测试
GET http://localhost:10801/api/member/service
Accept: */*
Cache-Control: no-cache
请求得到结果:
Hello, Member!
Blocked by Sentinel (flow limiting)
结果为什么是这样?不是才请求 2 次吗?而且 2 秒后不是应该放行了吗?因为我代码中强制延迟 400ms,2 秒后的请求还是超时,第一次成功是因为需要统计数据。
Sentinel 经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
5.类似 4.2章节 的情形,如果我把代码中强制延迟 400ms 写在资源服务中:
@SentinelResource(value = "sayHello", fallback = "sayHelloFail")
public String sayHello(String name) throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(400);
return "Hello, Member! " + name;
}
public String sayHelloFail(String name) {
return "I am sorry, Member! " + name;
}
一样的设置,一样的请求, 1 秒内去超过 5 次请求 /api/member/service:
#### 请求测试
GET http://localhost:10801/api/member/service
Accept: */*
Cache-Control: no-cache
请求得到结果:
I am sorry, Member!
事实证明已经被 Sentinel 限制访问,异常服务虽然已经被熔断,但是设置了降级方法 sayHelloFail() 还是能正常返回结果。
1.4 尝试对热点参数限流
热点就是经常访问的数据;
比如商品接口的 QPS 限定的是 100,有一天要秒杀,带着秒杀商品 ID 的请求的 QPS 限制在 50,这样还能有 50 的 QPS 用来访问其他的商品;
我们先对代码进行一点小改造,加一个请求参数 name**,并且重启项目**:
@Service
public class MemberService {
@SentinelResource(value = "sayHello", fallback = "sayHelloFail")
public String sayHello(String name) {
return "Hello, Member! " + name;
}
public String sayHelloFail(String name) {
return "I am sorry, Member! " + name;
}
}
@RestController
@RequestMapping
public class HelloController {
@Resource
private MemberService memberService;
@RequestMapping("/service")
public String service(String name) {
return memberService.sayHello(name);
}
}
2.打开的“热点规则”菜单,新增一个资源名为“sayHello”的热点规则:
参数索引 设置 0,表示第一个请求参数
单机阈值 设置 10,统计窗口时长 设置 1
参数值 设置 字符串 baicai,限流阈值 设置 1
总的来说,就是同样的请求 /api/member/service?name=xxx, 当参数传 baicai 时,QPS 例外控制为 1,而参数传别的任何值,QPS 控制为 10。
3.尝试 1秒内去多次请求 /api/member/service?name=baicai:
#### 请求测试
GET http://localhost:10801/api/member/service?name=baicai
Accept: */*
Cache-Control: no-cache
请求得到结果:
I am sorry, Member! baicai
4.尝试 1秒内去多次请求 /api/member/service?name=luobo:
#### 请求测试
GET http://localhost:10801/api/member/service?name=luobo
Accept: */*
Cache-Control: no-cache
请求得到结果:
Hello, Member! luobo
事实证明当参数为 baicai 时,QPS 超过 1 就被限制访问,但是设置了降级方法 sayHelloFail() 还是能正常返回结果。
1.5. 尝试黑白名单控制
很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源访问控制(黑白名单控制)的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。
测试结果和以上类似,这里就不做过多阐述了。看到这里,Sentinel 的强大好用是否已经征服你了呢?