SpringCloud(17~21章):Alibaba入门简介、Nacos服务注册和配置中心、Sentinel实现熔断与限流、Seata处理分布式事务

17 SpringCloud Alibaba入门简介

17.1 why会出现SpringCloud alibaba

  • Spring Cloud Netflix项目进入维护模式

  • Spring Cloud Netflix Projects Entering Maintenance Mode

    • 什么是维护模式
      • 将模块置于维护模式,意味着 Spring Cloud 团队将不会再向模块添加新功能。我们将修复 block 级别的 bug 以及安全问题,我们也会考虑并审查社区的小型 pull request。
    • 进入维护模式意味着什么呢?
      • Spring Cloud Netflix 将不再开发新的组件
      • 我们都知道Spring Cloud 版本迭代算是比较快的,因而出现了很多重大ISSUE都还来不及Fix就又推另一个Release了。进入维护模式意思就是目前一直以后一段时间Spring Cloud Netflix提供的服务和功能就这么多了,不在开发新的组件和功能了。以后将以维护和Merge分支Full Request为主
      • 新组件功能将以其他替代平代替的方式实现

17.2 SpringCloud alibaba带来了什么

是什么

  • 官网:
    • https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md
  • 诞生:
    • 2018.10.31,Spring Cloud Alibaba 正式入驻了 Spring Cloud 官方孵化器,并在 Maven 中央库发布了第一个版本。

去哪下:

  • https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md
  • 之前在pom文件已经引入此依赖了

能干嘛:

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

怎么玩

  • 如下图:

17.3 SpringCloud alibaba学习资料获取

18 Nacos服务注册和配置中心

  • SpringCloud Alibaba----Nacos服务注册和配置中心

18.1 Nacos简介

18.1.1 为什么叫Nacos

18.1.2 是什么

  • 一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
  • Nacos: Dynamic Naming and Configuration Service
  • Nacos就是注册中心 + 配置中心的组合
    • 等价于:Nacos = Eureka+Config +Bus

18.1.3 能干嘛

  • 替代Eureka做服务注册中心
  • 替代Config做服务配置中心

18.1.4 去哪下

  • 官网:https://nacos.io/zh-cn/index.html

  • 下载地址:https://github.com/alibaba/nacos/releases

  • spring-cloud-alibaba在GitHub上面的总文档:使用Nacos

    • https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_nacos_discovery
  • 也可以直接在Nacos官网中查看文档:

18.1.5 各种注册中心比较(简单讲解)

据说 Nacos 在阿里巴巴内部有超过 10 万的实例运行,已经过了类似双十一等各种大型流量的考验

18.2 安装并运行Nacos

18.2.1 新老版本说明

  • GitHub官网查看各个组件对应的版本:

    • https://github.com/alibaba/spring-cloud-alibaba

  • 老版本的直接启动即可

  • 新版本需要修改配置文件才能启动成功:

    • 官方文档说明:

    • 原因:老版本的鉴权有默认值,新版本为了安全去掉了默认值所以需要手动配置

    • 如何修改查看:B站动力节点SpringCloud视频

18.2.2 运行

  • 下载之后解压压缩包

  • 本地Java8+Maven环境已经OK

  • 在bin目录中输入cmd,进入到命令行窗口

    • 启动命令:startup.cmd -m standalone
    • standalone代表着单机模式运行,非集群模式
  • 命令运行成功后直接访问:http://localhost:8848/nacos

    • 默认账号密码都是nacos

18.3 Nacos作为服务注册中心演示

18.3.1 官网文档

18.3.2 基于Nacos的服务提供者

1)新建Module:cloudalibaba-provider-payment9001
2)POM
  • 父POM:之前已经引入过,这样子工程不需要每次都引入了。
xml 复制代码
            <!--spring cloud alibaba-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
  • 本模块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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.angenin.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.angenin.springcloud.alibaba</groupId>
    <artifactId>cloudalibaba-provider-payment9001</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- SpringBoot整合Web组件 -->
        <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>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>
  • 查看官网文档:
    • spring cloud alibaba依赖坐标
    • SpringCloud ailibaba nacos依赖坐标
3)YML
yml 复制代码
server:
  port: 9001

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #配置Nacos地址

management:
  endpoints:
    web:
      exposure:
        include: '*'    #暴露监控所有的端点
  • 官方文档:
4)主启动
java 复制代码
package com.angenin.springcloud.alibaba;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient   //这个注解和之前的不一样,开启服务注册功能
@SpringBootApplication
public class PaymentMain9001 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain9001.class, args);
    }

}
  • 官方文档
5)业务类
java 复制代码
package com.angenin.springcloud.alibaba.controller;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PaymentController {

    @Value("${server.port}")
    private String serverPort;

    @GetMapping(value = "/payment/nacos/{id}")
    public String getPayment(@PathVariable("id") Integer id) {

        return "nacos registry, serverPort: "+ serverPort+"\t id"+id;
    }
}
6)测试
  • 启动Nacos8848注册中心,启动9001生产者

    • 不像Eureka需要自己构建服务模块才能使用,这个只需要安装就可以用了。
  • 访问控制层方法:http://localhost:9001/payment/nacos/1

  • nacos控制台:http://localhost:8848/nacos

    • 默认账号密码都是nacos
  • nacos服务注册中心+服务提供者9001都OK了

7)提前创建9002
  • nacos自带负载均衡功能:为了下一章节演示nacos的负载均衡,参照9001新建9002

  • 方式一:取巧不想新建重复体力劳动,直接拷贝虚拟端口映射

    • 有时候可能会报错。
  • 方式二:手动创建新建 cloudalibaba-provider-payment9002

    • 创建步骤:略

    • 效果:

  • 启动9001,9002查看后台管理界面:

18.3.3 基于Nacos的服务消费者

1)新建Module:cloudalibaba-consumer-nacos-order83
2)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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.angenin.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.angenin.springcloud.alibaba</groupId>
    <artifactId>cloudalibaba-consumer-nacos-order83</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.angenin.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- SpringBoot整合Web组件 -->
        <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>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>
  • 为什么nacos支持负载均衡:自动集成了Ribbon(新版本没有,已经被LoadBalancer代替了
3)YML
yml 复制代码
server:
  port: 83

spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848   #Nacos注册中心的地址

#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)
#之前直接写的是生产者集群服务的名称 写死了,现在是写在配置文件中通过注解@Value读取获得
service-url:
  nacos-user-service: http://nacos-payment-provider
4)主启动
java 复制代码
package com.angenin.springcloud.alibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class OrderNacosMain83 {
    public static void main(String[] args) {

        SpringApplication.run(OrderNacosMain83.class,args);
    }
}
5)配置类
java 复制代码
package com.angenin.springcloud.alibaba.config;


import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContextBean {

    @Bean
    @LoadBalanced //使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
    public RestTemplate getRestTemplate() {
        //RestTemplate提供了多种便捷访问远程http访问的方法
        return new RestTemplate();
    }
}
6)业务类
java 复制代码
package com.angenin.springcloud.alibaba.controller;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
public class OrderNacosController {
    @Resource
    private RestTemplate restTemplate;

    //之前直接写的是生产者集群服务的名称 写死了,现在是写在配置文件中通过注解@Value读取获得
    @Value("${service-url.nacos-user-service}")
    private String serverURL;

    @GetMapping("/consumer/payment/nacos/{id}")
    public String paymentInfo(@PathVariable("id") Long id) {
        
        //getForObject两个参数:请求地址,返回的对象类型----读操作
        return restTemplate.getForObject(serverURL+"/payment/nacos/"+id,String.class);
    }

}
7)测试

18.3.4 服务注册中心对比(细节讲解)

  • Nacos全景图所示

  • Nacos和CAP

  • 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'

18.4 Nacos作为服务配置中心演示

18.4.1 Nacos作为配置中心-基础配置

1)新建:cloudalibaba-config-nacos-client3377
2)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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.angenin.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-config-nacos-client3377</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--nacos-config-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--nacos-discovery-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--web + actuator-->
        <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-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>


</project>
3)YML
  • why配置两个
    • Nacos同springcloud-config一样,在项目初始化时,要保证先从配置中心进行配置拉取,拉取配置之后,才能保证项目的正常启动。
    • springboot中配置文件的加载是存在优先级顺序的,bootstrap优先级高于application
    • 即:bootstrap存放拉去配置中心共有的, application存放自己本地的
  • bootstrap.yml
yml 复制代码
# nacos配置
server:
  port: 3377

spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #Nacos服务注册中心地址
      config:
        server-addr: localhost:8848 #Nacos作为配置中心地址
        file-extension: yaml #指定yaml格式的配置(3377就可以到8848上去读取,后缀名指定为yaml格式的文件)


# ${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension}

# nacos-config-client-dev.yaml   (不识别yml)
  • application.yml
yml 复制代码
spring:
  profiles:
    active: dev #表示开发环境

# 这样bootstrap+application结合起来就相当于:3377到8848配置中心上去读取,一个什么样的yml文件
4)主启动
java 复制代码
package com.angenin.springcloud;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class NacosConfigClientMain3377
{
    public static void main(String[] args) {
        SpringApplication.run(NacosConfigClientMain3377.class, args);
    }
}
5)业务类

通过Spring Cloud 原生注解@RefreshScope实现配置自动更新:

  • 之前是在SpringCloud Config分布式配置中心解决:不需要重启就可以手动刷新功能,之后还需要发送post请求生效。
java 复制代码
package com.angenin.springcloud.controller;

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.RestController;

@RestController
@RefreshScope //在控制器类加入@RefreshScope注解使当前类下的配置支持Nacos的动态刷新功能。
public class ConfigClientController {

    /**
     * 和之前学习SpringCloud Config分布式配置中心一样:
     * 分布式配置中心可以,将配置信息以REST接口的形式暴露:post、curl访问刷新均可......
     * 既然配置信息暴漏了,那么3355就可以通过REST风格读取到3344配置中心的消息和内容的配置。
     */
    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/config/info")
    public String getConfigInfo() {
        return configInfo;
    }
}
6)在Nacos中添加配置信息:Nacos中的匹配规则

理论:

实操:

  • 配置新增:nacos-config-client-dev

  • Nacos界面配置对应

yml 复制代码
config:
    info: nacos config center,version = 1
  • 点击发布:配置列表就多了一行配置信息

  • 总结:设置DataId

    • 公式:${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
    • prefix 默认为 spring.application.name 的值
    • spring.profile.active 即为当前环境对应的 profile,可以通过配置项 spring.profile.active 来配置。
    • file-exetension 为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension 来配置
    • 画图说明:
  • 历史配置

    • Nacos会记录配置文件的历史版本默认保留30天,此外还有一键回滚功能,回滚操作将会触发配置更新
    • 回滚
7)测试
  • 启动前需要在nacos客户端-配置管理-配置管理栏目下有对应的yaml配置文件
  • 启动nacos
  • 运行cloud-config-nacos-client3377的主启动类
  • 调用接口查看配置信息:http://localhost:3377/config/info
8)自带动态刷新
  • 修改下Nacos中的yaml配置文件,再次调用查看配置的接口,就会发现配置已经刷新

18.4.2 Nacos作为配置中心-分类配置

1)问题:多环境多项目管理
  • 问题1:
    • 实际开发中,通常一个系统会准备
      • dev开发环境
      • test测试环境
      • prod生产环境。
    • 如何保证指定环境启动时服务能正确读取到Nacos上相应环境的配置文件呢?
  • 问题2:
    • 一个大型分布式微服务系统会有很多微服务子项目,每个微服务项目又都会有相应的开发环境、测试环境、预发环境、正式环境...
    • 那怎么对这些微服务配置进行管理呢?
2)Nacos的图形化管理界面
  • 配置管理

  • 命名空间

3)Namespace+Group+Data ID三者关系?为什么这么设计?
  • 是什么

    • 类似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,就是微服务的实例。

18.4.3 案例:三种方案加载配置

1)DataID方案
  • 指定spring.profile.active和配置文件的DataID来使不同环境下读取不同的配置

  • 默认空间+默认分组+新建dev和test两个DataID

    • 新建dev配置DataID:就是上面创建的哪个
    • 新建test配置DataID
  • 通过spring.profile.active属性就能进行多环境下配置文件的读取

  • 测试

2)Group方案
  • 通过Group实现环境区分:新建Group

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


  • bootstrap+application

    • 在config下增加一条group的配置即可。
      可配置为DEV_GROUP或TEST_GROUP
  • 测试

  • 流程:nacos-config-client + TEST_GROUP + info + yaml

    • 表示找的是nacos-config-client微服务下的TEST_GROUP分组下的,前缀为info ,后缀为yaml的文件
3)Namespace方案
  • 新建dev/test的Namespace


  • 回到服务管理-服务列表查看

  • 按照域名配置填写



  • YML

    • bootstrap

    • application

  • 测试:

  • 启动Nacos,3377

  • http://localhost:3377/config/info

  • 此时找的是:dev命名空间下的+TEST_GROUP分组下的+dev前缀+yaml后缀文件

18.5 Nacos集群和持久化配置(重要)

  • 之前使用eureka注册中心需要手动创建模块,而Nacos不需要创建只需要解压使用即可
  • eureka有自我保护机制问题,但是Nacos把他屏蔽了没有这些问题。

18.5.1 官网说明

  • 官方文档2.x:https://nacos.io/zh-cn/docs/v2/guide/admin/cluster-mode-quick-start.html

  • 官网架构图(写的o(╥﹏╥)o)(vip:虚拟ip)

  • 上图官网翻译,真实情况

  • 说明:

    • 默认Nacos使用嵌入式数据库实现数据的存储。所以,如果启动多个默认配置下的Nacos节点,数据存储是存在一致性问题的。
      为了解决这个问题,Nacos采用了集中式存储的方式来支持集群化部署,目前只支持MySQL的存储。
      • 即:内存的东西一般断电就没了,但是我们在nacos中配置的作为配置中心时的yml配置文件,在重启nacos后发现还存在。原因:是nacos自带了内嵌是的数据库derby。问题:这样如果是集群模式每个nacos都携带了一个derby,数据的一致性统一会出现问题。解决:把数据都存储在一个mysql数据库集群中。
    • 按照上述,我们需要mysql数据库
    • 官方文档2.x:

18.5.2 Nacos持久化配置解释

1)Nacos自带数据库derby
2)derby到mysql切换配置步骤
  • 步骤1:nacos-server-1.1.4\nacos\conf目录下找到sql脚本

    • nacos-mysql.sql

    • 执行脚本:先创建一个数据库nacos_config(从脚本文件中查看,名字自己随便写一个也行)

  • 步骤2:nacos-server-1.1.4\nacos\conf目录下找到application.properties(需要多加个时区否则报错:startup.cmd -m standalone

java 复制代码
spring.datasource.platform=mysql

db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?&serverTimezone=UTC&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=root
  • 配置来源于官网文档:
2)重启Nacos进行测试
  • 在bin目录中输入cmd,进入到命令行窗口

    • 启动命令:startup.cmd -m standalone
    • standalone代表着单机模式运行,非集群模式
  • 命令运行成功后直接访问:http://localhost:8848/nacos

    • 默认账号密码都是nacos
  • 效果:重启Nacos,可以看到是个全新的空记录界面,以前是记录进derby

  • 测试:

    • 在配置;列表添加一个配置信息

    • 可以看到数据已经存储到了mysql数据库中

18.5.3 Linux版Nacos+MySQL生产环境配置

这个虚拟机SpringCloud之前配置的有

  • Zookeeper服务注册中心,运行环境依赖jdk,所以需要配置Zookeeper和jdk
  • 学习SpringCloud Bus消息总线屏蔽不同的消息中间件差异时,配置了RabbitMQ,依赖于erlang环境
1)Nacos集群部署架构说明
  • 说明 :按照Nacos官网配置集群的说明,nginx要配置成集群,Nacos配置成集群,MySQL配置成高可用。此时为了学习阶段方便测试配置成 1个Nginx+3个nacos注册中心+1个mysql
  • 条件有限只有一台电脑,如果配置成3个虚拟机占用内存太大。所以我们配置成伪集群,在当前一台虚拟机上配置成3个Nacos节点。

  • 官网集群环境要求:

2)nginx下载 安装 配置(linux系统)

详情查看:我写的另一篇博客:https://blog.csdn.net/aa35434/article/details/124853852

  • 安装完成后访问:http://192.168.10.140/
  • 启动:
    • 进入到安装后的sbin目录:cd /usr/local/src/Nginx/sbin/

    • ./nginx 启动

    • ./nginx -s stop 快速停止

    • ./nginx -v 查看 nginx 版本号

3)mysql下载 安装 配置(linux系统)

详情查看:我写的另一篇博客:https://blog.csdn.net/aa35434/article/details/124716035

  • 设置的有开机自动启动

  • 安装完成后使用sqlyog远程登录连接

4)Nacos之Linux版本安装
  • 下载步骤

  • 查看目录:windows启动使用的是startup.cmd,linux执行的是startup.sh

  • 在配置之前,先保存一份原始的配置,以防以后改错恢复配置时麻烦。(要养成这个习惯)

  • 问题:原先只有一个Nacos,直接使用命令启动即可。现在有3个Nacos组成的集群,那么使用命令该如何区分启动的是集群中的哪一个Nacos呢???

  • 解决:修改linux里面的nacos脚本,可以通过端口号进行区分。

5) Nacos集群配置(上)

第一个:和之前windows一样,在linux也需要进行Nacos持久化配置,目的是把数据由默认的derby迁移到MySQL。

  • 查看linux下的Nacos中的SQL脚本:在安装后的conf目录下

  • 把此文件的内容复制到Mysql中,执行此脚本:先创建好数据库

    我这个地方使用sqlyog远程工具连接的linux下的mysql8.0

  • 同样在conf目录下修改application.properties 配置

  • 改之前先把这个文件备份下

java 复制代码
#127.0.0.1代表的是linux系统下的本机

spring.datasource.platform=mysql

db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?&serverTimezone=UTC&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=root

第二个:Linux服务器上nacos的集群配置cluster.conf

  • 梳理出3台nacos集器的不同服务端口号

  • 复制cluster.conf.example文件为cluster.conf:
    cp cluster.conf.example cluster.conf

  • 我们修改的是这个新复制的文件cluster.conf

java 复制代码
192.168.10.140: 3333
192.168.10.140: 4444
192.168.10.140: 5555
  • 这个IP不能写127.0.0.1,必须是Linux命令hostname -i能够识别的IP

第三个:编辑Nacos的启动脚本startup.sh,使它能够接受不同的启动端口

  • /mynacos/nacos/bin 目录下有startup.sh

  • 在什么地方,修改什么,怎么修改

  • 思考

  • 修改内容

    59行:添加参数p,表示会执行p)分支

    最后:明确告诉Nacos启动的是那台节点

  • 新版:p已经被占用了,随便改一个字母为o
    PORT=$OPTARG;;

    -Dserver.port=${PORT}

  • 执行方式:bin目录下
    ./startup.sh -o 3333

6) Nacos集群配置(下)

第一个:Nginx的配置,由它作为负载均衡器

  • 修改nginx的配置文件:nginx安装路径的conf目录下的nginx.conf文件

  • nginx.conf:修改之前

  • nginx.conf:修改之后

  • Nginx服务器指定启动 配置文件命令:

7)测试1:集群是否搭建成功

截止到此处,1个Nginx+3个nacos注册中心+1个mysql

  • 启动3台Nacos:/usr/local/src/Nacos/nacos/bin/

    • ./startup.sh -o 3333
    • ./startup.sh -o 4444
    • ./startup.sh -o 5555
    • 查看进程:ps -ef|grep nacos | grep -v grep | wc -l
  • Nginx服务器指定启动配置文件命令:在/usr/local/nginx/sbin/目录下
    ./nginx -c /usr/local/nginx/conf/nginx.conf
    查看进程:ps -ef | grep nginx

    • 指向的文件
  • 启动mysql:开机自动启动

  • 测试通过nginx访问nacos:http://192.168.10.140:1111/nacos/#/login

    默认账号密码都是nacos

  • 新建一个配置测试

  • linux服务器的mysql插入一条记录

8)测试2:9002启动注册进nacos集群

微服务cloudalibaba-provider-payment9002启动注册进nacos集群

  • yml
yml 复制代码
        #server-addr: localhost:8848 #配置Nacos地址   配置在windows本机上的
        server-addr: 192.168.10.140:1111    #配置在linux上的nginx1111,由nginx在转发给3333 4444 5555Nacos
  • 启动9001
  • 结果:查看服务列表发现9002成功注册到安装在linux系统上的Nacos注册中心
9)高可用小总结

19 Sentinel实现熔断与限流

  • SpringCloud Alibaba Sentinel实现熔断与限流

19.1 Sentinel

19.1.1 官网

19.1.2 是什么

  • 一句话解释,之前我们讲解过的Hystrix
  • 和Hystrix的对比

19.1.3 去哪下

19.1.4 能干嘛

19.1.5 怎么玩

  • 文档:https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html#_spring_cloud_alibaba_sentinel

  • 服务使用中的各种问题

    • 服务雪崩
    • 服务降级
    • 服务熔断
    • 服务限流

19.2 安装Sentinel控制台

19.2.1 sentinel组件由2部分构成

Sentinel 分为两个部分:

  • 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
  • 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。

19.2.2 安装 启动-步骤

下载

  • 本次以1.8.6版本为例

运行命令

  • 前提
    • java8环境OK
    • 8080端口不能被占用(注意tomact默认端口号也是8080
    • 他是个jar包,不需要安装直接java -jar运行即可。
  • 命令:java -jar sentinel-dashboard-1.8.6.jar

访问sentinel管理界面

19.3 初始化演示工程

19.3.1 启动Nacos8848成功

19.3.2 创建:Module

1)cloudalibaba-sentinel-service8401
2)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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.angenin.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-sentinel-service8401</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
            <groupId>com.angenin.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- SpringBoot整合Web组件+actuator -->
        <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>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.6.3</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

</project>
3)YML
yml 复制代码
server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinal-service
  cloud:
    nacos:
      discovery:
        #Nacos服务注册中心地址(即:把此服务注册到注册中心8848‍)
        server-addr: 127.0.0.1:8848
    sentinel:
      transport:
        #配置Sentin dashboard地址(配置sentinel8080监控8401服务)
        dashboard: 127.0.0.1:8080
        # 默认8719端口,假如被占用了会自动从8719端口+1进行扫描,直到找到未被占用的 端口
        port: 8719   #指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer


management:
  endpoints:
    web:
      exposure:
        include: '*'
4)主启动
java 复制代码
package com.angenin.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401 {
    public static void main(String[] args) {
        SpringApplication.run(MainApp8401.class, args);
    }
}
5)业务类FlowLimitController
java 复制代码
package com.angenin.springcloud.controller;


import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FlowLimitController {

    @GetMapping("/testA")
    public String testA() {
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB() {
        return "------testB";
    }
}
6)测试
  • nacos已启动

  • sentinel控制台已启动

  • 启动8401微服务后查看sentienl控制台

  • 结论:sentinel8080正在监控微服务8401

  • 在图形化界面可以看到每一个微服务的restful风格的接口调用的访问情况。

19.4 流控规则

属于流量限制控制规则,不是流程控制。

19.4.1 基本介绍

  • 位置:

  • 解释:

19.4.2 流控模式

1)直接(默认)
  • 系统默认:直接->快速失败

  • 即:那个资源触发了阈值,我就对那个资源进行限流。

  • 配置及说明:

    表示1秒钟内查询1次就是OK,若超过次数1,就直接-快速失败,报默认错误

  • 测试1:QPS

    • 快速点击访问http://localhost:8401/testA

    • 结果:Blocked by Sentinel (flow limiting)

    • 思考???

      • 直接调用默认报错信息,技术方面OK
        but,是否应该有我们自己的后续处理?
      • 类似有个fallback的兜底方法?(即:不使用默认的报错信息,而是使用自定义的报错信息。)
  • 测试2:并发线程数

    • 多次点击发现结果不变。

    • QPS和并发线程数的区别:QPS是请求没有进来之前就被阻挡了,并发线程数是随便进来但是里面能处理的只有一个线程。

    • 在A方法中加上暂停时间:

    • 多次点击,会出现报错:1秒钟内只允许一个线程进来

2)关联
  • 是什么

    • 当关联的资源达到阈值时,就限流自己
    • 当与A关联的资源B达到阀值后,就限流A自己
    • B惹事,A挂了
  • 恢复代码:

  • 配置A

  • postman模拟并发密集访问testB

    • 访问testB成功

    • postman里新建多线程集合组

    • 将访问地址添加进新新线程组

    • Run:大批量线程高并发访问B,导致A失效了

  • 运行后发现testA挂了

  • 等这20个线程跑完,再次访问恢复正常。

3)链路
  • 多个请求调用了同一个微服务
  • eg:a、b、c三个资源,a、b都要访问c资源,但是我在统计资源c的时候我只统计从A过来的请求,b过来的不管。所以这种流控模式是对请求的来源来做判断和限流。


19.4.3 流控效果

1)直接->快速失败(默认的流控处理)
  • 直接失败,抛出异常:Blocked by Sentinel (flow limiting)
  • 源码:
    • com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController
2)预热
  • 说明

    • 公式:阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值
  • 官网:https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6

    • 默认coldFactor为3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值。
    • 限流 冷启动:https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81---%E5%86%B7%E5%90%AF%E5%8A%A8
  • 源码

    • com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController
  • WarmUp配置

  • 多次点击http://localhost:8401/testB,刚开始不行,后续慢慢OK

  • 应用场景:

    • 如:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,可慢慢的把流量放进来,慢慢的把阀值增长到设置的阀值。
3)排队等待
  • 匀速排队,阈值必须设置为QPS

  • 官网:https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6

  • 源码:com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController

  • 测试



19.5 降级规则

19.5.1 官网

  • https://github.com/alibaba/Sentinel/wiki/%E7%86%94%E6%96%AD%E9%99%8D%E7%BA%A7

19.5.2 基本介绍

1) 老版本:
  • 进一步说明
    • Sentinel 熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。
    • 当资源被降级后,在接下来的降级时间窗口之内,对该资源的调用都自动熔断(默认行为是抛出 DegradeException)。
  • Sentinel的断路器是没有半开状态的
    • 半开的状态系统自动去检测是否请求有异常,没有异常就关闭断路器恢复使用,有异常则继续打开断路器不可用。具体可以参考Hystrix
    • 新版本1.8.0开始有半开状态了。
    • 复习Hystrix:有半开状态
2) 新版本:

慢调用:

名词解释:

  • 熔断降级:熔断降级是解决雪崩问题的重要手段。其思路是由断路器统计服务调用的异常比例、慢请求比例如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求;而当服务恢复时,断路器会放行访问该服务的请求。

  • 熔断策略:断路器想要从open变为close状态,需要判断服务有没有触发熔断的条件,而熔断条件的判断就是依据熔断策略完成的。

  • 慢调用比例:看的是响应的时间,如果响应时间RT(response time)过长超过了指定时间,那么你这个调用就是慢调用,请求很慢就会调用额外的资源 会拖慢整个服务。

  • 最大RT:响应时间,表示超过500毫秒的响应都算是慢调用。

  • 比例阈值:慢调用的比超过了0.5达到一半以上就触发阈值了。

  • 熔断时长:一旦熔断,熔断时长持续5秒,5秒后进入Half-Open半熔断状态。

  • 最小请求数,统计时长:表示我会统计最近1秒内的至少10次请求,那么10次里面超过500ms的这种慢调用比例达到了一半以上,那么我就触发熔断,而熔断时间为5秒钟。

异常比例、异常数:

  • 异常比例:不是看你调用的快和慢而是看你有没有抛出异常,按照异常的比例。
  • 以上配置含义:1秒钟内统计10次请求,如果10次请求里有4次都抛了异常,那么就触发了熔断,熔断时长为5秒钟。
  • 异常数:按异常的次数
  • 以上配置含义:1秒钟内统计10次请求,如果10次请求里有2次都抛了异常,那么就触发了熔断,熔断时长为5秒钟。

19.5.3 降级策略实战

  • 这里我是用的是Sentinel1.8.6版本,而老师使用的是1.7.0版本,所以配置方式会有些不一样。
1)RT

测试

  • 代码
java 复制代码
    @GetMapping("/testD")
    public String testD() {
       //暂停几秒钟线程
        try {
            TimeUnit.MILLISECONDS.sleep(60);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("testD 测试RT");
        return "------testD";
    }
  • 配置:表示我会统计最近1秒内的至少5次请求,那么5次里面超过50ms的这种慢调用比例达到了2次以上,那么我就触发熔断,而熔断时间为5秒钟。

  • 测试:不需要使用压测工具,自己点就可以,只要1秒钟5次请求只需要有2次触发就行了。

2)异常比例

测试

  • 代码
java 复制代码
    @GetMapping("/testE")
    public String testE() {
        log.info("testD 测试RT");
        int age = 10/0;
        return "------testD";
    }
  • 配置:1秒钟内统计5次请求,如果5次请求里有2次都抛了异常,那么就触发了熔断,熔断时长为5秒钟。

  • 同样不需要jmeter,手动测试,只要1秒钟5次请求只需要有2次触发就行了。
3)异常数
  • 按异常的次数
  • 代码
java 复制代码
    @GetMapping("/testF")
    public String testF() {
        log.info("testD 测试RT");
        int age = 10/0;
        return "------testD";
    }
  • 配置:1秒钟内统计5次请求,如果5次请求里有2次都抛了异常,那么就触发了熔断,熔断时长为5秒钟。
  • 同样不需要jmeter,手动测试,只要1秒钟5次请求只需要有2次触发就行了。

19.6 热点key限流

19.6.1 基本介绍

  • 何为热点
    • 热点即经常访问的数据,很多时候我们希望统计或者限制某个热点数据中访问频次最高的TopN数据,并对其访问进行限流或者其它操作

19.6.2 官网

  • https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81

19.6.3 承上启下复习start

兜底方法:分为系统默认和客户自定义,两种

  • 之前的case,限流出问题后,都是用sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
    我们能不能自定?类似hystrix,某个方法出问题了,就找对应的兜底降级方法?
  • 结论
    • 从HystrixCommand 到@SentinelResource

19.6.4 代码

  • 源码:com.alibaba.csp.sentinel.slots.block.BlockException
  • 代码测试
java 复制代码
    @GetMapping("/testHotKey")
    //value:资源的唯一标识,名字任意一般和上面的地址值保持一致。
    @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) {
        //sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
        return "-----dealHandler_testHotKey";
    }

19.6.5 配置


19.6.6 测试

多次点击测试:方法testHotKey里面第一个参数只要QPS超过每秒1次,马上降级处理。用了我们自己定义的

如果使用默认的提示:异常打到了前台用户界面看到,不友好

19.6.7 参数例外项

  • 上述案例演示了第一个参数p1,当QPS超过1秒1次点击后马上被限流

  • 特例情况

    • 普通:超过1秒钟一个后,达到阈值1后马上被限流
    • 我们期望p1参数当它是某个特殊值时,它的限流值和平时不一样
    • 特例:假如当p1的值等于5时,它的阈值可以达到200
  • 配置:添加按钮不能忘

  • 测试:多次点击

  • 前提条件:热点参数的注意点,参数必须是基本类型或者String

19.6.8 其它

  • 手贱添加异常看看.../(ㄒoㄒ)/~~

  • 效果:发现并没有执行自定义的提示方法。

  • @SentinelResource

    处理的是Sentinel控制台配置的违规情况,有blockHandler方法配置的兜底处理;

  • RuntimeException

    int age = 10/0,这个是java运行时报出的运行时异常RunTimeException,@SentinelResource不管

  • 总结

    @SentinelResource主管配置出错,运行出错该走异常走异常

  • 后面讲:还有其它的配置来解决这个问题

19.7 系统规则

  • 是什么:之前是细粒度的从控制层的方法进行限流,现在是粗粒度的进行限流。

    • https://github.com/alibaba/Sentinel/wiki/%E7%B3%BB%E7%BB%9F%E8%87%AA%E9%80%82%E5%BA%94%E9%99%90%E6%B5%81
  • 各项配置参数说明

  • 配置全局QPS

  • 多次访问:不管是访问p1还是p2,都会报错。(之前配置的是只有p1会报错)

19.8 @SentinelResource

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

1)启动
  • 启动Nacos成功
  • 启动Nacos成功
2)修改:cloudalibaba-sentinel-service8401
  • pom:之前已引入

  • yml:没有改变

  • 业务类RateLimitController

java 复制代码
package com.angenin.springcloud.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.angenin.springcloud.entities.CommonResult;
import com.angenin.springcloud.entities.Payment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RateLimitController {
//既可以使用url地址来配置:/byResource
//也可以使用@SentinelResource注解中的value 属性来配置
    @GetMapping("/byResource")
    @SentinelResource(value = "byResource",blockHandler = "handleException")
    public CommonResult byResource() {

        return new CommonResult(200,"按资源名称限流测试OK",new Payment(2020L,"serial001"));
    }

    public CommonResult handleException(BlockException exception) {

        return new CommonResult(444,exception.getClass().getCanonicalName()+"\t 服务不可用");
    }

}
  • 主启动:没有变化
3)配置流控规则
  • 配置步骤

  • 图形配置和代码关系

  • 表示1秒钟内查询次数大于1,就跑到我们自定义的处流,限流

4)测试
  • 1秒钟点击1下,OK
  • 超过上述,疯狂点击,返回了自己定义的限流处理信息,限流发生
5)额外问题
  • 此时关闭问服务8401看看
  • Sentinel控制台,流控规则消失了?????
  • 临时/持久?:说明是临时的

19.8.2 按照Url地址限流+后续处理

  • 通过访问的URL来限流,会返回Sentinel自带默认的限流处理信息
  • 业务类RateLimitController
java 复制代码
    @GetMapping("/rateLimit/byUrl")
    @SentinelResource(value = "byUrl")
    public CommonResult byUrl() {

        return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
    }

19.8.3 上面兜底方案带来的问题

  1. 系统默认的,没有体现我们自己的业务要求。
  2. 依照现有条件,我们自定义的处理方法又和业务代码耦合在一块,不直观。
  3. 每个业务方法都添加一个兜底的,那代码膨胀加剧。
  4. 全局统一的处理方法没有体现。

19.8.4 客户自定义限流处理逻辑

  • 创建CustomerBlockHandler类用于自定义限流处理逻辑
java 复制代码
package com.angenin.springcloud.myhandler;

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.angenin.springcloud.entities.CommonResult;


public class CustomerBlockHandler {

    public static CommonResult handleException1(BlockException exception){

        return new CommonResult(2020,"自定义的限流处理信息......CustomerBlockHandler1");
    }
    public static CommonResult handleExceptio2(BlockException exception){

        return new CommonResult(2020,"自定义的限流处理信息......CustomerBlockHandler2");
    }
}
  • RateLimitController
java 复制代码
    /**
     * 自定义通用的限流处理逻辑,
     * blockHandlerClass = CustomerBlockHandler.class
     * blockHandler = handleException2
     * 上述配置:找CustomerBlockHandler类里的handleException2方法进行兜底处理
     */
    @GetMapping("/rateLimit/customerBlockHandler")
    //指定哪一个全局类中的的哪一个方法
    @SentinelResource(value = "customerBlockHandler",
            blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handleExceptio2")
    public CommonResult customerBlockHandler() {

        return new CommonResult(200,"按客户自定义限流处理逻辑");
    }

19.8.5 更多注解属性说明

  • 多说一句:除了默认的系统提示,和使用注解编写自定义提示外,他还支持使用代码的方式编写自定义提示规则。

  • Sentinel主要有三个核心Api

    • SphU定义资源
    • Tracer定义统计
    • ContextUtil定义了上下文

19.9 服务熔断功能

  • sentinel整合ribbon+openFeign+fallback

19.9.1 Ribbon系列

  • 启动nacos和sentinel
  • 结构
1)提供者9003/9004
  • 新建cloudalibaba-provider-payment9003/9004两个一样的做法

  • 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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.angenin.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-provider-payment9003</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
            <groupId>com.angenin.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- SpringBoot整合Web组件 -->
        <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>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>
  • YML:记得修改不同的端口号
yml 复制代码
server:
  port: 9003

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #配置Nacos地址

management:
  endpoints:
    web:
      exposure:
        include: '*'
  • 主启动
java 复制代码
package com.angenin.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain9003
{
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain9003.class, args);
    }
}
  • 业务类
java 复制代码
package com.angenin.springcloud.controller;

import com.angenin.springcloud.entities.CommonResult;
import com.angenin.springcloud.entities.Payment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;

@RestController
public class PaymentController {
    @Value("${server.port}")
    private String serverPort;

    public static HashMap hashMap = new HashMap();

    //模拟连接一个数据库
    static {
        hashMap.put(1L,new Payment(1L,"28a8c1e3bc2742d8848569891fb42181"));
        hashMap.put(2L,new Payment(2L,"bba8c1e3bc2742d8848569891ac32182"));
        hashMap.put(3L,new Payment(3L,"6ua8c1e3bc2742d8848569891xt92183"));
    }

    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult paymentSQL(@PathVariable("id") Long id) {
        Payment payment = (Payment)hashMap.get(id);
        CommonResult result = new CommonResult(200,"from mysql,serverPort:  "+serverPort,payment);
        return result;
    }



}
2)消费者84
  • 新建cloudalibaba-consumer-nacos-order84

  • 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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.angenin.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-consumer-nacos-order84</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.angenin.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- SpringBoot整合Web组件 -->
        <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>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>
  • yml
yml 复制代码
server:
  port: 84

spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: localhost:8080
        #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
        port: 8719

#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)
service-url:
  nacos-user-service: http://nacos-payment-provider
  • 主启动
java 复制代码
package com.angenin.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
public class OrderNacosMain84 {
    public static void main(String[] args) {
        SpringApplication.run(OrderNacosMain84.class, args);
    }
}
  • 结构
  • 业务类详情查看下面
  • 修改后请重启微服务
    • 热部署对java代码级生效及时
    • 对@SentinelResource注解内属性,有时效果不好
  • 目的
    • fallback管运行异常
    • blockHandler管配置违规
3)配置类:ApplicationContextConfig
  • ApplicationContextConfig
java 复制代码
package com.angenin.springcloud.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApplicationContextConfig {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}
4)业务类 CircleBreakerController :没有任何配置
java 复制代码
package com.angenin.springcloud.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.angenin.springcloud.entities.CommonResult;
import com.angenin.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
@Slf4j
public class CircleBreakerController {
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
    @SentinelResource(value = "fallback")//没有配置
    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;
    }

}
  • 测试
    • 测试地址:http://localhost:84/consumer/fallback/1

      通过84消费者可以以负载均衡轮训的方式,访问9003/9004

    • 没有任何配置:给客户error页面,不友好(在控制层方法中设置的访问1、2、3正常,4、5异常)

5)业务类 CircleBreakerController :只配置fallback
  • 代码
java 复制代码
package com.angenin.springcloud.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.angenin.springcloud.entities.CommonResult;
import com.angenin.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
@Slf4j
public class CircleBreakerController {
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
    //@SentinelResource(value = "fallback")//没有配置
    @SentinelResource(value = "fallback", fallback = "handlerFallback") //fallback只负责业务异常
    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;
    }

    //本例是fallback
    public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(444,"兜底异常handlerFallback,exception内容  "+e.getMessage(),payment);
    }


}
6)业务类 CircleBreakerController :只配置blockHandler
  • 代码
java 复制代码
package com.angenin.springcloud.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.angenin.springcloud.entities.CommonResult;
import com.angenin.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
@Slf4j
public class CircleBreakerController {
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
    //@SentinelResource(value = "fallback")//没有配置
    //@SentinelResource(value = "fallback", fallback = "handlerFallback") //fallback只负责业务异常
    @SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
    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;
    }

    //本例是fallback
/*    public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(444,"兜底异常handlerFallback,exception内容  "+e.getMessage(),payment);
    }*/

    //本例是blockHandler
    public CommonResult blockHandler(@PathVariable  Long id, BlockException blockException) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException  "+blockException.getMessage(),payment);
    }



}
7)业务类 CircleBreakerController :fallback和blockHandler都配置
  • 代码
java 复制代码
package com.angenin.springcloud.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.angenin.springcloud.entities.CommonResult;
import com.angenin.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@RestController
@Slf4j
public class CircleBreakerController {
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
    //@SentinelResource(value = "fallback")//没有配置
    //@SentinelResource(value = "fallback", fallback = "handlerFallback") //fallback只负责业务异常
    //@SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
    @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler") //都配置
    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;
    }

    //本例是fallback
    public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(444,"兜底异常handlerFallback,exception内容  "+e.getMessage(),payment);
    }

    //本例是blockHandler
    public CommonResult blockHandler(@PathVariable  Long id, BlockException blockException) {
        Payment payment = new Payment(id,"null");
        return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException  "+blockException.getMessage(),payment);
    }



}
  • 配置

  • 测试1:http://localhost:84/consumer/fallback/1(访问正常)

    • 第一次点击:正常访问

    • 快速点击:超过阈值,会访问自定义的blockHandler方法

  • 测试2:http://localhost:84/consumer/fallback/4(访问异常)

    • 第一次点击:返回fallback属性标注的自定义方法

    • 快速点击:超过阈值,此时既满足fallback业务异常又满足blockHandler控制台配置违规,那么此时返回的结果是blockHandler属性指定的方法。

  • 结论:若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。

8)业务类 CircleBreakerController :忽略属性...
  • 即:排除指定的异常,即便配置了出现异常后执行自定义的方法提示,但是加上此属性后出现此异常执行的仍然是系统自带的提示信息。

    exceptionsToIgnore = {IllegalArgumentException.class}

    http://localhost:84/consumer/fallback/4

19.9.2 Feign系列

1)修改84模块
  • 84消费者调用提供者9003

  • Feign组件一般是消费侧

2)POM
xml 复制代码
        <!--SpringCloud openfeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
3)YML
yml 复制代码
server:
  port: 84

spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: localhost:8080
        #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
        port: 8719

#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)
service-url:
  nacos-user-service: http://nacos-payment-provider

# 激活Sentinel对Feign的支持
feign:
  sentinel:
    enabled: true
4)业务类
  • 接口
java 复制代码
package com.angenin.springcloud.service;

import com.angenin.springcloud.entities.CommonResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * value:找到注册中心上的微服务接口名
 * 过程:fallback:相当于去找nacos-payment-provider这个微服务的名字,去调用下面已有的方法,
 *       假如出事了去调用PaymentFallbackService里面的方法
 */
@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)//调用中关闭9003服务提供者
public interface PaymentService {
    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult paymentSQL(@PathVariable("id") Long id);
}
  • 接口实现类:解决和业务逻辑混一起???混乱
java 复制代码
package com.angenin.springcloud.service;

import com.angenin.springcloud.entities.CommonResult;
import com.angenin.springcloud.entities.Payment;
import org.springframework.stereotype.Component;

@Component
public class PaymentFallbackService implements PaymentService {
    @Override
    public CommonResult paymentSQL(Long id) {
        return new CommonResult(444,"服务降级返回,没有该流水信息",new Payment(id, "errorSerial......"));
    }
}
  • Controller
java 复制代码
    //==================OpenFeign
    @Resource
    private PaymentService paymentService;

    @GetMapping(value = "/consumer/openfeign/{id}")
    public CommonResult paymentSQL(@PathVariable("id") Long id) {
        if(id == 4) {
            throw new RuntimeException("没有该id");
        }
        return paymentService.paymentSQL(id);
    }
5)主启动
java 复制代码
package com.angenin.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients //启用 激活
public class OrderNacosMain84 {
    public static void main(String[] args) {
        SpringApplication.run(OrderNacosMain84.class, args);
    }
}
6)测试

19.9.3 熔断框架比较

Sentinel Hystrix resilience4j
隔离策略 信号量隔离(并发线程数限流) 线程池隔商/信号量隔离 信号量隔离
熔断降级策略 基于响应时间、异常比率、异常数 基于异常比率 基于异常比率、响应时间
实时统计实现 滑动窗口(LeapArray) 滑动窗口(基于RxJava) Ring Bit Buffer
动态规则配置 支持多种数据源 支持多种数据源 有限支持
扩展性 多个扩展点 插件的形式 接口的形式
基于注解的支持 支持 支持 支持
限流 基于QPS,支持基于调用关系的限流 有限的支持 Rate Limiter
流量整形 支持预热模式匀速器模式、预热排队模式 不支持 简单的Rate Limiter模式
系统自适应保护 支持 不支持 不支持
控制台 提供开箱即用的控制台,可配置规则、查看秒级监控,机器发观等 简单的监控查看 不提供控制台,可对接其它监控系统

19.10 规则持久化

19.10.1 是什么

一旦我们重启应用,sentinel规则将消失,生产环境需要将配置规则进行持久化

19.10.2 怎么玩

将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到,只要Nacos里面的配置不删除,针对8401上sentinel上的流控规则持续有效

19.10.3 步骤:修改cloudalibaba-sentinel-service8401

1)POM
xml 复制代码
<!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
2)YML
yml 复制代码
server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinal-service
  cloud:
    nacos:
      discovery:
        #Nacos服务注册中心地址(即:把此服务注册到注册中心8848‍)
        server-addr: 127.0.0.1:8848
    sentinel:
      transport:
        #配置Sentin dashboard地址(配置sentinel8080监控8401服务)
        dashboard: 127.0.0.1:8080
        # 默认8719端口,假如被占用了会自动从8719端口+1进行扫描,直到找到未被占用的 端口
        port: 8719   #指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer
      datasource: #<---------------------------关注点,添加Nacos数据源配置
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: cloudalibaba-sentinel-service
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow


management:
  endpoints:
    web:
      exposure:
        include: '*'
3)添加Nacos业务规则配置


  • 内容解析
    • resource:资源名称;
    • limitApp:来源应用;
    • grade:阈值类型,0表示线程数,1表示QPS;
    • count:单机阈值;
    • strategy:流控模式,0表示直接,1表示关联,2表示链路;
    • controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;
    • clusterMode:是否集群。
yml 复制代码
[
    {
        "resource": "/rateLimit/byUrl",
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]
4)添加配置,启动8401
  • 控制层方法:之前的方法

  • 配置流控规则

  • 启动8401

5)快速访问测试接口
6)停止8401再看sentinel
  • 停机后发现流控规则没有了
7)重新启动8401再看sentinel

20 Seata处理分布式事务

  • SpringCloud Alibaba Seata处理分布式事务
  • 阳哥讲的版本太老了,这里我已黑马的版本为例进行学习。
    • 博客查看:待发布

20.1 Seata-Server安装(1.7.0)

20.3.1 版本说明

  • 说明:Seata不同版本的配置有很大的不同,1.4.2之前conf下需要修改2个配置文件,到现在都整合为了一个application.yml文件,下面讲解使用1.7.0版本如何进行安装配置(2023-9-5)

20.1.2 Seata Server存储模式(3种)

  • seata-server-1.7.0.zip解压到指定目录并修改conf目录下的application.yml配置文件,先备份原始application.yml文件
  • 查看application.yml文件
yml 复制代码
#  Copyright 1999-2019 Seata.io Group.
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#  http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

server:
  port: 7091   #它是UI界面的端口号,不是对外提供服务的端口号

spring:     #服务名
  application:
    name: seata-server

logging:     #日志
  config: classpath:logback-spring.xml
  file:
    path: ${user.home}/logs/seata
  extend:
    logstash-appender:
      destination: 127.0.0.1:4560
    kafka-appender:
      bootstrap-servers: 127.0.0.1:9092
      topic: logback_to_logstash

console:    #平台界面的用户名密码
  user:
    username: seata
    password: seata
seata:
  config:        #配置中心
    # support: nacos, consul, apollo, zk, etcd3
    type: file
  registry:      #注册中心
    # support: nacos, eureka, redis, zk, consul, etcd3, sofa
    type: file
  store:         #存储中心
    # support: file 、 db 、 redis
    mode: file
#  server:   #这才是对外提供的端口号,默认是7091+1000=8091.所以不用配置
#    service-port: 8091 #If not configured, the default is '${server.port} + 1000'
  security:  #安全
    secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
    tokenValidityInMilliseconds: 1800000
    ignore:
      urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.jpeg,/**/*.ico,/api/v1/auth/login
  • 3种存储模式 :Seata Server需要对全局事务与分支事务进行存储,以便对它们进行管理。共存储模式目前支持三种:file、 db 与redis(后续将引入raft,mongodb)。
    • file模式:会将相关数据存储在本地文件中,一般用于Seata Server的中机测试。
    • db模式:会将相关数据存储在数据库中,一般用于生产环境下的Seata Server集群部著。生产环境下使用最多的模式。
    • redis模式:会将相关数据存储在redis 中,一般用于生产环境下的Seata Server集群部署。性能略高于db模式,如果对性能要求较高,可选择redis模式。

20.1.3 配置步骤:以db模式为例

1)修改application.yml配置文件

说明:此文件的修改都可以参考示例文件的内容。

修改之前先复制一份原始文件

修改存储中心

  • 拷贝示例文件内容
  • 修改application.yml
yml 复制代码
  store:
    # support: file 、 db 、 redis
    mode: db
    session:
      mode: db
    lock:
      mode: db
    db:
      datasource: druid
      db-type: mysql
      driver-class-name: com.mysql.jdbc.Driver     #如果是mysql8.0驱动为:com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true
      user: root
      password: root
      min-conn: 10
      max-conn: 100
      global-table: global_table
      branch-table: branch_table
      lock-table: lock_table
      distributed-lock-table: distributed_lock
      query-limit: 1000
      max-wait: 5000

修改配置中心

  • 拷贝示例文件内容

  • 修改application.yml

yml 复制代码
seata:
  config:
    # support: nacos, consul, apollo, zk, etcd3
    type: nacos
    nacos:
      server-addr: 127.0.0.1:8848
      namespace:
      group: fsp_tx_group       #分组名称
      username: nacos           #连接Nacos平台的用户名密码默认都是nacos
      password: nacos
      context-path:
      ##if use MSE Nacos with auth, mutex with username/password attribute
      #access-key:
      #secret-key:
      data-id: seataServer.properties    #之后需要再nacos配置中心创建此文件。

修改注册中心

  • 拷贝示例文件内容

  • 修改application.yml

yml 复制代码
  registry:
    # support: nacos, eureka, redis, zk, consul, etcd3, sofa
    type: nacos
    nacos:
      application: seata-server      #启动后注册到注册中心的服务名
      server-addr: 127.0.0.1:8848
      group: fsp_tx_group   #组名保持一致
      namespace:
      cluster: default
      username: nacos
      password: nacos
      context-path:
      ##if use MSE Nacos with auth, mutex with username/password attribute
      #access-key:
      #secret-key:
2)新建库seata,并执行脚本
  • 之前在application.yml文件中配置的是使用数据库来管理全局事务与分支事务,所以要创建库,在库中新建表。

  • 脚本位置:注意不推荐从官网上找脚本,因为官网上更新的速度比较慢可能会导致版本不一致。推荐从下载的安装包查找。

  • 创建seata数据库,并执行脚本

3)seataServer.properties
  • 需要在nacos平台,配置此文件

  • 配置内容来源:

  • 复制一份原始文件,修改config.txt文件内容。


java 复制代码
#For details about configuration items, see https://seata.io/zh-cn/docs/user/configurations.html
#Transport configuration, for client and server
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableTmClientBatchSendRequest=false
transport.enableRmClientBatchSendRequest=true
transport.enableTcServerBatchSendResponse=false
transport.rpcRmRequestTimeout=30000
transport.rpcTmRequestTimeout=30000
transport.rpcTcRequestTimeout=30000
transport.threadFactory.bossThreadPrefix=NettyBoss
transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
transport.threadFactory.shareBossWorker=false
transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
transport.threadFactory.clientSelectorThreadSize=1
transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
transport.threadFactory.bossThreadSize=1
transport.threadFactory.workerThreadSize=default
transport.shutdown.wait=3
transport.serialization=seata
transport.compressor=none

#Transaction routing rules configuration, only for the client
service.vgroupMapping.default_tx_group=default
#If you use a registry, you can ignore it
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false

#Transaction rule configuration, only for the client
client.rm.asyncCommitBufferLimit=10000
client.rm.lock.retryInterval=10
client.rm.lock.retryTimes=30
client.rm.lock.retryPolicyBranchRollbackOnConflict=true
client.rm.reportRetryCount=5
client.rm.tableMetaCheckEnable=true
client.rm.tableMetaCheckerInterval=60000
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.rm.sagaJsonParser=fastjson
client.rm.tccActionInterceptorOrder=-2147482648
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
client.tm.interceptorOrder=-2147482648
client.undo.dataValidation=true
client.undo.logSerialization=jackson
client.undo.onlyCareUpdateColumns=true
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
client.undo.logTable=undo_log
client.undo.compress.enable=true
client.undo.compress.type=zip
client.undo.compress.threshold=64k
#For TCC transaction mode
tcc.fence.logTableName=tcc_fence_log
tcc.fence.cleanPeriod=1h

#Log rule configuration, for client and server
log.exceptionRate=100

#Transaction storage configuration, only for the server. The file, db, and redis configuration values are optional.
store.mode=db
store.lock.mode=db
store.session.mode=db
#Used for password encryption
#store.publicKey=      

#If `store.mode,store.lock.mode,store.session.mode` are not equal to `file`, you can remove the configuration block.
#store.file.dir=file_store/data
#store.file.maxBranchSessionSize=16384
#store.file.maxGlobalSessionSize=512
#store.file.fileWriteBufferCacheSize=16384
#store.file.flushDiskMode=async
#store.file.sessionReloadReadSize=100

#These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block.
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=root
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000

#These configurations are required if the `store mode` is `redis`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `redis`, you can remove the configuration block.
#store.redis.mode=single
#store.redis.single.host=127.0.0.1
#store.redis.single.port=6379
#store.redis.sentinel.masterName=
#store.redis.sentinel.sentinelHosts=
#store.redis.maxConn=10
#store.redis.minConn=1
#store.redis.maxTotal=100
#store.redis.database=0
#store.redis.password=
#store.redis.queryLimit=100

#Transaction rule configuration, only for the server
server.recovery.committingRetryPeriod=1000
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=1000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
server.distributedLockExpireTime=10000
server.xaerNotaRetryTimeout=60000
server.session.branchAsyncQueueSize=5000
server.session.enableBranchAsyncRemove=false
server.enableParallelRequestHandle=false

#Metrics configuration, only for the server
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898
  • 以上这些配置参数信息所代表的含义,可以查看官网:
  • 启动Nacos,并登录管理页面
  • 在配置列表新建:seataServer.properties,配置内容为刚刚修改的config.txt文件,注意类型为properties。

4)启动

先启动Nacos端口号8848,再启动seata-server

  • 位置
  • cmd,输入命令:seata-server.bat -m db,默认是file所以要指定db。如果不是本机还要指定ip和端口号。
  • 查看服务列表:

20.2 domain实体类

  • 不同的公司,实体类的叫法可能不同。
  • 封装数据库的实体类。与前端页面交互的实体类。
相关推荐
七夜zippoe44 分钟前
分布式系统实战经验
java·分布式
nomi-糯米1 小时前
Fisco Bcos 2.11.0配置console控制台2.10.0及部署调用智能合约
分布式·网络安全·区块链·智能合约·分布式账本
喜欢猪猪2 小时前
Kafka是如何保证数据的安全性、可靠性和分区的
分布式·kafka
芊言芊语2 小时前
分布式消息服务Kafka版的详细解析和配置方式
分布式·kafka
Alluxio2 小时前
选择Alluxio来解决AI模型训练场景数据访问的五大理由
大数据·人工智能·分布式·ai·语言模型
武子康3 小时前
大数据-133 - ClickHouse 基础概述 全面了解
java·大数据·分布式·clickhouse·flink·spark
.生产的驴3 小时前
SpringBoot 消息队列RabbitMQ 消费者确认机制 失败重试机制
java·spring boot·分布式·后端·rabbitmq·java-rabbitmq
人生百态,人生如梦4 小时前
大数据处理从零开始————3.Hadoop伪分布式和分布式搭建
hadoop·分布式
一叶飘零_sweeeet5 小时前
为什么 Feign 要用 HTTP 而不是 RPC?
java·网络协议·http·spring cloud·rpc·feign
芊言芊语5 小时前
分布式缓存服务Redis版解析与配置方式
redis·分布式·缓存