目录
服务雪崩
什么是服务雪崩
在服务调用链路中, 服务提供者不可用, 导致服务调用者不可用, 间接让上上游也不可用, 这个不可用逐渐放大的过程, 叫做服务雪崩
服务不可用原因
- 内存泄漏
- 大流量请求, 超过正常承受qps
- 缓存击穿, 大量直接打到数据库
- 硬件损坏
解决方案
-
超时机制
-
限流
-
资源隔离(线程池/信号量隔离)
-
熔断降级
技术选型对比
Sentinel
介绍
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
官方文档: https://sentinelguard.io/zh-cn/docs/introduction.html
优点
- 丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。
- 完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
- 广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
- 完善的 SPI 扩展点: Sentinel 提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。例如定制规则管理、适配数据源等。
核心概念
资源
资源可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。
规则
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。一个资源可以对应多个规则, 一个规则只能对应一个资源.
代码实战
API实现
- 引入maven依赖
XML
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.6</version>
</dependency>
- 接口实现
java
@RestController
@Slf4j
public class HelloController {
// 定义资源名称
private static final String RESOURCE_NAME = "HelloWorld";
@RequestMapping(value = "/hello")
public String hello() {
// try catch包起来的代码块 就是资源
try (Entry entry = SphU.entry(RESOURCE_NAME)) {
// 被保护的逻辑
log.info("hello world");
return "hello world";
} catch (BlockException ex) {
// 自定义流控逻辑
log.info("blocked!");
return "被流控了";
}
}
/**
* 定义流控规则
*/
@PostConstruct
private static void initFlowRules(){
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
//设置受保护的资源
rule.setResource(RESOURCE_NAME);
// 设置流控规则 QPS
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 设置受保护的资源阈值, qps>1 就被流控
rule.setCount(1);
rules.add(rule);
// 加载配置好的规则
FlowRuleManager.loadRules(rules);
}
}
存在缺点: 代码侵入太强, 不够灵活
@SentinelResource注解实现
- 引入pom依赖, sentinel核心jar和切面jar
XML
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.8.6</version>
</dependency>
- 注入切面类
java
@Configuration
public class SentinelAspectConfiguration {
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
- 设置流控规则注解, 注解定义资源以及降级逻辑
java
@PostConstruct
private static void initFlowRules(){
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
//设置受保护的资源
rule.setResource(RESOURCE_NAME);
// 设置流控规则 QPS
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 设置受保护的资源阈值
rule.setCount(3);
rules.add(rule);
// 加载配置好的规则
FlowRuleManager.loadRules(rules);
}
@SentinelResource(value = RESOURCE_NAME,
blockHandler = "handleException",blockHandlerClass = ExceptionUtil.class,
fallback = "fallbackException",fallbackClass = ExceptionUtil.class)
@RequestMapping("/hello2")
public String hello2() {
int i = 1 / 0;
return "helloworld ";
}
java
public class ExceptionUtil {
public static String fallbackException(Throwable t){
return "===被异常降级啦===";
}
public static String handleException(BlockException ex){
return "===被限流啦===";
}
}
Sentinel控制台
启动控制台服务
官方文档:https://sentinelguard.io/zh-cn/docs/dashboard.html
- 下载控制台
https://github.com/alibaba/Sentinel/releases/download/1.8.7/sentinel-dashboard-1.8.7.jar
- 启动控制台
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.7.jar
- 登录控制台
访问http://localhost:8080/#/login ,默认用户名密码: sentinel/sentinel
java应用接入控制台
- 引入sentinel通信jar
XML
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.6</version>
</dependency>
- java应用增加启动参数, 启动服务
-Dproject.name=kk-sentinel-demo -Dcsp.sentinel.dashboard.server=localhost:8080 -Dcsp.sentinel.api.port=8719
- 访问流控接口http://localhost:8800/hello, 登录控制台检查
- 控制台修改流控规则, 接口测试, 实时生效
- get接口查看流控规则, url = http://localhost:8720/getRules?type=flow
微服务接入Sentinel
- 引入pom依赖
XML
<!--sentinel -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- 对外暴露的 Endpoint -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
- 修改yml配置
cs
server:
port: 8800
feign:
sentinel:
enabled: true #开启Sentinel 对 Feign 的支持
spring:
application:
name: mall-user
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
sentinel:
transport:
# 添加sentinel的控制台地址
dashboard: 127.0.0.1:8080
# 指定应用与Sentinel控制台交互的端口,应用会起一个HttpServer占用该端口
# port: 8719
#暴露actuator端点 http://localhost:8800/actuator/sentinel
management:
endpoints:
web:
exposure:
include: '*'
- 对URL流控
java
// 对URL流控
@RequestMapping("/info/{id}")
@SentinelResource(value = "userinfo", blockHandler = "handleException")
public R info(@PathVariable("id") Integer id){
UserEntity user = userService.getById(id);
if(id==4){
throw new IllegalArgumentException("异常参数");
}
return R.ok().put("user", user);
}
// 对子方法流控
@SentinelResource(value = "getUser",blockHandler = "handleException")
public UserEntity getById(Integer id) {
return userDao.getById(id);
}
- 接入openFeign 熔断降级
java
@FeignClient(value = "mall-order",path = "/order",fallbackFactory = FallbackOrderFeignServiceFactory.class)
public interface OrderFeignService {
@RequestMapping("/findOrderByUserId/{userId}")
public R findOrderByUserId(@PathVariable("userId") Integer userId);
}
@Component
public class FallbackOrderFeignServiceFactory implements FallbackFactory<OrderFeignService> {
@Override
public OrderFeignService create(Throwable throwable) {
return new OrderFeignService() {
@Override
public R findOrderByUserId(Integer userId) {
return R.error(-1,"=======服务降级了========");
}
};
}
}