蘇阿細 - 微服务
type: channel
link: https://wangchouchou.com/category/%E5%BE%AE%E6%9C%8D%E5%8A%A1/
description: 微服务
items: Spring Cloud OAuth2.0
items: Seata分布式事务原理
items: Seata
items: Sentinel规则持久化
items: Sentinel整合Open Feign
items: 服务熔断
items: @SentinelResource注解
items: 系统保护规则
items: 热点规则
items: 降级规则

Spring Cloud OAuth2.0
type: item
date: 2022-02-19T10:59:00+00:00
description: 一、介绍1. 概念OAuth开放授权是一个开放标准，允许用户授权第三方应用访问存储在另外的服务提供者上的信息，而不需要将用户名和密码提供给第三方应用或分享数据的内容，OAuth2.0是OAuth协议的延续版本，不向下兼容OAuth1.0.2. 流程示例允许将认证和授权的过程交由一个独立的第三方来进行担保，OAuth协议用来定义如何让第三方的担保有效且双方可信，以登录百度账号为例：官方示意图：OAuth2.0包含以下几个角色：客户端（示例中的浏览器、微信客户端）本身不存储资源，需要通过资源拥有者的授权去请求资源服务器的资源资源拥有者（示例中的用户）通常是用户，也可以是应用程序，即该资源的拥有者授权服务器（也称认证服务器）（示例中的微信）用于服务提供者对资源资源拥有者的身份进行认证，对访问资源进行授权，认证成功后会给客户端发放令牌（access_token），作为客户端访问资源服务器的凭证资源服务器（示例中的百度、微信）存储资源的服务器，示例中，微信通过OAuth协议让百度可以访问自己存储的用户信息，而百度则通过该协议让用户可以访问自己受保护的资源3. 补充clientDetails(client_id)：客户信息，代表百度在微信中的唯一索引secret：密钥，百度获取微信信息时需要提供的一个加密字段scope：授权作用域百度可以获取到的微信的信息范围，如：登录范围的凭证无法获取用户信息范围的内容access_token：访问令牌，百度获取微信用户信息的凭证grant_type：授权类型，authorization_code(授权码模式), password(密码模式), client_credentials(客户端模式), implicit(简易模式、隐式授权), refresh_token(刷新令牌)userDetails(user_id)：授权用户标识，示例中代表用户的微信号二、Demo实现OAuth2的服务包含授权服务（Authorization Server）和资源服务（Resource Server）。授权服务包含对接入端以及登入用户的合法性进行验证并颁发token等功能，对令牌的请求断点由SpringMVC控制器进行实现AuthorizationEndPoint服务用于认证请求，默认url：/oauth/authorizeTokenEndPoint用于访问令牌的请求，默认url：/oauth/tokenOAuth2AuthenticaionProcessingFilter用于对请求给出的身份令牌进行解析健全大致业务流程：客户请求授权服务器申请access_token客户携带申请到的access_token访问资源服务器中的资源信息资源服务器将检验access_token的合法性，验证合法后返回对应的资源信息1. 父工程搭建pom.xml<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <modules> <module>OAuth-Server</module> <module>OAuth-User</module> </modules> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> <relativePath/> </parent> <groupId>com.sw</groupId> <artifactId>Spring-Cloud-OAuth2</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>pom</packaging> <properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <springboot.version>2.2.5.RELEASE</spri…

Seata分布式事务原理
type: item
date: 2021-05-05T05:37:00+00:00
description: 1、TM开启分布式事务（TM向TC注册全局事务）2、按业务场景，编排数据库、服务等事务内的资源（RM向TC汇报资源准备状态）3、TM结束分布式事务，事务一阶段结束（TM通知TC提交/回滚）4、TC汇总事务信息，决定最终是提交还是回滚事务5、TC通知所有RM提交/回滚 资源，事务二阶段结束Seata提供了四个模式：AT、TCC、SAGA、XAAT模式两阶段提交协议的演变：一阶段：业务数据和回滚日志记录在同一个本地事务中提交，释放本地锁和连接资源二阶段：提交异步化（能快速完成）；回滚通过一阶段的回滚日志进行反向补偿一阶段:在一阶段，seata会拦截“业务SQL”：1、解析SQL语义，找到“业务SQL”要更新的业务数据，在业务数据被更新前，将其保存为before image2、执行“业务SQL”更新业务数据，更新之后将业务数据保存为after image3、最后生成行锁以上操作全部在一个数据库事务内完成，保证了一阶段操作的原子性二阶段:1、成功提交二阶段正常执行的话，只需将一阶段保存的快照数据和行锁删除，即可完成数据清理，因为“业务SQl”在一阶段已经在提交至数据库2、事务回滚二阶段如果出现异常，需要事务回滚，seata就需要回滚一阶段已经执行的“业务SQL”，还原业务数据；回滚方式使用before image还原业务数据，在还原之前需要做校验脏写，对比数据库当前的业务数据和after image数据快照，如果两份数据完全一致，就说明没有脏写，执行还原操作，如果不一致，就需要转人工处理

Seata
type: item
date: 2021-05-05T05:33:00+00:00
description: seata是一个分布式的解决方案，致力于在微服务架构下提供高性能和简单易用的分布式微服务，官网：http://seata.io/zh-cn/一、三组概念TC 事务协调者：维护全局和分支事务的状态，驱动全局事务提交或回滚TM 事务管理器：定义全局事务的范围：开始、提交、回滚RM 资源管理器：管理分支事务处理的资源，与TC交谈以注册分支事务和报告分支事务的状态，并驱动分支事务提交或回滚二、安装GitHub地址：https://github.com/seata/seata（以Nacos 2.0、Seata 1.4.2为例）修改配置文件1、/conf/file.conf (注意与1.0之前的版本区分，1.0之后可以在yml文件中指定service配置)修改数据库模式（使用数据库存储事务信息）和数据源2、/conf/registry.conf3、mysql建表1、新建seata数据库2、运行mysql.sql注意：建表sql在/conf/REDME.md文件中，点击server出现存放sql的github地址：https://github.com/seata/seata/tree/develop/script/server4、启动先启动Nacos再启动Seata（bin/seata-server.bat）三、业务测试1、业务说明创建三个微服务：订单---库存---账户大致流程：当用户下单时，订单服务创建订单，远程调用库存服务扣减库存，再通过远程调用账户服务来扣减账户余额，最后在订单服务中修改订单状态为已完成。2、数据库建表创建三个数据库seata_order（订单），seata_storage（库存），seata_account（账户）创建对应的表-- t_order DROP TABLE IF EXISTS `t_order`; CREATE TABLE `t_order` ( `id` bigint(11) NOT NULL AUTO_INCREMENT, `user_id` bigint(11) NULL DEFAULT NULL COMMENT '用户id', `product_id` bigint(11) NULL DEFAULT NULL COMMENT '产品id', `count` int(11) NULL DEFAULT NULL COMMENT '数量', `money` decimal(11, 0) NULL DEFAULT NULL COMMENT '金额', `status` int(1) NULL DEFAULT NULL COMMENT '订单状态：0：创建中; 1：已完结', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- t_storage DROP TABLE IF EXISTS `t_storage`; CREATE TABLE `t_storage` ( `id` bigint(11) NOT NULL AUTO_INCREMENT, `product_id` bigint(11) NULL DEFAULT NULL COMMENT '产品id', `total` int(11) NULL DEFAULT NULL COMMENT '总库存', `used` int(11) NULL DEFAULT NULL COMMENT '已用库存', `residue` int(11) NULL DEFAULT NULL COMMENT '剩余库存', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; INSERT INTO `t_storage` VALUES (1, 1, 100, 0, 100); -- t_account DROP TABLE IF EXISTS `t_account`; CREATE TABLE `t_account` ( `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT 'id', `user_id` bigint(11) NULL DEFAULT NULL COMMENT '用户id', `total` decimal(10, 0) NULL DEFAULT NULL COMMENT…

Sentinel规则持久化
type: item
date: 2021-04-29T14:19:00+00:00
description: 默认规则是临时存储的，重启Sentinel服务之后消失1、环境搭建以8401模块为例添加pom依赖 <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency>ymlserver: port: 8401 spring: application: name: cloud-alibaba-sentinel-service cloud: nacos: discovery: server-addr: localhost:8848 sentinel: transport: # sentinel dashboard地址 dashboard: localhost:8080 # 默认8719端口，如果8719被占用，默认递增 port: 8719 # 流控规则持久化 datasource: ds1: nacos: server-addr: localhost:8848 # namespace根据具体的情况指定 dataId: cloud-alibaba-sentinel-service groupId: DEFAULT_GROUP data-type: json rule-type: flow management: endpoints: web: exposure: include: '*'Nacos新建配置文件参数说明：resource：资源名称limitApp：应用来源grade：阈值类型，0：线程数，1：QPScount：单机阈值strategy：流控模式，0：直接，1：关联，2：链路controBehavier：流控效果，0：快速失败，1：Warm Up，2：排队等待clusterMode：是否集群2、测试1、启动8401，在Sentinel控制中心可以看到读取了Nacos那边配置的流控规则；2、关闭8401，Sentinel控制中心的规则消失；3、重启8401，重启之后如果出现了流控规则，则表明规则持久化配置成功。图片来源：尚硅谷 - 周阳 - Spring Cloud Alibaba

Sentinel整合Open Feign
type: item
date: 2021-04-29T14:17:00+00:00
description: 1、环境搭建以8884模块为例pom文件添加依赖 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>yml添加# 激活sentinel对feign的支持 feign: sentinel: enabled: true启动类@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients public class OrderMain84 { public static void main(String[] args) { SpringApplication.run(OrderMain84.class, args); } }创建远程调用接口@FeignClient(value = "nacos-payment-provider") public interface PaymentService { @GetMapping("/payment/{id}") public CommonResult<Payment> payment(@PathVariable("id")Long id); }实现类（用于服务降级）@Component public class PaymentFallbackService implements PaymentService { @Override public CommonResult<Payment> payment(Long id) { return new CommonResult<Payment>(444, "服务降级返回--PaymentService", new Payment(id, "errorSerial")); } }接口指定降级的类@FeignClient(value = "nacos-payment-provider", fallback = PaymentFallbackService.class) public interface PaymentService { @GetMapping("/payment/{id}") public CommonResult<Payment> payment(@PathVariable("id")Long id); }controller@Resource private PaymentService service; @GetMapping("/payment/{id}") public CommonResult<Payment> payment(@PathVariable("id")Long id){ return service.payment(id); }2、测试启动9003、8884，如果中途9003出现问题关闭，8884服务降级成功3、熔断框架比较 SentinelHystrixresilience4j隔离策略信号量隔离线程池/信号量隔离信号量隔离熔断降级策略基于响应时间、异常比例、异常数异常比例异常比例、响应时间实时统计滑动窗口（LeapArray）滑动窗口（Rxjava）Ring Bit Buffer动态规则支持多种数据源支持多种数据源有限的支持扩展性多个扩展点插件接口基于注解的支持支持支持支持限流QPS、调用关系有限的支持Rate Limiter图片来源：尚硅谷 - 周阳 - Spring Cloud Alibaba

服务熔断
type: item
date: 2021-04-29T14:13:00+00:00
description: 1、环境搭建1、启动Nacos、Sentinel2、新建9003、9004两个模块pom <dependency> <groupId>com.sw</groupId> <artifactId>cloud-api-commons</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency>ymlserver: port: 9003 spring: application: name: nacos-payment-provider cloud: nacos: discovery: server-addr: localhost:8848 management: endpoints: web: exposure: include: '*'启动类@SpringBootApplication @EnableDiscoveryClient public class PaymentMain9003 { public static void main(String[] args) { SpringApplication.run(PaymentMain9003.class, args); } }controller(此处的虚拟数据库是为了方便演示)@RestController @RequestMapping("/payment") public class PaymentController { @Value("${server.port}") private String serverPort; public static Map<Long, Payment> map = new HashMap<>(); static { map.put(1L, new Payment(1L, "螺蛳粉01")); map.put(2L, new Payment(2L, "螺蛳粉02")); map.put(3L, new Payment(3L, "螺蛳粉03")); } @GetMapping("/{id}") public CommonResult<Payment> payment(@PathVariable("id")Long id){ Payment payment = map.get(id); CommonResult<Payment> result = new CommonResult<>(200, "serverPort: " + serverPort, payment); return result; } }注：9004构建步骤与9003一致2、新建8884模块pom同理9004、9004模块ymlserver: port: 8884 spring: application: name: nacos-order-consumer cloud: nacos: discovery: server-addr: localhost:8848 sentinel: transport: # sentinel dashboard地址 dashboard: …

@SentinelResource注解
type: item
date: 2021-04-29T14:10:00+00:00
description: 1、环境搭建(8401模块)8401模块的pom增加以下依赖 <dependency> <groupId>com.sw</groupId> <artifactId>cloud-api-commons</artifactId> <version>1.0-SNAPSHOT</version> </dependency>controller@RestController public class RateLimitController { @GetMapping(value = "/byResource", produces = {"application/json;charset=UTF-8"}) @SentinelResource(value = "byResource", blockHandler = "handlerException") public CommonResult<JSONObject> byResource(){ return new CommonResult(200, "按资源名称测试限流",new Payment(100L, "干脆面")); } public CommonResult<JSONObject> handlerException(BlockException exception){ return new CommonResult(444, exception.getClass().getCanonicalName() + "\t 服务不可用！"); } }限流规则注：配置了@SentinelResource注解后，资源名填byResource或者/byResource都可以测试2、自定义限流规则单独创建一个handler类，用于处理限流public class CustomerBlockHandler { public static CommonResult handlerException1(BlockException exception){ return new CommonResult(444, "global handlerException01"); } public static CommonResult handlerException2(BlockException exception){ return new CommonResult(444, "global handlerException02"); } }controller指定自定义的降级方法@GetMapping(value = "/customerBlockHandler", produces = {"application/json;charset=UTF-8"}) @SentinelResource(value = "customerBlockHandler", blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handlerException2" ) public CommonResult<JSONObject> customerBlockHandler(){ return new CommonResult(200, "按客户自定义测试限流",new Payment(100L, "干脆面")); }Sentinel自定义限流规则测试补充3、其他属性@SentinelResource不适用于private方法value：资源名称，必需项（不能为空）；entryType：entry类型，可选项（默认为 EntryType.OUT）；fallback：fallback函数名称，可选项，用于在抛出异常的时候提供 fallback处理逻辑；fallback函数可以针对所有类型的异常（除了exceptionsToIgnore里面排除掉的异常类型）进行处理。fallback函数签名和位置要求： 返回值类型必须与原函数返回值类型一致；方法参数列表需要和原函数一致，或者可以额外多一个 Throwable类型的参数用于接收对应的异常；fallback函数默认需要和原方法在同一个类中。若希望使用其他类的函数，则可以指定 fallbackClass为对应的类的 Class 对象，注意对应的函数必需为 static函数，否则无法解析。 defaultFallback（since 1.6.0）：默认的 fallback函数名称，可选项，通常用于通用的 fallback逻辑（即可以用于很多服务或方法）。默认 fallback函数可以针对所有类型的异常（除了exceptionsToIgnore里面排除掉的异常类型）进行处理。若同时配置了 fallback和 d…

系统保护规则
type: item
date: 2021-04-29T14:09:00+00:00
description: 参数说明：LOAD自适应：（仅对Linux/Unix生效）系统的1oad1作为启发指标，进行自适应系统保护。当系统load1超过设定的启发值，且系统当前的并发线程数超过估算的系统容量时才会触发系统保护（BBR阶段），系统容量由maxQps * minRt估算得出，设定的参考值一般为：CPU cores * 2.5RT：单台机器上所有入口流量的平均RT达到阈值，触发系统保护，单位：ms线程数：单台机器上所有入口流量的并发线程数达到阈值，触发系统保护入口QPS：单台机器上所有入口流量的QPS达到阈值，触发系统保护CPU使用率：当系统CPU使用率超过阈值，触发系统保护测试（以入口QPS为例）：图片来源：尚硅谷 - 周阳 - Spring Cloud Alibaba

热点规则
type: item
date: 2021-04-29T14:06:00+00:00
description: 热点规则：很多时候我们希望统计数据中访问次数最高的数据，并对其访问进行限制热点参数限流会统计传入参数中的热点参数，并根据配置的限流阈值和模式，对包含热点参数的资源调用进行限流（该策略仅对包含热点参数的资源生效）。1、测试：新增测试方法，并自定义降级方法测试结果：带参数p1访问/testHotKey，且每秒钟的请求次数触发了限流规则不带热点参数访问：2、设置热点规则的其他选项测试：测试结果：图片来源：尚硅谷 - 周阳 - Spring Cloud Alibaba

降级规则
type: item
date: 2021-04-29T14:02:00+00:00
description: ​ Sentinel熔断降级会在调用链路中某个资源出现不稳定状态时（超时或异常），对这个资源的调用进行限制，让请求快速失败，避免影响到其它资源而导致级联错误。​ 当资源被降级后，在接下来的降级时间窗口内，对该资源的调用都会自动熔断（默认抛出DegradeException异常）。参数说明：RT（平均响应时间，秒级）：平均响应时间超出阈值==且==在时间窗口内通过的请求 >= 5，两个条件同时满足后，进行服务降级，时间窗口期过后，关闭断路器RT最大4900ms（更大的值需通过-Dcsp.sentinel.statistic.max.rt=xxx设置）异常比例（秒级）：QPS >= 5 ==且==异常比例（[0.01-1.0]）超过阈值，触发降级，时间窗口结束后，关闭断路器异常数（分钟级）：异常数超过阈值时，触发降级，时间窗口结束后，关闭断路器1、RT平均响应时间Sentinel默认设置为1秒5次请求。一秒钟进入5个请求，且平均响应时间超过设置的200ms，就触发降级Jmeter压力测试：新增一个测试方法：2、异常比例​ 当资源的每秒请求量 >= 5，并且每秒异常总数占总通过请求数的比值超过设置的阈值，触发熔断降级，异常比例阈值范围：[0.01-1.0]测试:修改刚才新增的/testD测试方法设置降级规则：未触发降级的返回结果：触发降级的返回结果：3、异常数​ 当请求的资源近1分钟的异常数目超过阈值之后，会进行熔断。由于统计时间窗口是分钟级的，如果timeWindow（时间窗口期）小于60s，结束熔断后可能会再次进入熔断状态。