0%

SpringCloudAlibaba

Nacos

Nacos 作为服务注册中心

  • github下载Nacos并运行,Nacos默认以集群模式启动,需要手动指定单机版

    ./startup.cmd -m standalone

  • 访问localhost:8848/nacos访问控制台页面,默认的用户名和密码都是nacos

  • 需要注册的服务引入依赖(服务提供者和服务消费者)

    1
    2
    3
    4
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
  • 配置文件

    1
    2
    3
    4
    5
    spring:
    cloud:
    nacos:
    discovery:
    server-addr: localhost:8848
  • Nacos集成了Ribben,直接使用RestTemplate进行访问url即可具有负载均衡功能

    nacos控制台展示所有注册的服务即表示成功

    61H_X2`1OJHNPN`M_LTVNHY.png

Nacos作为服务注册的中心可以满足AP和CP模型,可以进行切换,只需要发送特定的post请求进行修改

ip:port/nacos/v1/ns/operator/switches?entry=serverMode&value=CP

Nacos 作为服务配置中心

基础配置

  • 依赖

    1
    2
    3
    4
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
  • 配置文件bootstrap.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    server:
    port: 3377

    spring:
    profiles:
    active: dev
    application:
    name: nacos-config-client
    cloud:
    nacos:
    discovery:
    server-addr: localhost:8848 #Nacos服务注册中心地址
    config:
    server-addr: localhost:8848 #Nacos作为配置中心地址
    file-extension: yml #指定yaml格式的配置
    group: DEV_GROUP #组名称,默认为DEFAULT_GROUP
    namespace: 7a901d46-e75e-4e6a-b186-5980cca4249b #命名空间namespace,默认会走public组

    # 配置中心对应配置文件的dataId格式:
    # ${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}
    # 这里对应的dataId为:nacos-config-client-dev.yml
  • 在Nacos配置中心添加配置文件

    J~%5S3AH)$A}W6Z0L$YF0JB.png

  • 点击发布后,nacos会自动通知每个注册配置中心的微服务更新配置,不需要再手动发送请求更新

    需要更新代码中的属性则需要标注@RefreshScope在对应类上

分类配置

情景:分布式系统的多环境、多项目配置管理

Nacos使用的是三层定位配置文件的规则,以便更方便的管理不同环境和不同项目

Nacos配置文件的定位顺序

  1. NameSpace:新建namespace如图所示

    N@MBJ9B{G9E$%LXN~~D7UPB.png

    如果不指定id的话会自动生成id,如acdd62bc-3159-452e-aab1-24c4657e8fde

  2. GroupId

  3. DataId

1
2
3
4
5
6
spring:
cloud:
nacos:
config:
group: DEV_GROUP #组名称,默认为DEFAULT_GROUP
namespace: 7a901d46-e75e-4e6a-b186-5980cca4249b #命名空间namespace的id,默认会走public组

Sentinel

Sentinel流量控制

github下载sentinel的jar包,直接以springboot方式运行即可,默认的前端监控页面端口为8080

  • 阈值类型:

    • 按QPS:限制每秒请求数

    • 按线程数:限制正在执行的线程数

  • 流控模式:

    • 直接:API达到限流条件时,直接限流

    • 关联:当关联的资源达到阈值时,就限流自己

    • 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)(API级别的针对来源)

  • 流控效果:

    • 快速失败:直接失败,抛异常

    • warmUp:根据coldFactor(冷加载因子,默认3)的值,从阈值/codeFacotor,经过预热时长,才达到设置的QPS阈值

    • 排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效

Sentinel默认的拦截消息都是Blocked by Sentinel (flow limiting)

Sentinel熔断降级

  • 降级策略:

    • RT:平均响应时间,以ms为单位,当单位统计时长内请求书目大于设置的最小请求数(默认5个/s)并且RT大于所设阈值就会熔断

    • RT在高版本为慢调用比例,在RT的基础上根据设置的慢调用阈值计算出慢调用的比例,根据比例设置的阈值计算熔断

    • 异常比例:异常的比例大于阈值会自动进行熔断,同时应该满足最小请求数的限制

    • 异常数:当单位统计时长(默认1min)内的异常数目超过阈值之后

  • 热点key

    仅支持QPS模式,根据指定的参数索引(对应的是参数在方法名上指定的位置)来进行拦截

    • 参数例外项:可以对这个参数的某一个参数值单独进行限流配置,比如一些热点话题已经预热完毕时可以将限流阈值设置高一些
  • 系统规则

    系统规则相当于整个系统外部的把关门禁,当拦截生效时整个服务都将不能正确响应

@SentinelResource注解的使用

@SentinelResource不支持private方法

这里类似于Hystrix中的HystrixCommand注解,可以指定对应的限流处理方法注意与FallBack区分,指定的对应方法只能处理限流的响应,业务代码抛出的RuntimeException则不能处理

  • blockHandler参数指定处理对应的限流、熔断等配置的响应的方法(只处理BlockException)

  • FallBack参数指定处理业务类异常的方法(RuntimeException)

注意:要使@SentinelResource注解生效,在Sentinel控制台指定限流策略时资源名必须设置成@SentinelResource设定的value值,设置资源名为url路径则只会响应默认的Blocked by Sentinel (flow limiting)

  • 单独业务方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @RequestMapping("/testHotKey")
    @SentinelResource(value = "testHotKey", blockHandler = "deal_testHotKet") //指定对应的限流处理方法
    public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
    @RequestParam(value = "p2",required = false) String p2){
    return "testHotKey-------";
    }

    //这里处理限流方法的参数必须在原方法的基础上添加一个BlockException参数
    public String deal_testHotKet(String p1, String p2, BlockException e) {
    return "----限流响应----";
    }
  • 分离业务类处理

    限流处理类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    //不需要注入
    public class Customerhandler {
    //限流处理
    public CommonResult handlerException(BlockException exception) {
    return new CommonResult(444,"处理限流策略,global handlerException",new Payment(2020L,"serial003"));
    }

    //业务类异常处理
    public CommonResult handleFallback(Throwable e) {
    return new CommonResult(444,"处理业务异常,global handleFallback",new Payment(2020L,"serial003"));
    }
    }

    业务类

    1
    2
    3
    4
    5
    6
    7
    8
    @RequestMapping("/testA")
    @SentinelResource(value = "testA",
    blockHandlerClass = Customerhandler.class, //指定限流处理类
    blockHandler = "handlerException", //指定限流处理方法名
    fallback = "handleFallback") //指定业务异常处理方法名
    public String testA(){
    return "testA-------";
    }

Sentinel持久化

  • 默认情况下,当注册到Sentinel的服务关闭/重启后sentinel的持久化规则会自动清除

  • 可以使用Nacos等配置中心方式来持久化配置,但是笔者感觉这种方式还是不太合理,需要自己手动编写json来保存到nacos,通过sentinel的控制页面设定的配置还是不能保存,等待后续版本优化吧。。。

Seata

  • TC (Transaction Coordinator) - 事务协调者,一般是seata服务器

    维护全局和分支事务的状态,驱动全局事务提交或回滚。

  • TM (Transaction Manager) - 事务管理器,一般是上游标注@GlobalTransactional的服务

    定义全局事务的范围:开始全局事务、提交或回滚全局事务。

  • RM (Resource Manager) - 资源管理器,所有管理具体sql的事务机制

    管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚。

Seata安装部署

SeataServer

  • 修改配置文件file.conf,将存储方式改为db

  • 建库建表,建表sql在对应的readme文件里面有提示,执行即可

  • 修改registry.conf,配置nacos为注册中心

    ![VJLU0A4SJA5VT2O3XC$N.png

  • 每一个需要用到分布式事务的客户端数据库都需要单独建表(尽量从官网上取最新的sql)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    CREATE TABLE IF NOT EXISTS `undo_log`
    (
    `branch_id` BIGINT NOT NULL COMMENT 'branch transaction id',
    `xid` VARCHAR(128) NOT NULL COMMENT 'global transaction id',
    `context` VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
    `rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info',
    `log_status` INT(11) NOT NULL COMMENT '0:normal status,1:defense status',
    `log_created` DATETIME(6) NOT NULL COMMENT 'create datetime',
    `log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime',
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
    ) ENGINE = InnoDB
    AUTO_INCREMENT = 1
    DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';

SeataClient

  • <dependency>
        <groupId>io.seata</groupId>
        <artifactId>seata-spring-boot-starter</artifactId>
        <version>1.4.2</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>endency>
    
    1
    2
    3
    4
    5
    6
    7

    + 推荐使用Nacos配置SeataClient,具体配置方式请依照官方文档[Seata 快速开始](https://seata.io/zh-cn/docs/user/quickstart.html)

    + 需要开启分布式事务的方法(一般是上游调用下游服务的业务方法)添加注解即可生效

    ```java
    @GlobalTransactional(name = "transactionNameA", rollbackFor = Exception.class)

回滚原理

一二阶段提交事务

  1. 一阶段:TM标志@GlobalTransactional开启分布式事务,各个RM执行sql逻辑,并向TC提交执行结果

    ![9`8%F0C{XWQ(9(OCPLG6.png](https://cdn.jsdelivr.net/gh/lan5th/pics/blog_images/20220722212759.png)

    RM事务执行逻辑

    • 执行之前,生成beforeImage,作为修改前数据的快照

    • 执行sql逻辑

    • 执行之后,生成afterImage,作为修改后数据的快照

    • 生成行锁

  2. 二阶段:TC根据汇总到的RM执行结果执行提交逻辑

    7}OJ}S~$ADXE~AF4@E{)3V.png

    • 全部执行成功:通知所有RM删除beforeImage和afterImage,提交事务

    • 有事务执行失败:通知所有RM执行补偿还原机制,根据beforeImage和AfterImage来还原数据

      • 如果afterImage和当前数据没有差异,则直接还原

      • 如果修改和还原之间数据已经由其他sql进行了改变,则无法正常还原,等待运维人员操作。

    • 不论是否执行成功,最终都会删除afterImage、beforeImage和行锁