文章目录
- sentinel下载安装
- 启动sentinel
- 访问sentinel
- pmhub-gateway 整合 sentinel
- 引入依赖
- YML配置文件
- Nacos持久化配置
- 启动pmhub-gateway, 查看sentinel控制台
- 启动结果如图
- 相关名词解释
- OpenFeign和 Sentinel 集成实现自定义 fallback 服务降级
- Sentinel 和 Gateway 集成实现网关限流。
- 通过 OpenFeign和 Sentinel 集成实现自定义 fallback 服务降级,减轻服务负担。
sentinel下载安装
- 下载地址:https://github.com/alibaba/Sentinel/releases
- 文档地址:https://sentinelguard.io/zh-cn/docs
- 下载稳定的sentinel版本, ( 1.8.7 / 1.8.8 均可 )
启动sentinel
- 打开命令窗CD到下载放置 sentinel-dashboard-1.8.8.jar 的文件夹
- 执行
**java -jar sentinel-dashboard-1.8.8.jar**
就可以启动了
- 如果出现端口被占用, 就将端口对应的进程kill掉即可
- KILL进程 :
- Windows
netstat -ano | findstr port
taskkill /pid PID -f # 第二个PID填写端口对应的PID
- Mac
lsof -i tcp:port
sudo kill -9 PID
访问sentinel
- 访问 http://localhost:8080/`
- 初始账号密码均为 : sentinel
- 忽略左边的
**pmhub-gateway**
哈哈哈, 第一次启动是没有的
pmhub-gateway 整合 sentinel
- Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:
- route 维度:即在 Spring 配置文件中配置的路由条目,资源名为对应的 routeId
- 自定义 API 维度:用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组
- 在 PmHub 中主要是用的 route 维度,也即对应的微服务名
引入依赖
<!-- SpringCloud Alibaba Sentinel 核心依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!-- SpringCloud Alibaba Sentinel Gateway,如果不是gateway可以不用引入 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<!-- Sentinel Datasource Nacos 用来做持久化存储-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
YML配置文件
spring:
cloud:
sentinel:
# 取消控制台懒加载
eager: true
transport:
# 配置控制台服务地址
dashboard: 127.0.0.1:8080
# 默认 8719 端口,假如被占用会自动从 8719 开始依次 +1 扫描,直至找到未被占用的端口
port: 8719
# nacos配置持久化
datasource:
ds1:
nacos:
server-addr: 127.0.0.1:8848
dataId: sentinel-pmhub-gateway
groupId: DEFAULT_GROUP
data-type: json
rule-type: gw-flow
Nacos持久化配置
Sentinel 的配置默认是放在内存中,如果服务一旦重启,原先配置好的规则就都不见了,为了防止这样,所以需要配置数据持久化,因为在 PmHub 中,nacos 本身配置了持久化,也就是 nacos 的数据都会最终持久化到 MySQL 数据库。所以我们只需要将 Sentinel 的配置放到 nacos 配置统一管理起来就好了。
- 上一步已经配置了持久化的配置,可以看到文件是 sentinel-pmhub-gateway。
启动pmhub-gateway, 查看sentinel控制台
启动结果如图
相关名词解释
参数名称 | 参数值示例 | 解释 |
---|---|---|
API类型 | Route ID / API分组 | 指定限流规则应用的API类型, 可以是路由ID或API分组 |
API名称 | pmhub-system | 被限流的具体API的名称 |
针对请求属性 | 复选框 | 是否根据请求属性, (如IP地址, 用户身份等), 进行限流 |
阈值类型 | QPS / 线程数 | 限流的依据类型, 可以是美妙查询数( QPS ), 或并发线程数 |
QPS阈值 | 1000 | 指定每秒允许通过的最大请求数, 当超过此值时, 将触发限流 |
间隔 | 1 | 配合QPS阈值使用, 指定限流的时间窗口大小, 如1秒, 1分钟等 |
流控方式 | 快速失败 / 匀速排队 | 当达到限流阈值时, 采取的策略. 快速失败表示直接拒绝, 匀速排队表示排队等待 |
Burst size | 0 | 突发请求数, 表示允许瞬间通过的请求数, 0表示不允许突发流量 |
OpenFeign和 Sentinel 集成实现自定义 fallback 服务降级
- SentinelResource 注解是 Sentinel 官方提供的流量防卫防护组件注解,
- 用于指定防护资源,对配置的资源进行流量控制,熔断降级等功能。
- 在接口上加上这个注解,就能够实现自定义限流提示和程序异常返回 fallback 服务降级
/**
* 根据用户名获取当前用户信息
*/
@InnerAuth
@GetMapping("/info/{username}")
@SentinelResource(value = "infoSentinelResource",blockHandler = "handlerBlockHandler", fallback = "doActionFallback") // 演示SentinelResource细粒度管控服务流控和降级
public R<LoginUser> info(@PathVariable("username") String username) {
SysUser sysUser = userService.selectUserByUserName(username);
if (StringUtils.isNull(sysUser)) {return R.fail("用户名或密码错误");}
// 角色集合
Set<String> roles = permissionService.getRolePermission(sysUser);
// 权限集合
Set<String> permissions = permissionService.getMenuPermission(sysUser);
LoginUser loginUser = new LoginUser();
loginUser.setUser(sysUser);
loginUser.setRoles(roles);
loginUser.setPermissions(permissions);
loginUser.setUserId(sysUser.getUserId());
loginUser.setDeptId(sysUser.getDeptId());
loginUser.setNickName(sysUser.getNickName());
return R.ok(loginUser);
}
- 所谓 fallback 服务降级是指,调用一个微服务出现异常时候,访问者要有fallback 服务降级的情况,也就是我们常见的一些提醒如:“服务繁忙,请稍后再试!”不要持续访问9001加大微服务负担,
- 直接在接口的 @SentinelResource 方法直接加 fallback 降级,但是通过 feign 接口调用的方法各自不同,如果每个不同方法都加一个fallback 配对方法,会导致代码膨胀不好管理,工程埋雷…
- 在 UserFeignService 中的 @FeignClient 注解上
- 添加自定义 fallbackFactory 就能实现我们想要的功能,下面是具体的代码。
/**
* @author canghe
* @description 用户服务
* @create 2024-04-24-22:38
*/
@FeignClient(contextId = "userFeignService", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = UserFeginFallbackFactory.class)
public interface UserFeignService {
/**
* 根据用户名获取当前用户信息
*/
@GetMapping("/system/user/info/{username}")
R<LoginUser> info(@PathVariable("username") String username, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
/**
* 根据 userId 获取用户信息
*/
@GetMapping("/system/user/getInfoByUserId/{userId}")
R<LoginUser> getInfoByUserId(@PathVariable("userId") Long userId, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
/**
* 根据条件获取用户列表
*/
@PostMapping("/system/user/listOfInner")
R<List<SysUserVO>> listOfInner(@RequestBody SysUserDTO sysUserDTO, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
/**
* 注册用户信息
*
* @param sysUser 用户信息
* @param source 请求来源
* @return 结果
*/
@PostMapping("/system/user/register")
R<Boolean> registerUserInfo(@RequestBody SysUser sysUser, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
}
- UserFeginFallbackFactory 降级处理
/**
* 用户服务降级处理
*
* @author canghe
*/
@Component
public class UserFeginFallbackFactory implements FallbackFactory<UserFeignService>
{
private static final Logger log = LoggerFactory.getLogger(UserFeginFallbackFactory.class);
@Override
public UserFeignService create(Throwable throwable)
{
log.error("用户服务调用失败:{}", throwable.getMessage());
return new UserFeignService()
{
@Override
public R<LoginUser> info(String username, String source) {
return R.fail("根据用户名获取用户失败:" + throwable.getMessage());
}
@Override
public R<LoginUser> getInfoByUserId(Long userId, String source) {
return R.fail("根据userId获取用户失败:" + throwable.getMessage());
}
@Override
public R<List<SysUserVO>> listOfInner(SysUserDTO sysUserDTO, String source) {
return R.fail("根据调教获取用户列表失败:" + throwable.getMessage());
}
@Override
public R<Boolean> registerUserInfo(SysUser sysUser, String source) {
return R.fail("注册用户失败:" + throwable.getMessage());
}
};
}
}