目录
2、Sentinel基本使用(设置规则的时候记得要重新设置,因为是保存在内存中)
一、什么是Sentinel?
Sentinel以流量为切入点,从流量控制、流量路由、熔断降级、系统自适应过载保护、热点流量防护等多个维度保护服务的稳定性。
Sentinel 具有以下特征:
- 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
- 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
- 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Apache Dubbo、gRPC、Quarkus 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。同时 Sentinel 提供 Java/Go/C++ 等多语言的原生实现。
- 完善的 SPI 扩展机制:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
二、我们为什么使用Sentinel?
【大流量请求】:在秒杀和大促开始前,如果准备不充分,瞬间大量请求会造成服务提供者的不可用。
【硬件故障】:可能为硬件损坏造成的服务器主机宕机, 网络硬件故障造成的服务提供者的不可访问。
【缓存击穿】:一般发生在缓存应用重启, 缓存失效时高并发,所有缓存被清空时,以及短时间内大量缓存失效时。大量的缓存不命中, 使请求直击后端,造成服务提供者超负荷运行,引起服务不可用。
保持系统的稳定性。
三、Sentinel和Hystrix有什么区别
四、如何使用Sentinel
1、Dashboard控制台
Sentinel 可以简单的分为 Sentinel 核心库和 Dashboard控制台。核心库不依赖 Dashboard,但是结合 Dashboard 可以取得最好的效果。
访问https://github.com/alibaba/Sentinel,把代码clone下来,通过mvn clean pakcage打包,
运行命令,
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
访问控制台,如果发现下面的界面就说明运行成功了
2、Sentinel基本使用(设置规则的时候记得要重新设置,因为是保存在内存中)
我们说的资源,可以是任何东西,服务,服务里的方法,甚至是一段代码。使用 Sentinel 来进行资源保护,主要分为几个步骤:
- 定义资源
- 定义规则
- 检验规则是否生效
方法一(基于try-catch定义资源):
package com.example.demo.gulimall34;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
@RestController
@Slf4j
public class SentinelController {
//①定义资源
private static final String RESOURCE_NAME = "hello";
@RequestMapping(value = "/hello")
public String hello() {
Entry entry = null;
try {
entry = SphU.entry(RESOURCE_NAME);
// 被保护的业务逻辑
//int i=1/0;
String str = "hello world";
log.info("=====" + str);
return str;
} catch (BlockException ex) {
// 资源访问阻止,被限流或被降级
//进行相应的处理操作
log.info("block!");
} catch (Exception ex) {
// 若需要配置降级规则,需要通过这种方式记录业务异常
Tracer.traceEntry(ex, entry);
} finally {
if (entry != null) {
entry.exit();
}
}
return null;
}
//定义规则
/**
* 设置流控规则
*/
@PostConstruct
public static void initFlowRules() {
List<FlowRule> flowRules = new ArrayList<>();
FlowRule flowRule = new FlowRule();
// 设置受保护的资源
flowRule.setResource(RESOURCE_NAME);
// 设置流控规则 QPS
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 设置受保护的资源阈值
// Set limit QPS to 20.
flowRule.setCount(1);
flowRules.add(flowRule);
// 加载配置好的规则
FlowRuleManager.loadRules(flowRules);
}
}
方法二(基于注解来定义资源):
// 原本的业务方法.
@SentinelResource(value = "findOrderByUserId",
blockHandler = "handleException", // 指定触发限流等规则时执行的方法名
fallback = "fallback" // 指定fallback降级执行的方法名
//blockHandlerClass = ExceptionUtil.class, // 指定blockHandler函数的所在类,如果在当前类可以忽略
//fallbackClass = ExceptionUtil.class, 指定fallback函数所在类,如果在当前类可以忽略
)
@RequestMapping(value = "/user/findOrderByUserId/{id}")
public String findOrderByUserId(@PathVariable("id") Integer id) {
throw new RuntimeException("getUserById command failed");
}
// blockHandler 函数,原方法调用被限流/降级/系统保护的时候调用
public String handleException(@PathVariable("id") Integer id, BlockException ex) {
return new String("admin");
}
// fallback 函数,原方法调用被降级的时候调用
public String fallback(@PathVariable("id") Integer id, Throwable e) {
return new String("admin1");
}
2)在控制台定义规则
③、进行访问,检验规则是否生效
我们设置的QPS是1,所以第二次访问就是空白
3、自定义流控相应(当不满足规则时返回我们定义的数据)
①导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
②暴露终端的位置
management.endpoints.web.exposure.include=*
③写配置文件
//自定义限流,降级异常处理对象
@Slf4j
@Configuration
public class SekillSentinelConfiguration{
public SekillSentinelConfiguration(){
WebCallbackManager.setUrlBlockHandler(new UrlBlockHandler() {
@Override
public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws IOException {
httpServletResponse.setHeader("Content-type", "text/html;charset=UTF-8");
httpServletResponse.getWriter().write("记得要设置返回值的编码哦");
}
});
}
}
④定义流控规则
⑤验证
4、熔断、降级
Sentinel 提供以下几种熔断策略:
- 慢调用比例 (
SLOW_REQUEST_RATIO
):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs
)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。 - 异常比例 (
ERROR_RATIO
):当单位统计时长(statIntervalMs
)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是[0.0, 1.0]
,代表 0% - 100%。 - 异常数 (
ERROR_COUNT
):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
远程调用的设置:
①设置配置信息,开启熔断配置
spring.cloud.sentinel.transport.port=8719
spring.cloud.sentinel.transport.dashboard=127.0.0.1:8080
spring.cloud.sentinel.transport.clientIp=127.0.0.1
feign.sentinel.enabled=true
②开启注册中心,调用者服务,被调用者服务;调用远程;如果远程调用失败,就会熔断
@Slf4j
@RestController
@RequestMapping("product/spuinfo")
public class SpuInfoController {
// 验证sentinel的使用
@GetMapping("/getSentinel")
public R getSentinel(){
List<Long> list=new ArrayList<>();
list.add(1L);
list.add(11L);
R skuHasStock = wareFeignService.getSentinel(list);
return skuHasStock;
}
}
@Component
@FeignClient(value = "guli-ware",fallback = WareFeignServiceImpl.class)
public interface WareFeignService {
@PostMapping(value = "ware/waresku/hasStock")
R getSkuHasStock(@RequestBody List<Long> SkuIds);
@RequestMapping(value = "ware/waresku/sentinel")
R getSentinel(@RequestBody List<Long> SkuIds);
}
@Slf4j
@Component
public class WareFeignServiceImpl implements WareFeignService {
@Override
public R getSkuHasStock(List<Long> SkuIds) {
log.info("到底能不能行啊");
return R.error().setData("我要使用sentinel的熔断机制啦");
}
@Override
public R getSentinel(List<Long> SkuIds) {
log.info("到底能不能行啊");
return R.error().setData("我要使用sentinel的熔断机制啦");
}
}
@Slf4j
@RestController
@RequestMapping("product/spuinfo")
public class SpuInfoController {
// 验证sentinel的使用
@GetMapping("/getSentinel")
public R getSentinel(){
List<Long> list=new ArrayList<>();
list.add(1L);
list.add(11L);
R skuHasStock = wareFeignService.getSentinel(list);
return skuHasStock;
}
}
③自定义降级
//自定义限流,降级异常处理对象
@Slf4j
@Configuration
public class SekillSentinelConfiguration{
public SekillSentinelConfiguration(){
WebCallbackManager.setUrlBlockHandler(new UrlBlockHandler() {
@Override
public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws IOException {
httpServletResponse.setHeader("Content-type", "text/html;charset=UTF-8");
httpServletResponse.getWriter().write("记得要设置返回值的编码哦");
}
});
}
}
5、 降级和熔断的关系
①什么是降级?
降级主要有三种方式:超时、不可用、限流
②什么是熔断?
熔断很好理解,就是一个断开的过程;
熔断就像是家里的保险丝一样,当电流达到一定条件时,比如保险丝能承受的电流是5A,如果你的电流达到了6A,因为保险丝承受不了这么高的电流,保险丝就会融化,这时候电路就会断开,起到了保护电器的作用;
在微服务里面也是一样,当下游的服务因为某种原因突然变得不可用或响应过慢,上游服务为了保证自己整体服务的可用性,不再继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用;
③熔断和降级的关系
降级和熔断其实就是服务安全中的2个不同的流程,在服务发生故障时,肯定是先断开(熔断)与服务的连接,然后在执行降级逻辑;
6、网关流量控制
。。。。