请选择 进入手机版 | 继续访问电脑版

Spring Cloud Alibaba学习总结

[复制链接]
丁翼 发表于 2020-12-31 18:10:42 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
Spring Cloud Alibaba

1.入门简介

1.1 为什么会出现SpringCloud alibaba

  spring cloud Netflix进入维护模式
1.2 是什么

  2018.10.31, Spring cloud Alibaba正式入驻了Spring Cloud官方孵化器,并在Maven中央库发布了第一个版本.
1.3 能干嘛

  

  • 服务限流降级
    默认支持Servlet、Feign、RestTemplate、Dubbo和RocketMQ限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持检察限流降级Metrics监控
  • 服务注册与发现
    适配Spring Cloud服务注册与发现标准,默认集成了Ribbon的支持
  • 分布式设置管理
    支持分布式系统中的外部化设置,设置更改时自动刷新
  • 消息驱动本事
    基于Spring Cloud Stream为微服务应用构建消息驱动本事
  • 阿里云存储对象
    阿里云提供的海量、安全、低本钱、高可靠的云存储服务.支持在任何应用、任何时间、任何所在存储和访问任意范例的数据
  • 分布式任务调治
    提供秒级、精准、高可靠、高可用的定时(基于Cron表达式)任务调治服务.同时提供分布式的任务执行模子,如网格任务.网格任务支持海量子任务均匀分配到所有Worker(schedulerx-client)上执行
1.4 怎么用

  

  • Sentinel
    阿里巴巴开源产品,把流量作为切入点,从流量控制,熔断降级,系统负载掩护等多个维度掩护服务的稳定性.
  • Nacos
    阿里巴巴开源产品,一个更易于构建云原生应用的动态服务发现,设置管理和服务管理平台.
  • RocketMQ
    Apache RocketMQ基于Java的高性能,高吞吐量的分布式消息和流盘算平台.
  • Dubbo
    Apache Dubbo是一款高性能的Java RPC框架.
  • Seata
    阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务办理方案.
  • Alibaba Cloud OSS
    阿里云对象存储服务器(Object Storage Service,简称OSS),是阿里云提供的海量,安全,低本钱,高可靠的云存储服务.
  • Alibaba Cloud Schedulerx
    阿里中间件团队开辟的一款分布式调治产品,支持周期性的任务与固定时间点触发任务.
2. SpringCloud Alibaba Nacos服务注册和设置中心

2.1 Nacos(Naming Configuration Service)简介

2.1.1 是什么


  • 一个更易于构建云远程应用的动态服务发现,设置管理和服务管理平台
  • Nacos就是注册中心 + 设置中心的组合 等价于 Nacos = Eureka + Config + Bus
2.1.2 能干嘛


  • 替代Eureka做服务注册中心
  • 替代Config做服务设置中心
2.1.3 注册中心比较

服务注册与发现框架CAP模子控制台管理社区活泼度EurekaAP支持低(2.x版本闭源)ZookeeperCP不支持中ConsulCP支持高NacosAP/CP支持高

  • nacos和CAP


2.2 Nacos安装


  • 当地Java8+Maven情况已经OK
  • 先从官网下载Nacos
  • 解压安装包,直接运行bin目次下的startup.cmd
  • 运行乐成后访问http://localhost:8848/nacos
  • 默认账号nacos nacos
2.3 Nacos作为服务注册中心

2.3.1 pom

  1.                             com.alibaba.cloud            spring-cloud-starter-alibaba-nacos-discovery                            org.springframework.boot            spring-boot-starter-web                            org.springframework.boot            spring-boot-starter-actuator                            org.springframework.boot            spring-boot-devtools            runtime            true                            org.springframework.boot            spring-boot-starter-test            test                                com.atguigu.springcloud            cloud-api-commons            
复制代码
2.3.2 yml文件

  1. server:  port: 9001spring:  application:    name: nacos-payment  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848management:  endpoints:    web:      exposure:        include: '*'
复制代码
2.3.3 主启动类

  1. package com.atguigu.springcloud;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication@EnableDiscoveryClientpublic class NacosPaymentMain9001 {    public static void main(String[] args) {        SpringApplication.run(NacosPaymentMain9001.class,args);    }}
复制代码
2.3.4 Nacos支持AP和CP两种模式的切换


  • C是所有节点在同一时间看到的数据是一致的;而A的界说是所有的请求都会收到响应.
  • 何时选择何种模式
       
        一般来说,
        如果不需要存储服务级别的信息且服务实例是通过nacos-client注册,而且可以或许保持心跳上报,那么就可以选择AP模式.当主流的服务如Spring Cloud 和 Dubbo 服务,都是用于AP模式,AP模式为了服务的大概性而削弱了一致性,因此AP模式下支持注册临时实例.
        如果需要在服务级别编辑或者存储设置信息,那么CP是必须,K8S服务和DNS服务则适用于CP模式.
        CP模式下则支持注册长期化实例,此时则是以Raft协议为集群运行模式,该模式下注册实例之前必须先注册服务,如果服务不存在,则会返回错误.
        curl -X PUT ‘$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP’
       

2.4 Nacos作为服务设置中心

2.4.1 设置中心dataID设置

  文件后缀名不能写yml,要写yaml

2.4.2 pom文件

  1.             cloud2020        com.atguigu.springcloud        1.0-SNAPSHOT        4.0.0    cloud-alibaba-nacos-config-client3377                                com.alibaba.cloud            spring-cloud-starter-alibaba-nacos-config                                    com.alibaba.cloud            spring-cloud-starter-alibaba-nacos-discovery                            org.springframework.boot            spring-boot-starter-web                            org.springframework.boot            spring-boot-starter-actuator                            org.springframework.boot            spring-boot-devtools            runtime            true                            org.springframework.boot            spring-boot-starter-test            test                            com.atguigu.springcloud            cloud-api-commons                                                    org.springframework.boot                spring-boot-maven-plugin                        
复制代码
2.4.3 yaml文件

  1. # bootstrap.yml# nacos设置server:  port: 3377spring:  application:    name: nacos-config-client  cloud:    nacos:      discovery:        server-addr: localhost:8848  #Nacos作为服务注册中心地点      config:        server-addr: localhost:8848  #Nacos作为设置中心地点        file-extension: yaml  # 指定设置文件的格式为yaml        group: DEV_GROUP  #指定设置文件分组GROUP        namespace: 357392ad-2083-4c4a-afb1-945dc549080f  #通过定名空间ID指定定名空间#${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}# nacos-config-client-dev.yaml
复制代码
  1. # application.ymlspring:  profiles:    active: dev # 表现开辟情况   
复制代码
2.4.4 主启动类

  1. package com.atguigu.springcloud;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication@EnableDiscoveryClientpublic class ConfigClientMain3377 {    public static void main(String[] args) {        SpringApplication.run(ConfigClientMain3377.class,args);    }}
复制代码
2.4.5 业务类

  1. package com.atguigu.springcloud.controller;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Value;import org.springframework.cloud.context.config.annotation.RefreshScope;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/** 通过spring cloud的原生注解@RefreshScope 实现设置的自动刷新功能* */@RestController@Slf4j@RefreshScope   //支持nacos的动态刷新功能@RequestMapping("/config")public class ConfignClientController {    @Value("${config.info}")    private String configInfo;    @GetMapping("/info")    public String getConfigInfo(){        return "config info : " + configInfo;    }}
复制代码
2.4.6 分类设置

2.4.6.1 namespace+Group+DataID三者关系


  • 是什么
       

    • 雷同于Java内里的package名和类名
    • 最外层的namespace是可以用于鱼粉摆设情况的,Group和DataID逻辑上区分两个目标对象
       

  • 三者情况


  • 默认情况
       
        Namespace=public,Group=DEFAULT_GROUP,默认Cluster是DEFAULT
       

  

  • Nacos默认的定名空间是public,Namespace主要是用来实现隔离.
  • 比方说我们说我们现在有三个开辟情况:开辟,测试,生产情况,我们就可以创建三个Namespace,不同的Namespace之间是隔离的.
  • Group默认是DEFAULT_GROUP,Group可以把不同的微服务划分到同一个分组内里去
  • Service就是微服务;一个Service可以包罗多个Cluster(集群),Nacos默认Cluster是DEFAULT,Cluster是指对指定微服务的一个虚拟划分.
  • 比方说为了容灾,将Service微服务分别摆设在了杭州机房和广州机房,
  • 这时就可以给杭州机房的Service微服务起一个集群名称(HZ),
  • 给广州机房的Service微服务起一个集群名称(GZ),还可以只管让同一个机房的微服务互相调用,以提升性能.
  • 最后是Instance,就是微服务的实例.
2.4.6.1 三种法案加载设置


  • DataID方案
       

    • 指定spring.profile.active和设置文件的DataID来使不同情况下读取不同的设置
    • 默认空间+默认分组+新建dev和test两个DataID

      • 新建dev设置DataID----------nacos-config-client-dev.yaml
      • 新建test设置DataID----------nacos-config-client-test.yaml

    • 通过spring.profile.active属性就能举行多情况下文件的读取
      1. spring:  profiles:    active: dev # 表现开辟情况    #active: test   #表现测试情况
      复制代码
       

  • Group方案
       

    • 通过Group实现情况区分

      • 新建Group,在新建设置文件时,将DEFAULT_GROUP改为你要建的分组即可(比方DEV_GROUP)

    • 在nacos图形界面控制台上面新建设置文件DataID

      • 新建dev设置DataID----------nacos-config-client-dev.yaml

    • bootstrap+application

      • bootstrap文件在config下指定group
        1. spring:  application:    name: nacos-config-client  cloud:    nacos:      discovery:        server-addr: localhost:8848  #Nacos作为服务注册中心地点      config:        server-addr: localhost:8848  #Nacos作为设置中心地点        file-extension: yaml  # 指定设置文件的格式为yaml        group: DEV_GROUP  #指定设置文件分组GROUP
        复制代码
      • yml文件
        1. spring:  profiles:    active: dev # 表现开辟情况
        复制代码

       

  • Namespace方案
       

    • 新建dev/test的Namespace
    • 回到服务管理-服务列表检察
    • 按照域名设置填写
    • yml

      • bootstrap.yml
        1. spring:  application:    name: nacos-config-client  cloud:    nacos:      discovery:        server-addr: localhost:8848  #Nacos作为服务注册中心地点      config:        server-addr: localhost:8848  #Nacos作为设置中心地点        file-extension: yaml  # 指定设置文件的格式为yaml        group: DEV_GROUP  #指定设置文件分组GROUP        namespace: 357392ad-2083-4c4a-afb1-945dc549080f  #通过定名空间ID指定定名空间
        复制代码
      • application.yml
        1. spring:  profiles:    active: dev # 表现开辟情况
        复制代码

       

2.5 Nacos集群和长期化设置(重要)

2.5.1 说明


  • 默认Nacos使用嵌入式数据库实现数据存储.所以,如果启动多个默认设置下的Nacos节点,数据存储是存在一致性问题的.为相识决这个问题,Nacos接纳了集中式存储的方式来支持集群化摆设,现在只支持MySQL的存储.
  • Nacos支持三种摆设模式
       

    • 单机模式 - 用于测试和单机使用.

      • 在0.7版本之前,在单机模式时nacos使用嵌入式数据库实现数据的存储,不方便观察数据存储的基本情况.
      • 0.7版本之后增加了mysql数据源本事,详细的操作步调:

        • 安装数据库,版本要求: 5.6.5+
        • 初始化mysql数据库,数据库初始化文件:nacos-mysql.sql
        • 修改conf/application.properties文件,增加支持mysql数据源设置(现在只支持mysql),添加mysql数据源的url,用户名和暗码.



       
       
       
    1. 4. 再以单机模式启动nacos,nacos所有写嵌入式数据库的数据都写到了mysql.
    复制代码
       

    • 集群模式 - 用于生产情况,确保高可用.
    • 多集群模式 - 用于多数据中心场景.
       

2.5.2 Nacos长期化设置表明


  • Nacos默认自带的是嵌入式数据库derby
  • derby到mysql切换设置步调

    • nacos-server-1.1.4\nacos\conf目次下找到SQL脚本----nacos-mysql.sql-----并执行脚本
    • nacos-server-1.1.4\nacos\conf目次下找到application.properties,添加这段设置
      1. spring.datasource.platform=mysqldb.num=1db.url.0=jdbc:mysql://localhost:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=truedb.user=rootdb.password=123456
      复制代码

  • 启动Nacos,可以看到是个全新的空纪录界面,以前是纪录进derby
  • MYSQL暗码:u3w)D9Q&wb%w
3. SpringCloud Alibaba Sentinel

SentinelHystrix1.单独一个组件,可以独立出来1.需要我们程序员自己手工搭建监控平台2.直接界面化的细粒度统一设置2.没有一套web界面可以给我们举行更加细粒度化的设置流控,速率控制,服务熔断,服务降级…
  

  • 约定 > 设置 > 编码
  • 都可以写在代码内里,但是我们本次照旧大规模学习使用设置和注解的方式,只管少写代码
3.1 安装Sentinel控制台

3.1.1 组成

  Sentinel分为两个部分:
  

  • 焦点库(Java客户端)不依赖任何框架/库,可以或许运行于所有Java运行时情况,同时对Dubbo/SpringCloud等框架也有较好的支持.
  • 控制台(Dashboard)基于SpringBoot开辟,打包后可以直接运行,不需要额外的Tomcat等应用容器.
3.1.2 安装步调


  • 下载 https://github.com/alibaba/Sentinel/releases/download/1.7.0/sentinel-dashboard-1.7.0.jar
  • 运行下令
       

    • 前提

      • java 8 情况OK
      • 8080端口不能被占用

    • 下令 java -jar sentinel-dashboard-1.7.0.jar
       

  • 访问sentinel管理界面 localhost:8080
  • pom文件依赖
    1.                     com.alibaba.cloud            spring-cloud-starter-alibaba-sentinel                                    com.alibaba.csp            sentinel-datasource-nacos        
    复制代码
3.2 流控规则

3.2.1 基本介绍

  表明说明:
  

  • 资源名: 唯一名称,默认请求路径
  • 针对泉源: Sentinel可以针对调用者举行限流,填写微服务名,默认default(不区分泉源)
  • 阈值范例/单机阈值:

    • QPS(每秒钟的请求数量): 当调用该api的QPS到达阈值的时候,举行限流.
    • 线程数: 当调用该api的线程数到达阈值的时候,举行限流

  • 是否集群模式: 不需要集群
  • 流控模式:

    • 直接: api到达限流条件时,直接限流
    • 关联: 当关联的资源到达阈值时,就限流自己
    • 链路: 只纪录指定链路上的流量(指定资源从入口资源进来的流量,如果到达阈值,就举行限流) [api级别的针对泉源]

  • 流控效果:

    • 快速失败: 直接失败,抛异常
    • Warm Up: 根据codeFactor(冷加载因子,默认3)的值,从阈值/codeFactor,经过预热时长,才到达设置的QPS阈值
    • 列队等候: 匀速列队,让请求以匀速的速度通过,阈值范例必须设置为QPS,否则无效

3.2.2 流控模式


  • 直接(默认)
       
        表现1秒钟内查询一次就是OK,若高出一次,就直接-快速失败,报默认错误
       

       
       
        效果: Blocked by Sentinel (flow limiting)
        QPS和线程区别:

    • QPS把仇人抵抗在国门之外,高出阈值,就不让进来
    • 线程是放进来关门打狗,高出阈值,你进来,但是你在那给我等着.
       

  • 关联
       
        设置效果
        当关联资源/testB的QPS阈值高出1时,就限流/testA的Rest访问地点,当关联资源到达阈值后限制设置好的资源名
       

       

  • 链路
3.2.2 流控效果


  • 直接–>快速失败(默认的流控处理)
  • Warm up(预热)
       
        Warm Up(RuleConstant.CONTROL_BEHAVIOR_WAARM_UP)方式,即预热/冷启动方式.当系统恒久处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位大概瞬间把系统压垮.通过"冷启动",让通过的流量迟钝增加,在一定的时间内逐渐增加到阈值上线,给冷系统一个预热的时间,制止冷系统被压垮.详细文档可以参考流量控制 - Warm Up 文档

    • 说明: 公式: 阈值除以coldFactor(默认值为3),经过预热时长后才会到达阈值
    • 官网

      • 默认coldFactor为3,即请求QPS从threshold/3开始,经预热时长逐渐升至设定的QPS阈值.
      • 限流冷启动

    • Warm Up设置

      • 默认coldFactor为3,即请求QPS从(threshold/3)开始,经多少预热时长才逐渐升至设定的QPS阈值.
      • 案例,阈值为10 + 预热时长设置为5秒
        系统初始化的阈值为10/3约便是3,即阈值刚开始为3;然后过了5秒后阈值才逐步升高规复到10


       

  • 列队等候
       
        匀速列队,让请求以均匀的速度通过,阈值范例必须设置成QPS,否则无效.
        设置寄义: /testA每秒请求一次,高出的话就列队等候,等候的超时时间为20000毫秒.
       

       

3.3 Sentinel降级

3.3.1 基本介绍

  Sentinel熔断降级会在调用链路中某个资源出现不稳定状态时(比方调用超时或者异常比例升高),对这个资源的调用举行限制,让请求快速失败,制止影响到其他的资源而导致级联错误.
  挡子源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出DegradeException).
  Sentinel的断路器是没有半开状态的
  

  • 半开的状态系统自动去检测是否请求有异常,
  • 没有异常就关闭断路器规复使用,
  • 有异常则基础打开断路器不可用.


  • RT(均匀响应时间,秒级)
       
        均匀响应时间 超出阈值 且 在时间窗口期内通过的请求>=5, 两个条件同时满足后触发降级
        窗口期过后关闭断路器
        RT最大4900(更大的需要通过-Dcsp.sentinel.statistic.max.rt=XXXX才华生效)
       

  • 异常比例(秒级)
       
        QPS >= 5 且异常比例(秒级统计)高出阈值时,触发降级;时间窗口竣事后,关闭降级
       

  • 异常数(分钟级)
       
        异常数(分钟统计)高出阈值,触发降级;时间窗口竣事后,关闭降级
       

3.3.2 降级计谋实战


  • RT
       

    • 是什么
            
             均匀响应时间(DEGRADE_GRADE_RT): 当1s内一连进入5个请求,对应时刻的均匀响应时间(秒级)均高出阈值(count,以ms为单元),那么在接下来的时间窗口(DegradeRule中的timeWindow,以s为单元)之内,对这个方法的调用都会自动的熔断(抛出DegradeException).注意Sentinel默认统计的RT上线是4900ms,超出此阈值的都会算作4900ms,若需要变更此上限可以通过启动设置项-Dcsp.sentinel.statistic.max.rt=xxx来设置.
            

            

    • 测试

      • 测试代码
        1. @GetMapping("/testD")    public String getD(){        try {            TimeUnit.SECONDS.sleep(1);        } catch (InterruptedException e) {            e.printStackTrace();        }        log.info("testD   测试RT");        return "------testD";    }
        复制代码
      • 测试
                
                 

                 按照上述设置:

        • 永远一秒钟打进来10个线程(大于5个了)调用testD,我们希望200毫秒处理完本次的任务,
        • 如果高出200毫秒还没处理完,在未来一秒钟的窗口期内,断路器打开(保险丝跳闸)微服务不可用,保险丝跳闸断电了
        • 后续访问量没有那么大了,保险丝规复正常,微服务可以访问
                


       

  • 异常比例
       

    • 是什么
            
             异常比例(DEGRADE_GRADE_EXCEPTION_RATIO): 当资源的每秒请求量 >= 5,而且每秒异常总数占通过量的比值高出阈值(DegradeRule中的count)之后,资源进入降级状态,即在接下来的时间窗口(DegradeRule中的timeWindow,以s为单元)之内,对这个方法的调用都会自动地返回.异常比率的阈值范围[0.0,1.0],代表0% - 100%.
            

            

    • 设置
       

       
       
       
    1. @GetMapping("/testE")    public String getE(){        log.info("testE   测试异常比例");        int age = 10/0;        return "------testE";    }
    复制代码
       

    • 结论
            
             按照上述设置,
             单独访问一次,一定来一次报错一次(int age = 10/0),调一次错一次;
             开启jmeter后,直接高并发发送请求,多次调用到达我们的设置条件了.
             断路器开启(保险丝跳闸),微服务不可用了,不再报错error而是服务降级.
            

       

  • 异常数
       

    • 是什么
            
             异常数(DEGRADE_GRADE_EXCEPTION_COUNT): 当资源近1分钟的异常数目高出阈值之后会举行熔断.注意由于统计时间窗口是分钟级别的,若timeWindow小于60s,则竣事熔断状态后仍大概再进入熔断状态.
             时间窗口一定要大于便是60秒
            

            

    • 代码设置

      1. @GetMapping("/testF")    public String getF(){        log.info("testF   测试异常数");        int age = 10/0;        return "------testF";    }
      复制代码
       

3.4 热点key限流

3.4.1 是什么

  作甚热点?热点即常常访问的数据.许多时候我们希望统计某个热点数据中访问频次最高的Top K数据,并对其访问举行限制.比如:
  

  • 商品ID为参数,统计一段时间内最常购买的商品ID,并举行限制
  • 用户ID为参数,针对一段时间内频仍访问的用户ID举行限制
  热点参数限流会统计传入参数中的热点参数,并根据设置的限流阈值与模式,对包罗热点参数的资源调用举行限流.热点参数限流可以看做是一种特殊的流量控制,仅对包罗热点参数的资源调用生效.
3.4.2 返回的值(系统默认和自界说)


  • 兜底方法分为系统默认和用户自界说两种
  • 之前的case,限流出问题之后,都是用sentinel系统默认的提示: Blocked by Sentinel (flow limiting)
  • 现在我们可以自界说一个 从@HystrixCommand到@SentinelResource
3.4.3 代码设置

  1. @GetMapping("/getHotKey")    @SentinelResource(value = "getHotKey", blockHandler = "deal_getHotKey")    public String getHotKey(@RequestParam(value = "p1",required = false) String p1,                            @RequestParam(value = "p2",required = false) String p2){        log.info("getHotKey   测试热点key限流");        return "------getHotKey";    }    public String deal_getHotKey(String p1, String p2, BlockException exception){        log.info("deal_getHotKey    aaaaaa");        return "------deal_getHotKey";    }
复制代码


  • 第一种

    • @SentinelResource(value = “getHotKey”, blockHandler = “deal_getHotKey”)
    • 方法getHotKey内里第一个参数只要高出每秒1次,立即降级处理
    • 用了我们自界说的方法.效果:------deal_getHotKey

  • 第二种

    • @SentinelResource(value = “getHotKey”)
    • 异常打到了前台界面,对用户不友好,效果:


  • 所以,如果我们用热点key限流一定要写兜底的方法
3.4.4 参数破例项

  上述案例演示了第一个参数p1,当QPS高出1秒1次点击后立即被限流

  • 特例情况
       

    • 平凡 高出1秒后,到达阈值1后立即被限流
    • 我们盼望P1参数当他是某个特殊值时,它的限流值宁静常不一样
    • 特例 比方当p1的值便是5时,它的阈值可以到达200
       

  • 设置


  • 结论: http://localhost:8401/sentinel/getHotKey?p1=5 阈值在每秒200下,怎么点都可以
    http://localhost:8401/sentinel/getHotKey?p1=1 阈值照旧每秒1下,报错
  @SentinelResource
  处理的是Sentinel控制台设置的违规情况,有blockHandler方法设置的兜底处理;
  RuntimeException
  int age = 10/0,这个是java运行时爆出的运行时异常RuntimeException,@SentinelResource不管
  总结
  @SentinelResource主管设置堕落,运行堕落该走异常走异常
3.5 Sentinel系统规则

3.5.1 是什么

  系统掩护规则是从应用级别的入口流量举行控制,从单台呆板的load,cpu使用率,均匀RT,入口QPS和并发线程数等几个纬度监控应用指标,让系统尽大概泡在最大吞吐量的同时包管系统整体的稳定性.
  系统掩护规则是应用整体维度的,而不是资源维度的,而且仅对入口流量生效.入口流量指的是进入应用的流量(EntryType.IN),比如Web服务或Dubbo服务端吸收的请求,都从属于入口流量.
3.5.2 参数设置



  • 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到达阈值即触发系统掩护.
3.6 @SentinelResource

3.6.1 按资源名称限流+后续处理


  • 按照@SentinelResource资源名称设置流控规则
  • 因为我们写了兜底的方法,所以按照我们的方法执行
  • 产生的问题:关闭8401服务器,系统流控规则消失
3.6.2 按URL地点限流+后续处理


  • 按照URL地点举行设置流控规则
  • 我们没有写兜底的方法,所以就用系统默认自带的
  • 产生的问题:关闭8401服务器,系统流控规则消失
3.6.3 上面兜底方案面对的问题


  • 系统默认的,没有体现我们自己的业务要求.
  • 依照现有调价,我们自界说处理方法和业务代码耦合在一起,不直观.
  • 每个业务方法都添加一个兜底的方法,代码膨胀加剧.
  • 全局统一的处理方法没有体现.
3.6.4 客户自界说限流处理逻辑


  • 创建CustomerBlockHandler类用于自界说限流处理逻辑
  • 自界说限流处理类CustomerBlockHandler
    1. package com.atguigu.springcloud.myhandler;import com.alibaba.csp.sentinel.slots.block.BlockException;import com.atguigu.springcloud.utils.CommonResult;public class CustomerBlockHandler {    public static CommonResult handlerException(BlockException exception){        return new CommonResult(444,"用户自界说--------1");    }    public static CommonResult handlerException2(BlockException exception){        return new CommonResult(444,"用户自界说--------2");    }}
    复制代码
  • RateLimitController
    1. package com.atguigu.springcloud.controller;import com.alibaba.csp.sentinel.annotation.SentinelResource;import com.alibaba.csp.sentinel.slots.block.BlockException;import com.atguigu.springcloud.myhandler.CustomerBlockHandler;import com.atguigu.springcloud.utils.CommonResult;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/rate")public class RateLimitController {    @GetMapping("/consumerBlockHandler")    @SentinelResource(value = "consumerBlockHandler",            blockHandlerClass = CustomerBlockHandler.class,            blockHandler = "handlerException2")    public CommonResult consumerBlockHandler(){        return new CommonResult(200,"用户自界说----OK","我乐成了");    }}
    复制代码
  • 启动微服务后先调用一次
  • Sentinel控制台设置


  • 测试后我们自界说的出来了
3.7 服务熔断功能

  Sentinel整合ribbon+OpenFeign+fallback
3.7.1 服务熔断框架比较

SentinelHystrixresilience4j隔离计谋信号量隔离(并发线程数限流)线程池隔离/信号量隔离信号量隔离熔断降级计谋基于响应时间、一异常比率、异常数基于异常比率基于异常比率、响应时间实时统计实现滑动窗口(LeapArray)滑动窗口(基于RxJava)Ring Bit Buffer动态规则设置支持多种数据源支持多种数据源有限支持扩展性多个扩展点插件的形式接口的形式扩展性多个扩展点插件的形式接口的形式基于注解的支持支持支持支持限流基于QPS,支持基于调用关系的限流有限的支持Rate Limiter流量整形支持预热模式、匀速器模式、预热列队模式不支持简单的Rate Limiter模式系统自适应掩护支持不支持不支持控制台提供开箱即用的控制台,可设置规则、检察秒级监控、呆板发现等简单的监控检察不提供控制台,可对接其他监控系统3.8 规则长期化

3.8.1 是什么

  一旦我们重启应用,sentinel规则将消失,生产情况需要将设置规则举行长期化
3.8.2 怎么用

  将限流设置规则长期化进Nacos生存,只要刷新8401某个rest地点,sentinel控制台的流控规则就能看到,只要Nacos内里的设置不删除,针对8401上sentinel上的流控规则一连有效
3.8.3 步调


  • pom文件
    1.   com.alibaba.csp  sentinel-datasource-nacos
    复制代码
  • yml文件
    1. spring:  application:    name: nacos-sentinel-service  cloud:    nacos:      discovery:        # nacos 服务注册中心地点        server-addr: 127.0.0.1:8848    sentinel:      transport:        # 设置中心 sentinel dashboard地点        dashboard: 127.0.0.1:8080        # 默认8719端口,如果被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口        port: 8719      datasource:        ds1:          nacos:            server-addr: localhost:8848            dataId: nacos-sentinel-service            groupId: DEFAULT_GROUP            data-type: json            rule-type: flow
    复制代码
  • nacos新建设置
    1. [    {        "resource":"/rate/byResource",        "limitApp":"default",        "grade":1,        "count":1,        "strategy":0,        "controlBehavior":0,        "clusterMode":false    }]resource: 资源名称limitApp: 泉源应用grade: 阈值范例, 0表现线程数, 1表现QPScount: 单机阈值strategy: 流控模式, 0表现直接, 1表现关联, 2表现链路controlBehavior: 流控效果, 0表现快速失败, 1表现Warm Up, 2表现列队等候clusterMode: 是否集群
    复制代码
4. Spring Cloud Alibaba Seata处理分布式事务

4.1 分布式事务问题


  • 分布式前: 单机单库没有任何问题 从1:1 --> 1:N --> N:N
  • 分布式之后:
       
        单体应用被拆分成微服务应用,原来的三个模块被拆分成三个独立的应用,分别使用三个独立的数据源,
        业务操作需要三个微服务来完成.此时每个服务内部的数据一致性由当地事务来包管,但是全局的数据一致性问题没有办法包管
       

       
       
       

       

  • 一次业务操作需要跨多个数据源或需要跨多个系统举行远程调用,就会产生分布式事务问题
4.2 Seata简介

4.2.1 是什么

  Seata是一款开源的分布式事务办理方案,致力于在微服务架构下提供高性能和简单应用的分布式事务服务
  http://seata.io/zh-cn
4.2.2 能干嘛


  • 一个范例的分布式事务过程

    • 分布式事务处理过程的一ID+三组件模子

      • Transaction ID XID 全局唯一的事务ID
      • 3组件概念
              


        • Transaction Coordinator(TC) - 事务协调者
          事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚;
        • Transaction Manager™ - 事务管理器
          控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的协议;
        • Resource Manager(RM) - 资源管理器
          控制分支事务,负责分支注册、状态陈诉,并吸收事务协调器的指令,驱动分支(当地)事务的提交和回滚.
              


    • 处理过程
           

      • TM向TC申请开启一个全局事务,全局事务创建乐成而且生成一个全局唯一的XID;
      • XID在微服务调用链路的上下文中流传;
      • RM向TC注册分支事务,将其纳入XID对应全局事务的管辖;
      • TM向TC发起针对XID的全局提交或回滚决定;
      • TC调治XID下管辖的全部分支事务完成提交或回滚请求.
            

           


4.2.3 怎么用


  • 当地 @Transactional
  • 全局 @GlobalTransactional
4.3 Seata-Server安装


  • 下载 http://seata.io/zh-cn
  • 解压缩
  • 修改conf目次下的file.conf文件
    1. service {  #vgroup->rgroup  # vgroup_mapping.my_test_tx_group 修改为自己的名字,默认为default  vgroup_mapping.my_test_tx_group = "fsp_tx_group"    #only support single node  default.grouplist = "127.0.0.1:8091"  #degrade current not support  enableDegrade = false  #disable  disable = false  #unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent  max.commit.retry.timeout = "-1"  max.rollback.retry.timeout = "-1"}store {  ## store mode: file、db、redis  mode = "db"  # file修改为 db    # 下面的数据库设置修改为自己的  db {    ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp)/HikariDataSource(hikari) etc.    datasource = "druid"    ## mysql/oracle/postgresql/h2/oceanbase etc.    dbType = "mysql"    driverClassName = "com.mysql.jdbc.Driver"    url = "jdbc:mysql://127.0.0.1:3306/seata"    user = "root"    password = "123456"    minConn = 5    maxConn = 100    globalTable = "global_table"    branchTable = "branch_table"    lockTable = "lock_table"    queryLimit = 100    maxWait = 5000  }}
    复制代码
  • 创建seata数据库,将conf/db_store.sql粘脚本建表
  • 修改conf/registry.conf文件
    1. registry {  # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa  # type从file修改为nacos  type = "nacos"  nacos {  #nacos地点修改为自己的地点    serverAddr = "localhost:8848"    namespace = ""    cluster = "default"  }
    复制代码
4.4 订单/库存/账户业务数据库准备

4.4.1 业务说明

  这里我们会创建三个服务,一个订单服务,一个库存服务,一个账户服务.
  当用户下单时,会在订单服务中创建一个订单,然后通过远程调用库存服务来扣减下单商品的库存,
  再通过远程调用账户服务来扣减用户账户内里的余额,
  最后在订单服务中修改订单状态位已完成.
  该操作超过三个数据库,有两次远程调用,很显着会有分布式事务问题.
4.4.2 创建业务数据库


  • seata_order: 存储订单的数据库;
    1. -- 建表 t_order/* Navicat Premium Data Transfer Source Server         : 当地 Source Server Type    : MySQL Source Server Version : 50706 Source Host           : localhost:3306 Source Schema         : seata_order Target Server Type    : MySQL Target Server Version : 50706 File Encoding         : 65001 Date: 28/12/2020 16:34:14*/SET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS = 0;-- ------------------------------ Table structure for t_order-- ----------------------------DROP TABLE IF EXISTS `t_order`;CREATE TABLE `t_order`  (  `id` bigint(11) NOT NULL,  `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) UNSIGNED NULL DEFAULT NULL COMMENT '订单状态: 0创建中,1已完结',  PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '订单表' ROW_FORMAT = Compact;-- ------------------------------ Records of t_order-- ----------------------------INSERT INTO `t_order` VALUES (51, 1, 1, 10, 100, 1);INSERT INTO `t_order` VALUES (52, 1, 1, 10, 100, 1);INSERT INTO `t_order` VALUES (53, 1, 1, 10, 100, 1);INSERT INTO `t_order` VALUES (54, 1, 1, 10, 100, 0);SET FOREIGN_KEY_CHECKS = 1;-- 建回滚日志表conf/db_undo_log.sql
    复制代码
  • seata_storage: 存储库存的数据库;
    1. --建表 t_storage/* Navicat Premium Data Transfer Source Server         : 当地 Source Server Type    : MySQL Source Server Version : 50706 Source Host           : localhost:3306 Source Schema         : seata_storage Target Server Type    : MySQL Target Server Version : 50706 File Encoding         : 65001 Date: 28/12/2020 16:34:34*/SET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS = 0;-- ------------------------------ Table structure for t_storage-- ----------------------------DROP TABLE IF EXISTS `t_storage`;CREATE TABLE `t_storage`  (  `id` bigint(11) NOT NULL,  `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 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '库存' ROW_FORMAT = Compact;-- ------------------------------ Records of t_storage-- ----------------------------INSERT INTO `t_storage` VALUES (1, 1, 100, 0, 100);SET FOREIGN_KEY_CHECKS = 1;-- 建回滚日志表conf/db_undo_log.sql
    复制代码
  • seata_account: 存储账户信息的数据库.
    1. --建表 t_account/* Navicat Premium Data Transfer Source Server         : 当地 Source Server Type    : MySQL Source Server Version : 50706 Source Host           : localhost:3306 Source Schema         : seata_account Target Server Type    : MySQL Target Server Version : 50706 File Encoding         : 65001 Date: 28/12/2020 16:34:27*/SET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS = 0;-- ------------------------------ Table structure for t_account-- ----------------------------DROP TABLE IF EXISTS `t_account`;CREATE TABLE `t_account`  (  `id` bigint(11) NOT NULL,  `user_id` bigint(11) NULL DEFAULT NULL COMMENT '用户ID',  `total` decimal(10, 0) NULL DEFAULT NULL COMMENT '总额度',  `used` decimal(10, 0) NULL DEFAULT NULL COMMENT '已用额度',  `residue` decimal(10, 0) NULL DEFAULT NULL COMMENT '剩余可用额度',  PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '账户信息' ROW_FORMAT = Compact;-- ------------------------------ Records of t_account-- ----------------------------INSERT INTO `t_account` VALUES (1, 1, 1000, 0, 1000);SET FOREIGN_KEY_CHECKS = 1;-- 建回滚日志表conf/db_undo_log.sql
    复制代码
4.5 订单/库存/账户业务微服务准备

4.5.1 业务需求

  下订单->减库存->扣余额->改(订单)状态
4.5.2 订单微服务准备


  • pom文件
    1.             cloud2020        com.atguigu.springcloud        1.0-SNAPSHOT        4.0.0    seata-order-service2001                                com.alibaba.cloud            spring-cloud-starter-alibaba-nacos-discovery                                    com.alibaba.cloud            spring-cloud-starter-alibaba-sentinel                                    com.alibaba.csp            sentinel-datasource-nacos                                    com.alibaba.cloud            spring-cloud-starter-alibaba-seata                                                seata-all                    io.seata                                                                io.seata            seata-all            0.9.0                                    org.springframework.cloud            spring-cloud-starter-openfeign                            mysql            mysql-connector-java                            org.springframework.boot            spring-boot-starter-jdbc                                    org.mybatis.spring.boot            mybatis-spring-boot-starter            2.0.0                            org.springframework.boot            spring-boot-starter-web                            org.springframework.boot            spring-boot-starter-actuator                            org.springframework.boot            spring-boot-devtools            runtime            true                            org.springframework.boot            spring-boot-starter-test            test                            com.atguigu.springcloud            cloud-api-commons                                                    org.springframework.boot                spring-boot-maven-plugin                        
    复制代码
  • yam文件
    1. server:  port: 2001spring:  application:    name: seata-order-service  cloud:    alibaba:      seata:        tx-service-group: my_test_tx_group    nacos:      discovery:        server-addr: localhost:8848  datasource:    driver-class-name: com.mysql.jdbc.Driver    url: jdbc:mysql://localhost:3306/seata_order?useUnicode=true&rewriteBatchedStatements=true&useSSL=true    username: root    password: 123456feign:  hystrix:    enabled: truelogging:  level:    io:      seata: info# mybatis设置mybatis:  mapperLocations: classpath:mapper/*.xml  type-aliases-package: com.atgui.springcloud.domain  #实体类包
    复制代码
  • DataSourceProxyConfig设置类
    1. package com.atgui.springcloud.config;import com.alibaba.druid.pool.DruidDataSource;import io.seata.rm.datasource.DataSourceProxy;import org.apache.ibatis.session.SqlSessionFactory;import org.mybatis.spring.SqlSessionFactoryBean;import org.mybatis.spring.transaction.SpringManagedTransactionFactory;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import javax.sql.DataSource;/** * 使用seata对数据源举行代理 * */@Configurationpublic class DataSourceProxyConfig {    @Value("${mybatis.mapperLocations}")    private String mapperLocations;    @Bean    @ConfigurationProperties(prefix = "spring.datasource")    public DataSource druidDataSource(){        return new DruidDataSource();    }    @Bean    public DataSourceProxy dataSourceProxy(DataSource dataSource){        return new DataSourceProxy(dataSource);    }    @Bean    public SqlSessionFactory sqlSessionFactoryBean(DataSourceProxy dataSourceProxy) throws Exception{        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();        sqlSessionFactoryBean.setDataSource(dataSourceProxy);        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));        sqlSessionFactoryBean.setTransactionFactory(new SpringManagedTransactionFactory());        return sqlSessionFactoryBean.getObject();    }}
    复制代码
  • MybatisConfig设置类
    1. package com.atgui.springcloud.config;import org.mybatis.spring.annotation.MapperScan;import org.springframework.context.annotation.Configuration;@Configuration@MapperScan({"com.atgui.springcloud.dao"})public class MyBatisConfig {}
    复制代码
  • service实现类
    1. package com.atgui.springcloud.service.impl;import com.atgui.springcloud.dao.OrderDao;import com.atgui.springcloud.domain.Order;import com.atgui.springcloud.service.AccountService;import com.atgui.springcloud.service.OrderService;import com.atgui.springcloud.service.StorageService;import io.seata.spring.annotation.GlobalTransactional;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Service;import javax.annotation.Resource;@Service@Slf4jpublic class OrderServiceImpl implements OrderService {    @Resource    private OrderDao dao;    @Resource    private StorageService storageService;    @Resource    private AccountService accountService;    @Override    @GlobalTransactional(name = "order-create",rollbackFor = Exception.class)    public void create(Order order) {        //1.创建订单        log.info("--------开始创建订单---------");        dao.create(order);        //2.调用库存服务,扣减数量        log.info("--------订单微服务调用库存微服务,扣减数量---------");        storageService.decrease(order.getProductId(),order.getCount());        //3.调用账户服务,扣减money        log.info("--------订单微服务调用账户微服务,扣减钱---------");        accountService.decrease(order.getUserId(),order.getMoney());        //4.修改订单状态        log.info("--------修改订单状态开始---------");        dao.update(order.getUserId(),0);        log.info("--------修改订单状态竣事---------");        log.info("--------下订单竣事---------");    }}
    复制代码
4.7 Seata增补

4.7.1 执行流程


  • TM开启分布式事务(TM向TC注册全局事务纪录);
  • 按业务场景,编排数据库、服务等事务内资源(RM向TC会报资源准备状态);
  • TM竣事分布式事务,事务一阶段竣事(TM通知TC提交/回滚分布式事务);
  • TC汇总事务信息,决定分布式事务是提交照旧回滚;
  • TC通知所有RM提交/回滚资源,事务二阶段竣事.
4.7.2 AT模式如何做到对业务的无侵入

  Seata是一款开源的分布式事务办理方案,致力于提供高性能和浅易使用的分布式事务服务.Seata将为用户提供了AT、TCC、SAGA和XA事务模式,为用户打造一站式的分布式办理方案.

  • AT模式
       

    • 前提

      • 基于当地ACID事务的关系型数据库
      • Java应用,通过JDBC访问数据库

    • 整体机制(两阶段提交协议的演变)

      • 一阶段: 业务数据和回滚日志纪录在同一个当地事务中提交,释放当地锁和毗连资源.
      • 二阶段:

        • 提交异步化,非常快速地完成.
        • 回滚通过一阶段的回滚日志举行反向赔偿.


       

  • 一阶段加载
       
        在一阶段,Seata会拦截"业务SQL",
        1 . 剖析SQL语义,找到"业务SQL"要更新的业务数据,在业务数据被更新前,将其生存成"before image",
        2 . 执行"业务SQL"更新业务数据,在业务数据更新之后,
        3 . 将其生存成"after image",最后生成行锁.
        以上操作全部在一个数据库事务内完成,这样包管了一阶段操作的原子性.
       

       

  • 二阶段提交
       
        二阶段如果顺利提交的话,
        因为"业务SQL"在一阶段已经提交至数据库,所以Seata只需将一阶段生存的快照数据和行锁删掉,完成数据清理即可.
       

       

  • 二阶段回滚
       
        二阶段如果是回滚的话,Seata就需要回滚一阶段已经执行的"业务SQL",还原业务数据.
        回滚方式便是用"before image" 还原业务数据;但在还原前要首先要校验脏写,对比"数据库当前业务数据"和"after image",
        如果两份数据完全一致就说明没有脏写,可以还原业务数据,如果不一致就说明有脏写,出现脏写就需要转人工处理.
       

       

  • 增补


来源:https://blog.csdn.net/qq_43701330/article/details/111992660
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

发布主题

专注素材教程免费分享
全国免费热线电话

18768367769

周一至周日9:00-23:00

反馈建议

27428564@qq.com 在线QQ咨询

扫描二维码关注我们

Powered by Discuz! X3.4© 2001-2013 Comsenz Inc.( 蜀ICP备2021001884号-1 )