- 官网地址
- 文档手册
- 一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
- 是 Naming Configuration Service 的简写;用于注册中心 + 配置中心的整合,替代 Eureka 做服务注册中心,替代 Config 做服务配置中心;等价于 Nacos = Eureka + Config + Bus
- 项目地址
- 引入依赖 spring-cloud-starter-alibaba-nacos-discovery、配置 Nacos 地址等操作
- 底层集成 ribbon,所以具有远程调用的功能
- 如果不需要存储服务级别的信息且服务实例是通过 Nacos-Client 注册,并能够保持心跳上报一般选择 AP 模型
- 如果需要在服务级别编辑或者存储配置信息,一般选择 CP,例如 K8s、DNS 服务
- 使用命令进行切换:curl-X PUT'SNACOS_SERVER:8848/nacos/vl/ns/operator/switches?entry=serverMode&value=CP'
- 引入依赖 spring-cloud-starter-alibaba-nacos-discovery、spring-cloud-starter-alibaba-nacos-config、配置 Nacos 地址等操作
- namespace 是用于区分部署环境的命名空间
- group 和 DataID 逻辑上区分两个目标对象;groupid 可以放多个微服务,每个微服务对应的是 dataid
设置 DataId
- 公式:${spring.application.name}-${spring.profiles.active}-${spring.cloud.nacos.config.file-extension}
- prefix 默认为 spring.application.name 的值,spring.profiles.active 即为当前环境对应的 profile,file-extension 为配置内容的数据格式
- 官网配置
- 安装 mysql
- 默认 Nacos 使用嵌入式数据库 Derby 实现数据的存储。所以如果启动多个默认配置下的 Nacos 节点,数据存储是存在一致性问题的。为了解决这个问题,Nacos 采用了集中式存储的方式来支持集群化部署,目前只支持 MySQL 的存储
- 使用 docker 安装 Nacos 没有对应的 nacos-mysql.sql 文件,所以下载的统一版本的安装运行
- 修改 conf 目录下的 application.propertites 文件
- 官网
- 轻量级的流量控制、熔断降级 Java 库
- Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
- Sentinel 分为两部分:核心库(Java 客户端)不依赖任何框架/库,能够运行在 Java8 以上运行时环境,同时对 Dubbo、SpringCloud 框架也有较好的支持;控制台(DashBoard)主要负责管理推送规则、监控、管理机器信息等
- 注意 docker 安装不行,一直空白界面,采用多种方式例如添加配置 client-ip 仍不行,错误一直超时。可能的原因是 sentinel和部署的微服务一定要在同一个内网中
- docker 安装参考
- 最后使用本地运行 sentinel 解决,下载地址 sentinel:1.8.6
- 启动命令:java -jar sentinel-dashboard-1.8.6.jar --server.port=8081
- Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果
- 流量控制有以下几个角度:
- 资源的调用关系,例如资源的调用链路,资源和资源之间的关系
- 运行指标,例如 QPS、线程池、系统负载等
- 控制的效果,例如直接限流、冷启动、排队等
- 资源名:唯一名称,默认请求路径
- 针对来源:Sentinel 可以针对调用者进行限流,填写微服务名,默认 default(不区分来源)
- 阈值类型/单机阈值
- QPS(每秒的请求数量):当调用该 api 的 QPS 达到阈值的时候,进行限流
- 线程数:当调用该 api 的线程数达到阈值的时候,进行限流
- 直接:api 达到限流条件时,直接限流
- 关联:当关联的资源达到阈值时,就限流自己;可以通过 JMeter(并发)、PostMan(串行) 测试
- 链路:只记录指定链路上的流量,指定资源从入口资源进来的流量,如果达到阈值,就进行限流(api 级别的针对来源)
- 快速失败:直接失败,抛出异常
-
预热(Warm Up):根据 codeFactor(冷加载因子,默认3)的值,系统最开始的初始阈值为 阈值/codeFactor ,然后经过预热时长才慢慢达到设置的 QPS 阈值。应用于秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,可慢慢的把流量放进来,慢慢的把阀值增长到设置的阀值
-
排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置 QPS,否则无效;对应的算法是漏桶算法;主要用于处理间隔性突发的流量,例如消息队列。在某一秒有大量请求到来,而接下来的几秒则处于空闲状态,希望系统能过在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求
- sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
- 自定义提示:通过注解 @SentinelResource(value = "testHotKey", blockHandler = "dealHandler_testHotKey"),处理的是 sentinel 控制台配置的违规情况,有 blockHandler 方法兜底处理,不会管运行时异常;fallback 属性管理运行时异常
- RT(平均响应时间,秒级)
- 平均响应时间超出阈值 且 在 1s 内通过的请求 >= 5,两个条件同时满足后触发降级
- 当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断
- RT 最大为4900,仍需更大需要修改 -Dcsp.sentinel.statistic.max.rt=XXX 生效
- 异常比(秒级):QPS(资源每秒请求量) >= 5 且 异常比例(每秒的)超过阈值时,触发降级;当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断;在时间窗口期结束后,关闭降级
- 异常数(分钟级):异常数(每分钟)超过阈值时,触发降级;时间窗口期结束后,关闭降级
- 热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效
- 例如:方法里面的第一个参数(指的是后台方法里的第一个参数而不是前端传入的第一个参数)只要 QPS 超过每秒1次,马上进行降级处理
/**
* sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
* 自定义限流异常,testHotKey为资源名;blockHandler为fallback方法
*
* @SentinelResource 处理的是 sentinel 控制台配置的违规情况,有 blockHandler 方法配置的兜底处理
* 对于 RuntimeException 异常,例如 int age = 10 / 0,会走异常,@SentinelResource 注解不管
* @param p1
* @param p2
* @return
*/
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey", blockHandler = "dealHandler_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1, @RequestParam(value = "p2",required = false) String p2){
return "------testHotKey";
}
public String dealHandler_testHotKey(String p1, String p2, BlockException exception) {
return "-----dealHandler_testHotKey";
}
- 参数例外项:某些时候我们期望参数是某个特殊值的时候,它的限流值和平时不一样
- 官网
- 系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和 并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性
- 系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量,比如 web 服务或者 Dubbo 服务端接收的请求,都属于入口流量
- Load 自适应(仅对 linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR阶段)。系统容量由系统的 maxQPS * minRT 估算得出。设定参考值一般是 CPU cores * 2.5
- CPU usage(1.5.0+版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏
- 平均 RT:当单台机器上所有入口流量的平均 RT达到阈值即触发系统保护,单位是毫秒
- 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护
- 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护
- blockHandler 管理配置违规情况
- fallback 管理运行时异常,也就是业务代码异常
- 同时配置同时出问题,blockHandler > fallback
/**
* id = 4, 抛出运行时异常,会走 fallback 配置的方法,只负责业务异常
* blockHandler 负责在 sentinel 里面配置的降级限流
* 同时配置,blockHandler > fallback
* @param id
* @return
*/
@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback", blockHandler = "blockHandler", fallback = "blockFallBack")
public CommonResult<Payment> fallback(@PathVariable Long id) {
CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);
if (id == 4) {
throw new IllegalArgumentException("IllegalArgumentException,非法参数异常....");
} else if (result.getData() == null) {
throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
}
return result;
}
/**
* 业务类异常
* @param id
* @param throwable
* @return
*/
public CommonResult blockFallBack(@PathVariable Long id, Throwable throwable) {
return new CommonResult(4444, "运行时异常,fallback跳转,blockException: " + throwable.getMessage(), new Payment(id, "null"));
}
/**
* sentinel控制台配置异常
* @param id
* @param blockException
* @return
*/
public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) {
return new CommonResult<>(4445, "sentinel里面配置异常,blockHandler-sentinel限流, 无此流水: blockException " + blockException.getMessage(), new Payment(id, "null"));
}
- @SentinelResource(value = "byResource", blockHandler = "handleException"),其中 value 属性对应的就是资源名
- 没有下划线 /
- @GetMapping 对应URL,有下划线 /
- sentinel 控制台需要通过资源名配置,URL配置不起作用
- @SentinelResource(value = "customerBlockHandler", blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handleException2");blockHandlerClass 对应的是类里面的具体方法 handleException2
/**
* 自定义通用的限流处理逻辑,sentinel 控制台需要通过资源名配置,URL配置不起作用
* blockHandlerClass = CustomerBlockHandler.class
* blockHandler = handleException2
* 上述配置:找CustomerBlockHandler类里的handleException2方法进行兜底处理
*/
@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handleException2")
public CommonResult customerBlockHandler() {
return new CommonResult(200,"按客户自定义限流处理逻辑");
}
/**
* @author SHshuo
* @data 2023/2/3--10:32
* 自定义通用的限流处理逻辑
*/
public class CustomerBlockHandler {
public static CommonResult handleException2(BlockException exception){
return new CommonResult(2022,"自定义的限流处理信息......handleException2");
}
public static CommonResult handleException(BlockException exception){
return new CommonResult(2022,"自定义的限流处理信息......handleException");
}
}
- 一旦我们重启应用,sentinel 规则将会消失,所以需要将配置规则进行持久化配置
- 将限流配置规则持久化进 nacos 保存,需要在 nacos 中手写 JSON 配置,之后刷新 sentinel 控制台即出现配置规则
- 项目地址
- 感觉主要针对 sentinel 控制台进行操作,Hystrix 主要通过代码来实现
- 官网地址
- 一次业务操作需要跨多个数据源或者需要跨多个系统进行远程调用,就会产生分布式事务问题
- Seata 是一款开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。
- TM 向 TC 申请一个全局事务,全局事务创建成功并生成一个全局唯一的 XID
- XID 向微服务调用链路的上下文中传播
- RM 向 TC 注册分支事务,将其纳入 XID 对应全局事务的管辖
- 一阶段事务完成
- TM 向 TC 发起针对 XID 的全局提交或者回滚决议
- TC 调度 XID 下管辖的全部分支事务完成提交或者回滚请求
- 二阶段事务完成
名词介绍
- Transaction ID XID:全局唯一的事务ID
- Transaction Coordinator(TC):事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或者回滚
- Transaction Manager(TM):控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或者全局回滚的决议
- Resource Manager(RM):控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚
- 官网地址
- 此例子安装的是0.9版本,如果需要安装最新版请参考官网文档
- 修改 store.mode 改成 db,之后再对应位置修改数据库属性
- 修改 registry.type 改成 nacos,之后再对应位置修改 nacos 配置
- 运行初始化 SQL,老版在 /seata/conf/db_store.db;新版在 seata/script/server/db/mysql.sql
- 运行成功
-
seata 版本问题,新版直接将配置注册到 nacos,通过 yml 进行配置;老版需要创建 file.conf、registry.conf文件
-
添加 @GlobalTransactional(name = "fsp-create-order", rollbackFor = Exception.class) 注解之后,会抛出问题(不加正常调用)
- io.seata.rm.datasource.exec.LockConflictException: get global lock fail, xid:xxx, lockKeys:xxx
- 解决: 参考issues 2460 将配置添加
- 将数据库时区与当前时间一致
- 仍抛出 Global lock acquire failed,参考issues 2555、issues 2735暂时仍未解决
feign:
httpclient:
connection-timeout: 60000
connection-timer-repeat: 3000
ribbon:
ConnectTimeout: 60000 # 设置连接超时时间 default 2000
ReadTimeout: 60000 # 设置读取超时时间 default 5000
OkToRetryOnAllOperations: true # 对所有操作请求都进行重试 default false
MaxAutoRetriesNextServer: 20 # 切换实例的重试次数 default 1
MaxAutoRetries: 10 # 对当前实例的重试次数 default 0