服务保护
服务保护
在这个项目中我们将一个单体项目拆分成了一个微服务的项目
- 远程调用(
OpenFeign):用于微服务之间的相互调用 - 服务治理(
Nacos):由于微服务之间错综复杂的相互调用,我们使用Nacos进行服务治理 - 请求路由(网关):使前端能够统一调用错综复杂的微服务
- 身份认证(网关):基本上每一个微服务都需要进行身份认证,我们在网关中统一进行身份认证,减少了每个微服务中的重复代码
- 配置管理(
Nacos):由于每一个微服务的配置都太多,配置更改后不能及时刷新,我们使用Nacos进行配置管理
雪崩问题
由于微服务较多,当某一个微服务出现故障,可能导致整个链路中所有微服务都不可用,这就是雪崩
雪崩问题产生的原因
- 微服务相互调用,服务提供者出现故障或阻塞
- 服务调用者没有做好异常处理,导致自身故障
- 调用链中的所有服务级联失败,导致整个集群故障
解决思路有哪些
- 尽量避免服务出现故障或阻塞
- 保证代码的健壮性
- 保证网络通畅
- 能应对较高的并发请求
- 服务调用者做好远程调用异常的后备方案,避免故障扩散
雪崩问题服务保护方案
请求限流
- 请求限流:限制访问微服务的请求并发量,避免服务因流量激增出现故障
- 限流器:使用限流器将访问微服务的请求进行限流 保持请求数量的平稳
线程隔离
线程隔离:也叫舱壁模式,模拟船舱隔板的防水原理,通过限定每个业务能使用的线程数量而将故障业务隔离,避免故障扩散
服务熔断
- 服务熔断:由断路器统计请求的异常比例或慢调用比例,如果超过阈值则会熔断该业务,则拦截改接口的所有请求
- 熔断期间所有请求快速失败,全部走
fallback逻辑
服务保护技术
Sentinel | Hystrix | |
|---|---|---|
| 线程隔离 | 信号量隔离 | 线程隔离/信号量隔离 |
| 熔断策略 | 基于慢调用比例或异常比例 | 基于异常比例 |
| 限流策略 | 基于QPS,支持流量整形 | 有限的支持 |
Fallback | 支持 | 支持 |
| 控制台 | 开箱即用,可配置规则,查看秒级监控,机器发现等 | 不完善 |
| 配置方式 | 基于控制台,重启后失效 | 基于注解或配置文件,永久生效 |
初识Sentinel
Sentinel是阿里开源的一款微服务流量控制组件- 官网地址:Sentinel
Sentinel 的使用可以分为两个部分:
- 核心库(
Jar包):不依赖任何框架/库,能够运行于Java 8及以上的版本的运行时环境,同时对Dubbo/Spring Cloud等框架也有较好的支持。在项目中引入依赖即可实现服务限流、隔离、熔断等功能。 - 控制台(
Dashboard):Dashboard主要负责管理推送规则、监控、管理机器信息等。
下载Sentinel客户端并在docker中运行
运行jar包启动客户端
- 端口为8090
- 名称为
sentinel-dashboard
java -Dserver.port=8090 -Dcsp.sentinel.dashboard.server=localhost:8090 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.6.jar
批处理文件sentinel启动器,带打开浏览器功能
@echo off
chcp 65001 >nul
title Sentinel Dashboard Launcher
echo ========================================
echo 启动 Sentinel Dashboard
echo ========================================
echo.
REM 检查必要文件
if not exist "sentinel-dashboard-1.8.6.jar" (
echo [错误] 未找到 sentinel-dashboard-1.8.6.jar
pause
exit
)
REM 启动服务(在新窗口中)
start "Sentinel Dashboard" cmd /k "java -Dserver.port=8090 -Dcsp.sentinel.dashboard.server=localhost:8090 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.6.jar"
echo ✓ 服务正在启动...
echo 请等待15-30秒后访问: http://localhost:8090
echo 默认账号: sentinel
echo 默认密码: sentinel
echo.
echo 将在15秒后自动打开浏览器...
echo 按 Ctrl+C 取消自动打开
timeout /t 15 /nobreak > nul
REM 打开浏览器
start "" "http://localhost:8090"
echo ✓ 浏览器已打开
echo.
echo 注意: 不要关闭Sentinel Dashboard的控制台窗口
echo 按任意键退出启动器...
pause > nul
java中加入依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
加入配置(推荐加入到Nocos)
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8090 # 配置sentinel控制台地址
簇点链路
- 定义:单机调用链路,是一次请求进入服务后经过的每一个被
Sentinel监控的资源链。 - 默认
Sentinel会监控SpringMvc的每一个http接口。限流熔断等都是针对,簇点链路中的资源设置的。而资源名默认就是接口请求的路径
开启请求方式前缀
在Restful风格的api请求路劲一般都相同,这会导致簇点资源名称重复,因此我们要修改配置,把请求方式+请求路径作为簇点资源的名称
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8090
http-method-specify: true # 开启请求方式前缀
请求限流
- 在
Sentinel控制台的簇点链路模块中即可配置接口对应的限流模式
QPS表示:(Queries Per Second)即每秒查询次数,即接口被调用的次数- 单机阈值:表示限流的阈值,即接口被调用的次数

线程隔离
当某一个微服务发生堵塞或故障时,调用该微服务的其他服务可能被拖慢,甚至资源耗尽。因此需要限制调用该服务的最大可用线程数,实现线程隔离 

Fallback 请求资源失败时返回备用数据
在项目中很多资源都是通过OpenFeign进行调用的,因此需要开启Sentinel对OpenFeign的支持
feign:
sentinel:
enabled: true # 开启sentinel对OpenFeign的支持
okhttp:
enabled: true # 开启okhttp
编写Fallback自定义工厂类
package com.hmall.api.fallback;
import cn.hutool.core.collection.ListUtil;
import com.hmall.api.client.ItemClient;
import com.hmall.api.dto.ItemDTO;
import com.hmall.api.dto.OrderDetailDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;
import java.util.Collection;
import java.util.List;
@Slf4j
public class ItemClientFallbackFactor implements FallbackFactory<ItemClient> {
@Override
public ItemClient create(Throwable cause) {
return new ItemClient() {
@Override
public List<ItemDTO> queryItemsByIds(Collection<Long> ids) {
log.error("查询失败线程池满", cause);
//查询失败返回空集合
return ListUtil.empty();
}
@Override
public void deductStock(Collection<OrderDetailDTO> items) {
log.error("扣减库存失败", cause);
throw new RuntimeException("扣减库存失败");
}
};
}
}
将自定义工厂类注册为一个Bean
public class DefaultFeginConfig {
@Bean
public ItemClientFallbackFactor itemClientFallbackFactor() {
return new ItemClientFallbackFactor();
}
}
在OpenFeign配置类中添加FallbackFactory
@FeignClient(value = "item-service", fallbackFactory = ItemClientFallbackFactor.class)
public interface ItemClient {
//批量查询商品
@GetMapping("/items")
List<ItemDTO> queryItemsByIds(@RequestParam("ids") Collection<Long> ids);
//扣减库存
@PutMapping("/items/stock/deduct")
void deductStock(@RequestBody Collection<OrderDetailDTO> items);
}
服务熔断
- 服务熔断是解决雪崩问题的重要手段,思路是由熔断器统计服务调用的异常比例,慢请求比例,如果超出阈值则会熔断该服务。
- 即拦截访问该服务的一切请求;
- 而当服务恢复时,断路器会放行访问该服务的请求
断路器
断路器 具有三种状态:closed(关闭)、open(打开)、half-open(半开)
closed(关闭):此时处于关闭状态,如果服务调用的异常比例,慢请求比例超出阈值,则进入open(打开)状态open(打开):此时处于打开状态,将会拦截所有请求,并返回fallback数据,open是一个临时的状态,时间可配置,如果到期后,进入half-open(半开)状态half-open(半开)状态:此时处于半开状态,会放行部分请求,如果请求成功,则进入closed(关闭)状态,如果请求失败,则进入open( 打开)状态
配置

