Spring Cloud Alibaba笔记

😀😀😀创作不易,各位看官点赞收藏.

文章目录

  • Spring Cloud Alibaba 笔记
    • 1、Nacos 服务注册和配置中心
      • 1.1、Nacos 之下载启动
      • 1.2、Nacos 之注册中心
      • 1.3、Nacos 之服务发现
      • 1.4、Nacos 之配置中心
      • 1.5、Nacos 之分类配置
      • 1.6、Nacos 之集群配置
        • 1.6.1、Nacos 之持久化配置
        • 1.6.2、Nacos 之集群配置
    • 2、Sentinel 熔断与限流
      • 2.1、Sentinel 之基本使用
      • 2.2、Sentinel 之流量监控
      • 2.3、Sentinel 之服务降级
      • 2.4、Sentinel 之热点限流
      • 2.5、Sentinel 之系统规则
      • 2.6、Sentinel 之`@SentinelResource`注解
    • 3、 OpenFeign 远程服务调用
      • 3.1、Openfeign 之基本使用
      • 3.2、Openfeign 之超时控制
      • 3.3、Openfeign 之异常处理
    • 4、Gateway 服务网关
      • 4.1、Gateway 之网关简介
      • 4.2、Gateway 之配置路由
      • 4.3、Gateway 之配置断言
      • 4.4、Gateway 之配置过滤器

Spring Cloud Alibaba 笔记

Spring Cloud Alibaba 旨在为微服务开发提供一站式解决方案。该项目包括开发分布式应用程序和服务所需的组件,以便开发人员可以使用 Spring Cloud 编程模型轻松开发分布式应用程序。

使用Spring Cloud Alibaba,您只需添加一些注解和配置,您的应用程序就可以使用阿里巴巴的分布式解决方案,并通过阿里巴巴中间件构建您自己的分布式系统。

Spring Cloud 阿里巴巴的特点:

  1. 流量控制和服务降级:支持WebServlet、WebFlux、OpenFeign、RestTemplate、Dubbo接入限流降级功能。可以在运行时通过控制台实时修改限流和降流规则,还支持对限流和降流Metrics的监控。
  2. 服务注册和发现:可以注册服务,客户端可以使用 Spring 管理的 bean,自动集成 Ribbon 发现实例。
  3. 分布式配置:支持分布式系统的外部化配置,配置变化时自动刷新。
  4. Rpc Service:扩展 Spring Cloud 客户端 RestTemplate 和 OpenFeign 以支持调用 Dubbo RPC 服务。
  5. 事件驱动:支持构建与共享消息系统连接的高度可扩展的事件驱动微服务。
  6. 分布式事务:支持高性能、易用的分布式事务解决方案。
  7. 阿里云对象存储:海量、安全、低成本、高可靠的云存储服务。支持随时随地在任何应用程序中存储和访问任何类型的数据。
  8. 阿里云SchedulerX:精准、高可靠、高可用的定时作业调度服务,响应时间秒级。
  9. 阿里云短信:覆盖全球的短信服务,阿里短信提供便捷、高效、智能的通信能力,帮助企业快速联系客户。

1、Nacos 服务注册和配置中心

Nacos: 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。

Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。

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

1.1、Nacos 之下载启动

​ 安装方式有很多,可以去github上去下载对应的压缩包,但是下载慢。也可以去gitee上去找一个别人fork下源码,然后通过maven自己打包(要确定自己电脑上有Java环境和Maven环境)。

git clone https://github.com/alibaba/nacos.git
cd nacos/
# 打包命令
mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U  

# 进入到这个文件下,会发现打包好的文件
cd distribution/target/nacos-server-$version/nacos/bin

image-20221012215510643

Windows启动方式:

# 启动命令(standalone代表着单机模式运行,非集群模式):
startup.cmd -m standalone

image-20221012215845577

image-20221012220037926

注意:启动目录路劲不能包含中文,启动后就可以访问:127.0.0.1:8848/nacos/index.html,出现下面的页面就是启动成功了。

image-20221012220231874

Linux启动:

# Linux/Unix/Mac
sh startup.sh -m standalone 
# ubuntu系统
bash startup.sh -m standalone

1.2、Nacos 之注册中心

父spring-cloudalibaba的pom引入依赖:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2021.0.4.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

本地引入nacos的pom依赖:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

编写yaml文件:

server:
  port: 8081

spring:
  application:
    name:  pay-application-01 # 注册名称
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848 # 注册地址

management:
  endpoints:
    web:
      exposure:
        include: '*'

主启动类:

@SpringBootApplication
@EnableDiscoveryClient // 开启服务发现
public class PayApplication01 {
    public static void main(String[] args) {
        SpringApplication.run(PayApplication01.class,args);
    }
}

启动服务并注册到Nacos中:

image-20221101145044875

1.3、Nacos 之服务发现

​ nacos可以进行服务的调用,也可以自己进行负载均衡。将服务消费者注册到nacos中,并使用RestTemplate进行服务调用。

yaml文件编写:

server:
  port: 80

# 服务消费者
spring:
  application:
    name:  consumer-application # 注册名称
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848 # 注册地址

# 消费者将要访问的微服务名称
service-url:
  nacos-pay-service-name: pay-application-01

由于Spring Cloud2020.0.1.0之后不再使用netflix,所以不使用Ribbon做负载均衡,采用下面方式进行服务调用。

我们使用LoadBalancerClient作为负载均衡,首先引入依赖。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
@RestController
public class TestController {

    @Resource
    private RestTemplate restTemplate;
    @Resource
    private LoadBalancerClient loadBalancerClient;

    @Value("${service-url.nacos-pay-service-name}")
    private String SERVICE_NAME;

    @GetMapping("/test")
    public String test(){
        ServiceInstance serviceInstance = loadBalancerClient.choose(SERVICE_NAME);
        // 服务调用地址
        String path = String.format("http://%s:%s/%s",serviceInstance.getHost(),serviceInstance.getPort(),"test");
        System.out.println("request path:" +path);
        // 通过RestTemplate调用服务
        return restTemplate.getForObject(path,String.class);
    }
}

image-20221101162929657

每刷新一次,就会由不同服务提供者进行提供,这就实现了轮询的负载均衡。

1.4、Nacos 之配置中心

​ Nacos可以作为一个配置中心实时更新项目中的配置文件,这样就可以只需修改一处配置文件使所有服务的配置文件都修改。Nacos在项目初始化时要先从配置中心拉取配置之后,才能保证项目的正常启动。

引入依赖:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 配置中心依赖-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

编写配置文件:

一般有两种配置文件bootstrap.yamlapplication.yaml,但是前者优先级高于后者,所以将全局的配置放在bootstrap中,自己配置文件放在application中。(写一个就可以了)

server:
  port: 7001

spring:
  profiles:
    active: dev # 设置成开发环境
  application:
    name: config-application
  cloud:
    nacos:
        discovery:
          server-addr: 127.0.0.1:8848  # 服务注册地址
        config:
          server-addr: 127.0.0.1:8848 # 配置中心地址
          file-extension: yml # 配置文件后缀名

编写好配置模块后,在Nacos中创建配置文件:

image-20221101172744991

image-20221101172831527

Data ID命名规则:
命名公式 ${spring.cloud.nacos.config.prefix}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension},注意每一个不能省略,中间使用 - 隔开。

  • spring.cloud.nacos.config.prefix: 前缀,默认是项目名称,可以通过spring.cloud.nacos.config.prefix修改。
  • spring.profiles.active:在bootstrap中配置的环境类型。
  • spring.cloud.nacos.config.file-extension:在bootstrap中配置文件扩展名。

可能新版的nacos不支持bootstrap文件,需要导入依赖。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

以上的Data ID就该命名为:config-application-dev.yml

image-20221101175131444

配置文件动态刷新:

@RestController
@RefreshScope // 配置文件动态刷新,当修改nacos中心的配置文件发布后,不用重启项目就会发现配置发生变化了
public class TestController {

    @Value("${test.value}")
    private String values;

    @GetMapping("/test")
    public String test(){
        return values;
    }
}

1.5、Nacos 之分类配置

​ 在分布式开发中存在多环境,通常在实际开发中都会准备不同的开发环境,例如dev开发环境、test测试环境、prod生产环境,如何进行管理这些环境配置保证每个服务读取到正确的配置文件,这就需要Nacos的分类配置。

Namespace、group、Data ID三者之间的关系:

image-20221101202047935

Namespace区分部署环境,Group和Data ID逻辑上区分两个目标对象。相当于Java中的包名、类名。默认的Namespace是public,Group是DEFAULT_GROUP。

Nacos三种分配配置方式:(开发环境、测试环境、生产环境)

  1. 基于Data ID配置:通过切换项目的开发环境去配置中心拉取不同Data ID的配置文件。(常用)
# 项目切换不同环境
spring:
  profiles:
    active: dev # 设置成开发环境,对应配置中心Data ID为config-application-dev.yml
    # active: test # 设置成测试环境,对应配置中心Data ID为config-application-test.yml
    # active: prod # 设置成生产环境,对应配置中心Data ID为config-application-prod.yml

配置中心创建对应的配置文件,是在默认的public的Namespace下,默认的DEFAULT_GROUP分组下,分别切换对应环境就可以实现不能拉取不同环境的配置文件。

image-20221101225318164

  1. 基于GROUP分组配置:去拉取不同分组下同一个Data ID配置文件。

创建两个相同Data ID的配置文件,但是在不同的分组下。

image-20221101230225223

spring:
  profiles:
    active: dev # 设置成开发环境,对应配置中心Data ID为config-application-dev.yml
    # active: test # 设置成测试环境,对应配置中心Data ID为config-application-test.yml
    # active: prod # 设置成生产环境,对应配置中心Data ID为config-application-prod.yml
  application:
    name: config-application
  cloud:
    refresh:
      enabled: true
    nacos:
        discovery:
          server-addr: 127.0.0.1:8848  # 服务注册地址
        config:
          server-addr: 127.0.0.1:8848 # 配置中心地址
          file-extension: yml # 配置文件后缀名
          group: DEV_GROUP # 切换对应分组
  1. 基于Namespace命名空间:创建不同的命名空间,然后在不同的命名空间去查找对应的配置文件。

创建两个不同的命名空间,并创建两个GROUP和Data ID相同的配置文件,默认有一个public命名空间不能够删除。

image-20221101230945978

image-20221101231859038

image-20221101231303729

在不同分组中创建了两个相同GROPU和Data ID的配置文件,并修改配置文件来切换不同的命名空间。

spring:
  profiles:
    active: dev # 设置成开发环境,对应配置中心Data ID为config-application-dev.yml
    # active: test # 设置成测试环境,对应配置中心Data ID为config-application-test.yml
    # active: prod # 设置成生产环境,对应配置中心Data ID为config-application-prod.yml
  application:
    name: config-application
  cloud:
    refresh:
      enabled: true
    nacos:
        discovery:
          server-addr: 127.0.0.1:8848  # 服务注册地址
        config:
          server-addr: 127.0.0.1:8848 # 配置中心地址
          file-extension: yml # 配置文件后缀名
          group: TEST_GROUP # 切换对应分组
          namespace: module-dev # 切换不同的Namespace,填创建时的命名空间ID

1.6、Nacos 之集群配置

1.6.1、Nacos 之持久化配置

​ 在0.7版本之前,在单机模式时nacos使用嵌入式数据库(derby)实现数据的存储,不方便观察数据存储的基本情况。0.7版本增加了支持mysql数据源能力。对于搭建Nacos集群数据库为了保证数据的一致性,也是使用MySQL数据库来存放数据保证数据高可用。

初始化Nacos数据库脚本:在Nacos的conf目录下有一个nacos-mysql.sql脚本,复制后在MySQL来执行。

image-20221102110331668

image-20221102111215304

修改Nacos的数据源:修改conf目录下的application.properties文件,在文件最下面添加下面一句话。

# 一定要是mysql
spring.datasource.platform=mysql

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

重启Nacos并插入数据观察数据库是否增加数据记录,如果增加数据库就切换成功,这样新增的数据存放在数据库中,重启Nacos数据就不会丢失。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4tvtSrau-1692611041818)(https://jx-image-storage.oss-cn-hangzhou.aliyuncs.com/image/image-20221102112013186.png)]

1.6.2、Nacos 之集群配置

​ 在生产环境中Nacos都已集群的形式存在,这样保证了服务高可用。一般集群模式是客户端请求到代理服务器,然后代理服务器转发到每一台Nacos上。下面介绍使用1台Nginx+3台Nacos+1台MySQL做Nacos集群。

  1. 在Linux下安装Nacos压缩包并解压,并初始化持久化Sql脚本修改对应数据源,修改每一台Nacos启动端口和开启连接密码(都在application.properties)。

image-20221102130059493

image-20221102132906176

  1. 修改cluster.conf文件,配置集群组。

image-20221102130730338

  1. 安装Nginx代理服务器:https://blog.redis.com.cn/install

安装编译环境:

# g++环境
yum -y install gcc automake autoconf libtool make
yum install gcc gcc-c++
# 安装pcre、zlib、openssl
yum install pcre -y
yum install pcre-devel -y
yum install zlib -y
yum install zlib-devel -y
yum install openssl -y
yum install openssl-devel -y

下载tar包,并解压,默认解压后的路径是 /usr/local/nginx

#解压
cd /usr/local
tar -zxvf nginx-1.16.0.tar.gz
#进行configure配置,查看是否报错
cd nginx-1.16.0/
./configure
#编译
make
#安装
make install
#在 /usr/local/nginx目录下,可以看到如下4个目录:
#conf配置文件,html网页文件,logs日志文件,sbin主要二进制程序

修改Nginx配置文件并启动:

image-20221102142143199

#指定配置文件启动
/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
  1. 启动每一台Nacos服务
# 使用内置数据源
sh startup.sh -p embedded
# 使用外置数据源,我们使用这个
sh startup.sh 

image-20221102143959250

由于Nacos集群服务器启动需要很大内存,一般普通的云服务跑不起来,可以修改启动命令,将初始化的内存值改小。

image-20221102150504494

避坑端口偏移:Nacos 2.x 新增了 gRPC 协议的通讯端口,在启动时会自动在原有端口 port 的基础上根据偏移量 10001001 再打开另外两个端口。所以在一台服务器上去跑两个nacos不要使用相邻的端口号和不要使用偏移端口号,同时打开这两个端口。

2、Sentinel 熔断与限流

​ 随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。

下载地址:https://github.com/alibaba/Sentinel/releases/tag/v1.8.0

java -Dsentinel.dashboard.auth.username=admin -Dsentinel.dashboard.auth.password=admin123 -jar sentinel-dashboard-1.8.1.jar &

启动:下载完成后是一个Jar包,直接通过 java -Dserver.port=7777 -jar sentinel-dashboard-1.8.0.jar 命令启动后就可以直接访问sentinel的控制面板,账号和密码都是sentinel,不指定端口就是默认8080端口。

在Centos中运行jar包:nohup java -Dserver.port=7777 -jar sentinel-dashboard-1.8.0.jar >sentinel.log 2>&1 &

  • nohup意思是不挂断运行命令,当账户退出或终端关闭时,程序仍然运行

  • >spring.log代表将命令的输出定向存储到spring.log这个文件中,文件名可以自己定义。

  • &代表在后台运行

image-20221103132229284

2.1、Sentinel 之基本使用

导入依赖:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

修改yaml,使用sentinel监控服务:

server:
  port: 8081

spring:
  profiles:
    active: dev
  application:
    name: sentinel-application-01
  cloud:
      nacos:
        discovery:
          server-addr: xxxxxxx:8001
        config:
          server-addr: xxxxxxxx:8001 # 配置中心地址
          file-extension: yml # 配置文件后缀名
      sentinel:
        transport:
          # sentinel的地址
          dashboard: 127.0.0.1:8080
          # 默认端口号,如果被占用自动+1扫描,直到未被占用端口
          port: 8719

management:
  endpoints:
    web:
      exposure:
        include: '*'

启动服务,需要请求服务服务的某个接口,不然sentinel是空白页面。

image-20221103140058735

2.2、Sentinel 之流量监控

簇点链路:访问服务对应的访问路径,也会监控QPS、线程数等数据

image-20221103143954575

流控规则:对某个簇点设置对应的流控规则。

image-20221103144656730

  • 资源名:簇点访问路径
  • 针对来源:Sentinel可以针对调用者进行限流,默认是default(不分来源),一般填写微服务名称。
  • 阈值类型:
    • QPS:当api的每秒的请求数量达到阈值时进行限流。
    • 线程数:当调用api的线程数达到阈值时进行限流。
  • 是否集群:是否在集群中进行限流。
  • 流控模式:
    • 直接:当api达到限流条件时,直接限流。
    • 关联:当关联的api达到限流条件时,就限流自己。
    • 链路:只记录链路上的流量(如果api是从某个链路来的流量,当流量达到阈值就进行限流自己)。
  • 流控效果:
    • 快速失败:直接失败,抛出异常。
    • Warm Up:(预热),有一个默认的冷却因子3,当QPS、线程数达到 阈值 = 阈值\3 之前开始预热,会设置一个预热时间,在这个时间阈值有一个缓冲上升直到达到设置阈值。
    • 排队等待:匀速排队,设置请求超时时间(毫秒),这时阈值类型必须是QPS,否则无效。

QPS:指每一秒中请求api的次数。

线程数:
指服务中处理请求的线程数。

2.3、Sentinel 之服务降级

​ Sentinel熔断降级会在调用链路中某个资源出现不稳定状态(调用超时或异常比例升高),会对这个资源的请求进行限制,让请求快速失败,以避免影响到其它资源导致联错误。当服务降级后,在降级时间窗口之内,调用该资源就会自动熔断抛出异常(DegradeException)。

image-20221103165906979

现代微服务架构都是分布式的,由非常多的服务组成。不同服务之间相互调用,组成复杂的调用链路。以上的问题在链路调用中会产生放大的效果。复杂链路上的某一环不稳定,就可能会层层级联,最终导致整个链路都不可用。因此我们需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩。熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置。

  • 慢调用比例:(响应时间)
    • 最大RT:最大响应时间,当一个请求的响应时间超过这个阈值就是一个异常请求(单位:秒),这个服务进入准降级状态。
    • 最小请求数:当出现一个异常请求后,在一个单位时间内(默认是1s)会统计请求数,如果超过最小请求数,则统计时间内异常请求数的比例是否操作比例阈值,超过就进行服务降级。
    • 熔断时长:当服务发生熔断时,在熔断时长内所有请求自动抛出异常,时长过后服务继续使用,再出现熔断继续抛出异常。
    • 比例阈值:单位时间内,异常比例超过这个值就发生熔断。

image-20221103180246280

  • 异常比例:
    • 比例阈值:当请求出现异常时,在单位时间(1s)就会统计请求数量,如果请求数量超过最小请求数并且异常请求比例超过比例阈值,服务就会进行熔断。(如果熔断后恢复,第一次请求出现异常会继续熔断)

image-20221103183037189

  • 异常数:
    • 异常数:当请求出现异常,会在单位时间(1s)统计请求数量,如果请求数量大于最小请求数并且异常数量超过异常数,服务就进行降级。

2.4、Sentinel 之热点限流

​ 热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

编写一个热点限流接口:

@GetMapping("/hot")
// 作为热点限流的唯一标识,一般写rest接口名
// blockHandler:指定一个限流后的处理方法
@SentinelResource(value = "hot",blockHandler = "paramFlowExceptionHandler")
public String hotKey(@RequestParam(value = "p1", required = false) String p1,
                     @RequestParam(value = "p2", required = false) String p2){
    return "success test";
}

public static String paramFlowExceptionHandler(String p1, String p2, BlockException blockException){
    return p1+"热点数据被限流";
}

配置热点参数限流:

image-20221106155029278

image-20221106155126458

上面就表示,当访问的接口为url为:127.0.0.1:8081/hot?p1=xxx时,只要p1这个参数不为空,并且QPS超过阈值就会进行热点限流。如果p1为空就没有限流规则。参数索引就是指定需要进行热点参数的下标位置,从0开始。

参数例外项:当有时候我们希望热点参数为某个值时,对应的QPS的限流不一样,可以通过参数例外项进行控制。

image-20221106165223268

2.5、Sentinel 之系统规则

​ Sentinel 系统自适应保护从整体维度对应用入口流量进行控制,结合应用的 Load、总体平均 RT、入口 QPS 和线程数等几个维度的监控指标,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

image-20221106171656918

​ 系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量,比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。

  • Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般是 CPU cores * 2.5
  • CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0)。
  • RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  • 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

2.6、Sentinel 之@SentinelResource注解

基于资源名的流控、降级、热点:将@SentinelResource的value属性作为资源名,之前使用的rest地址作为资源名。

@GetMapping("/resource/test1")
@SentinelResource(value = "test1",blockHandler = "handlerTest1")
public String test(){
    return "test1";
}

public static String handlerTest1(BlockException e){
    return "处理test1的sentinel异常";
}

image-20221106174315732

blockHandler属性:
用于处理当满足在sentinel设置的规则进行处理时,自定义处理方法名,设置后不再使用sentine默认的返回值。

  • 处理方法必须在同一个类中。
  • 处理方法的返回值类型和参数必须与对应接口相同,并且需要再后面新增一个BlockException参数。
  • 处理方法必须使用static修饰,不然不会被解析,方法也必须是public修饰。

若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。但是使用上面方式去处理会发现每一个接口都需要一个自定义处理方法,这样代码膨胀,需要全局去处理。

blockHandler和fallback的理解:

blockHandler:指定一个方法去处理违反了sentinel配置规则的请求,不在使用sentinel默认的处理方式。

fallback:指定一个方法去处理在请求接口时出现了Java异常时,进行异常处理,不在用户页面展示报错信息。

@GetMapping("/resource/test2")
// fallback:指定处理异常的方法
@SentinelResource(value = "test2",fallback = "fallbackHandler")
public String test1(){
    int i = 1/0;
    return "test1";
}

// 方法名指定、static修饰、返回值类型相同、参数相同并且加一个Throwable、public修饰
public static String fallbackHandler(Throwable e){
    return "处理test1的Java异常"+e.getMessage();
}

image-20221107152803709

注意 blockHandler只处理在违背了sentinel配置错误时的异常,fallback只处理Java运行时的异常。

exceptionsToIgnore属性:参数是数组,当出现数组里面的异常时不进行处理

image-20221107154611842

Sentinel规则持久化:默认在Sentinel的规则都是临时的,只要关闭了服务所有的规则就会消失。下面介绍将Sentinel规则持久化进Nacos中。

  1. 引入依赖
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
  1. 修改pom

3、 OpenFeign 远程服务调用

​ Feign是一个声明式 Web 服务客户端。 它使编写 Web 服务客户端变得更加容易。 要使用Feign创建一个接口并对其进行注释。 它具有可插拔的注释支持,包括Feign注释和JAX-RS注释。 Feign还支持可插拔编码器和解码器。 Spring Cloud 增加了对 Spring MVC 注释的支持,并支持在 Spring Web 中默认使用相同注释。 Spring Cloud 集成了 Eureka 和 Spring Cloud LoadBalancer,以便在使用 Feign 时提供负载平衡的 http 客户端。HttpMessageConverters

导入依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

3.1、Openfeign 之基本使用

开启openfeign:使用@EnableFeignClients注解开启,basePackages数组属性:去指明应用程序A在启动的时候需要扫描服务B中的标注了@FeignClient注解的接口的包路径。

@SpringBootApplication
// 扫描com.cj包下所有带有@FeignClient的接口
@EnableFeignClients(basePackages = {"com.cj"})
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }
}

编写接口:

// value:是调用哪个注册到nacos中心服务的服务名称
// contextId:这个是调用注入时是bean的名称
@FeignClient(value = SourceConstants.ORDER_SOURCE)
public interface OrderRemoteService {

    // 在这个服务下对应的调用的那个接口
    @GetMapping("/order")
    R order();
}

编写服务调用:

@RestController
public class ConsumerController {

    // 注入编写好的openfeign接口,然后直接可以进行调用方法
    @Resource
    private OrderRemoteService orderRemoteService;

    @GetMapping("/1")
    public R consumer(){
        return orderRemoteService.order();
    }
}

总结:

  • Openfeign:是一个面向接口的远程服务调用,并且自带了负载均衡功能。
  • 使用:需要将服务注册到nacos中,并且在接口上指定调用服务的名称。

3.2、Openfeign 之超时控制

​ 在时机开发中,一些业务的处理时间可能和Openfeign默认的超时时间存在时间差,导致业务是正常时间完成但是Openfeign会报TimeOutException,所以需要我们自己去控制Openfeign的超时时间。

模拟超时异常:在业务逻辑让线程睡5s

@GetMapping("/timeOut")
public R timeOut(){
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return R.success("端口获取成功",port);
}

远程调用:

@GetMapping("/2")
public R timeOut(){
    return orderRemoteService.timeOut();
}

image-20221106122726306

修改超时时间:

image-20221106122904288

3.3、Openfeign 之异常处理

配置日志:编写一个配置类,设置对应的日志等级。

@Configuration
public class OpenfeignConfig {
    @Bean
    Logger.Level openFeignLoggerLevel(){
        return Logger.Level.FULL;
    }
}
  • NONE:默认,不显示任何日志。
  • BASIC:仅记录请求方法、url、响应状态码、执行时间。
  • HEADERS:除BASIC中的内容,还有请求头、响应头信心。
  • FULL:所有请求信息。

配置日志:

logging:
  level:
    # 配置openfeign以什么级别去监控哪个接口
    com.jx.*: debug

Openfeign+Sentinel远程服务异常处理:

  1. 将服务注册进Sentinel中,并开启Openfeign的Sentinel支持。
feign:
  sentinel:
    enabled: true
  client:
    config:
      default:
        # 修改openfeign的超时时间
        readTimeout: 5000 # 修改为5s
        connectTimeout: 5000
  1. 增加一个远程调用异常处理类
// 当调用远程服务出异常时,通过这个类进行处理,实现FallbackFactory接口,并重写create方法
@Component
public class OrderRemoteFallbackFactory implements FallbackFactory<OrderRemoteService> {

    private static final Logger log = LoggerFactory.getLogger(OrderRemoteFallbackFactory.class);

    @Override
    public OrderRemoteService create(Throwable cause) {
        log.error("order远程服务调用失败:{}", cause.getMessage());
        return new OrderRemoteService() {
            @Override
            public R order() {
                // 在这个方法中返回出现异常后的远程调用结果
                return R.error("order远程服务调用失败:{}",cause.getMessage());
            }

            @Override
            public R timeOut() {
                return R.error("order远程服务调用失败:{}",cause.getMessage());
            }

            @Override
            public R exceptionTest() {
                System.out.println("============================================");
                return R.error("order远程服务调用失败:{}",cause.getMessage());
            }
        };
    }
}
  1. 修改远程接口,在@FeignClient注解上添加fallbackFactory属性
@FeignClient(contextId = "orderRemoteService",value = SourceConstants.ORDER_SOURCE,fallbackFactory = OrderRemoteFallbackFactory.class)
public interface OrderRemoteService {

    @GetMapping("/order")
    R order();

    @GetMapping("/timeOut")
    R timeOut();

    @GetMapping("/exception")
    R exceptionTest();
}
  1. 编写一个测试接口/exception
@GetMapping("/exception")
public R exceptionTest() throws Exception {
    R r = null;
    r.put("name","name");
    return r;
}

image-20221106143435464

4、Gateway 服务网关

服务网关:在微服务的架构中,所有请求需要先通过网关,再由网关将请求路由转发到对应的每一个服务上。

  • 使用网关可以简化客户端工作,这样客户端只需和网关进行交互,不再很麻烦去交互所有的微服务。
  • 降低客户端与服务之间的耦合度,修改了服务接口只需要修改网关的配置策略,不用修改客户端。
  • 网关可以统一管理请求,可以实现负载均衡、流控、熔断降级、认证等操作。

image-20221108130711556

4.1、Gateway 之网关简介

Spring Cloud Gateway 使用的是Webflux中的reactor-netty响应式编程组件,底层是一个Netty通讯框架。

image-20221108130613413

Webflux是一个异步非阻塞框架,那么Gateway也是一个异步非阻塞模型,对于高并发请求性能很好。它能与 SpringCloud 生态很好兼容,单从流式编程+支持异步上也足以让开发者选择它了

image-20221108132212406

Gateway的三大组件:

  • Route路由:路由是构建网关的基本模块,它由ID、目标URL、一系列断言和过滤器组成,如果断言为true则进行路由转发。
  • Predicate断言:开发人员可以匹配Http请求的信息,如果请求与断言相匹配则进行路由转发。
  • Filter过滤器:使用过滤器,可以在请求的前或后对请求进行修改。

4.2、Gateway 之配置路由

引入网关依赖:

<!-- 引入gateway网关 -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-gateway</artifactId>
	<exclusions>
        <exclusion>
			<groupId>org.springframework.boot</groupId>
        	<artifactId>spring-boot-starter-web</artifactId>
        </exclusion>
    </exclusions>
</dependency>

注意,需要去除掉spring-boot-starter-web,不然启动会报错。

路由配置:Route 主要由 路由id、目标uri、断言集合和过滤器集合组成

  • id: 路由的唯一标识,必须唯一,自己定义。
  • uri:请求转发的目标地址。
  • order:路由的优先级,数字越小优先级越高。
  • predicates:断言数组,就是判断是否满足转发条件,如果断言为true就进行路由转发。
  • filters:过滤器,在请求的传递过程中对请求做一些修改。
spring:
  profiles:
    active: dev
  application:
    name: cloud-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8001
      config:
        server-addr: 127.0.0.1:8001
        file-extension: yml
    gateway:
      discovery:
        locator:
          lowerCaseServiceId: true
          enabled: true
      routes: # 配置路由
        - id: order # id,唯一标识
          uri: http://127.0.0.1:8000 # 路由转发的目标地址
          # 如果访问地址为 http://127.0.0.1:9000/order/test,他就会路由断言成功,就会转发到http://127.0.0.1:8000/test(去除了一级访问地址)
          predicates: # 断言判断,如果满足就进行路由转发
            - Path=/order/**
          filters:
            - StripPrefix=1 # 原始路去除到一级,上面就去除到/order

        - id: pay
          uri: http://127.0.0.1:9011
          predicates:
            - Path=/pay/**
          filters:
            - StripPrefix=1

Gateway动态路由配置:在服务架构中,服务可能是部署到多台服务上的,直接配置服务的url地址不方便,一旦服务ip地址发生变化就需要改配置,所以需要在注册中心去通过服务名称去发现服务并实现负载均衡的路由转发。

  1. 将Gateway网关注册进Nacos服务中心。
  2. 修改yaml配置文件
gateway:
  discovery:
    locator:
      # 路由的路径默认会使用大写ID,若想要使用小写ID,可将lowerCaseServiceId设置为true
      lowerCaseServiceId: true
      # 开启从注册中心动态创建路由功能
      enabled: true
  routes: # 动态配置路由
    - id: order
      uri: lb://cj-order # 固定格式:lb://+服务名
      predicates:
        - Path=/order/**
      filters:
        - StripPrefix=1

    - id: pay
      uri: lb://modules-pay-01
      predicates:
        - Path=/pay/**
      filters:
        - StripPrefix=1
  1. 引入依赖:因为带有负载均衡,需要引入loadbalancer
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

4.3、Gateway 之配置断言

 - id: pay
   uri: lb://modules-pay-01
   predicates:
       # 表示这个路径需要在这个时间之后访问才有效
       - After=2022-11-08T17:22:39.520+08:00[Asia/Shanghai]
       # 在这个时间之前访问才有效
       - Before=2017-01-20T17:42:47.789-07:00[America/Denver]
       # 在这个时间时间段访问才有效
       - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2022-11-08T17:22:39.520+08:00[Asia/Shanghai]
       # 带有指定cookie名的请求,并且值是指定的(支持正则)
       - Cookie=chocolate, ch.p
       # 带有指定的Header的请求,并且值是指定的(支持正则)
       - Header=X-Request-Id, \d+
       # Host带有指定值的,且值是指定的(支持正则)
       - Host=**.somehost.org,**.anotherhost.org
       # 指定方法的请求才有效果,可以指定多个,用逗号隔开
       - Method=GET,POST
       # 匹配请求路径
       - Path=/pay/**
       # 必须参数和正则参数,必须参数请求必须带有指定参数值的参数,正则参数就是满足对应正则的参数即可
       - Query=green, gree.
       # 请求的远程地址符合指定地址
       - RemoteAddr=192.168.1.1/24
       # 同一个uri的通过group分组,值表示权重,权重越高在负载均衡的时候分配的流量越大
       - Weight=group1, 2

时间格式的获取:

public static void main(String[] args) {
    ZonedDateTime now = ZonedDateTime.now();
    System.out.println(now);
    // 2022-11-08T16:44:48.004+08:00[Asia/Shanghai]
}

4.4、Gateway 之配置过滤器

Gateway自己的过滤器分为局部过滤和全局过滤,每个过滤器都有pre和post,局部有34个全局有9个。

文档地址:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#global-filters]

image-20221108165341659

自定义局部过滤器:可以自己定义局部过滤器让对应过滤器在对应的路由上使用。

// 配置局部过滤器,需要继承AbstractGatewayFilterFactory,<C>可能后续版本有用
@Component
@Slf4j
public class PartFilter extends AbstractGatewayFilterFactory<Object> {

    // 进行过滤操作
    @Override
    public GatewayFilter apply(Object config) {
        return (exchange, chain) ->{
            // 获取请求
            ServerHttpRequest request = exchange.getRequest();
            List<String> usernames = request.getQueryParams().get("username");
            System.out.println(usernames.toString());
            if (usernames==null || usernames.size()==0 || !usernames.get(0).equals("张三")){
                ServerHttpResponse response = exchange.getResponse();
                log.error("非法用户");
                // 直接拦截请求并返回错误信息
                return response.setComplete();
            }
            log.info("合法用户");
            // 放行请求
            return chain.filter(exchange);
        };
    }
}
filters:
  # 将局部filter设置到对应的路由中,过滤器的名称
  - PartFilter
  - StripPrefix=1

配置全局过滤器:全局过滤器回去过滤网关中所有的路由,直接注入就可使用,不用其它配置。

@Component
@Slf4j
public class FilterTest implements GlobalFilter, Ordered {

    // 自定义全局过滤操作
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取请求
        ServerHttpRequest request = exchange.getRequest();
        List<String> usernames = request.getQueryParams().get("username");
        System.out.println(usernames.toString());
        if (usernames==null || usernames.size()==0 || !usernames.get(0).equals("张三")){
            ServerHttpResponse response = exchange.getResponse();
            log.error("非法用户");
            // 直接拦截请求并返回错误信息
            return response.setComplete();
        }
        log.info("合法用户");
        // 放行请求
        return chain.filter(exchange);
    }

    // 设置过滤器的启动优先级,数字越小越先启动
    @Override
    public int getOrder() {
        return 0;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/85177.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

信号处理--基于EEG脑电信号的眼睛状态的分析

本实验为生物信息学专题设计小项目。项目目的是通过提供的14导联EEG 脑电信号&#xff0c;实现对于人体睁眼和闭眼两个状态的数据分类分析。每个脑电信号的时长大约为117秒。 目录 加载相关的库函数 读取脑电信号数据并查看数据的属性 绘制脑电多通道连接矩阵 绘制两类数据…

sdk manager (ubuntu20.4) 安装

1、首先下载sdk manager 1.9.3 下载链接 https://www.baidu.com/link?urlVXJhUqxxhS3eFK3bOPTzi5LFl6ybeW3JwDY1CwANaPf1gvO3IxQKzY547NIe53x1blJxnAXg7FTRTvs-cnfnVa&wd&eqida22baa7b0004ca980000000664e2d426 当然要登录自己的账号才能成功下载&#xff0c;下载对应…

神经网络基础-神经网络补充概念-54-softmax回归

概念 Softmax回归&#xff08;Softmax Regression&#xff09;是一种用于多分类任务的机器学习算法&#xff0c;特别是在神经网络中常用于输出层来进行分类。它是Logistic回归在多分类问题上的推广。 原理 Softmax回归的主要思想是将原始的线性分数&#xff08;得分&#xf…

k8s-dashboard使用指导手册

一、访问 dashboard http://172.66.209.101:32001 二、选择 Namespace 如下图&#xff1a; 1 在①搜索框中输入 spms 2 在②选择 spms-cloud 三、查找 pod 1 打开 pod 列表 2 打开过滤窗口 3 搜索 pod 在打开的搜索框中输入 pod的关键字&#xff0c;支持模糊搜索 如搜索…

以创新点亮前路,戴尔科技开辟数实融合新格局

编辑&#xff1a;阿冒 设计&#xff1a;沐由 2023年&#xff0c;对于戴尔科技而言是特殊的一年&#xff0c;这是戴尔科技进入中国市场第25个年头——“巧合”的是&#xff0c;这25年也是中国产业经济发展最快&#xff0c;人们工作与生活发生变化最大的四分之一个世纪。 2023年&…

QT-Mysql数据库图形化接口

QT sql mysqloper.h qsqlrelationaltablemodelview.h /************************************************************************* 接口描述&#xff1a;Mysql数据库图形化接口 拟制&#xff1a; 接口版本&#xff1a;V1.0 时间&#xff1a;20230727 说明&#xff1a;支…

LION AI 大模型落地,首搭星纪元 ES

自新能源汽车蓬勃发展以来&#xff0c;随着潮流不断进步和变革的“四大件”有着明显变化。其中有&#xff1a;平台、智能驾驶、配置、以及车机。方方面面都有着不同程度的革新。 而车机方面&#xff0c;从以前老旧的媒体机、 CD 机发展至如今具有拓展性、开放性、智能化的车机…

【xxl-job快速入门搭建】

目录标题 xxl-job快速入门搭建源码地址项目结构初始化数据库启动项目1、启动服务端2、启动任务执行器端 MD文档指导教程功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内…

RISC-V公测平台发布 · 数据库在RISC-V服务器上的适配评估

前言 上一期讲到YCSB在RISC-V服务器上对MySQL进行性能测试&#xff08;RISC-V公测平台发布 使用YCSB测试SG2042上的MySQL性能&#xff09;&#xff0c;在这一期文章中&#xff0c;我们继续深入讨论RISC-V数据库的应用。本期就继续利用HS-2平台来测试数据库软件在RISC-V服务器…

神经网络为什么可以学习

本资料转载于B站up主&#xff1a;大模型成长之路,仅用于学习和讨论&#xff0c;如有侵权请联系 动画解析神经网络为什么可以学习_哔哩哔哩_bilibilis 1、一个神经网络是由很多神经元形成的 1.1 也可以是一层&#xff0c;也可以是多层 2 层和层之间的连接就跟一张网一样 2.1 每…

python35种绘图函数总结,3D、统计、流场,实用性拉满

文章目录 基础图误差线三维图等高线图场图统计图非结构坐标图 基础图 下面这8种图像一般只有两组坐标&#xff0c;直观容易理解。 函数坐标参数图形类别plotx,y曲线图stackplotx,y散点图stemx,y茎叶图scatterx,y散点图polarx,y极坐标图stepx,y步阶图barx,y条形图barhx,y横向条…

excel导入导出百万级数据优化

背景 在我前年找实习的时候&#xff0c;遇到了面试官问我&#xff1a;mysql从excel导出百万级数据&#xff0c;该怎么做&#xff1f;我听到的第一反应是&#xff1a;我*&#xff0c;我哪去接触百万级的数据&#xff0c;你们导出的数据是什么&#xff1f;我还是一个才找实习工作…

python实战【外星人入侵】游戏并改编为【梅西vsC罗】(球迷整活)——搭建环境、源码、读取最高分及生成可执行的.exe文件

文章目录 &#x1f3a5;前言&#x1f4bc;安装Pygame&#x1f50b;游戏的实现读写并存储【外星人入侵】游戏最高分游戏源码alien_invasion.pygame_functions.pyship.pyalien.pybullet.pybutton.pyscoreboard.pygame_stats.pysettings.py宇宙飞船和外星人的 .bmp类型文件 &#…

Go语言入门指南:基础语法和常用特性(下)

上一节&#xff0c;我们了解Go语言特性以及第一个Go语言程序——Hello World&#xff0c;这一节就让我们更深入的了解一下Go语言的**基础语法**吧&#xff01; 一、行分隔符 在 Go 程序中&#xff0c;一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ;…

解决IDEA tomcat控制台只有server日志

解决IDEA tomcat控制台只有server日志 确认tomcatxxx/conf/logging.properties文件是否存在&#xff0c;存在就会有。前提是在run configuration配置了打印多个日志

K8s+Docker+KubeSphere+DevOps笔记

K8sDockerKubeSphereDevOps 前言一、阿里云服务器开通二、docker基本概念1.一次构建、到处运行2、docker基础命令操作3、docker进阶操作1.部署redis中间件2.打包docker镜像 三、kubernetes 大规模容器编排系统1、基础概念&#xff1a;1、服务发现和负载均衡2、存储编排3、自动部…

概率论与数理统计:第七章:参数估计 第八章:假设检验

文章目录 Ch7. 参数估计7.1 点估计1.矩估计2.最大似然估计(1)离散型(2)连续型 7.2 评价估计量优良性的标准(1)无偏性 (无偏估计)(2)有效性(3)一致性 7.3 区间估计1.置信区间、置信度2.求μ的置信区间 Ch8. 假设检验1.拒绝域α、接受域1-α、H₀原假设、H₁备择假设2.双边检验、…

操作符详解(2)

9.条件操作符 由问号和冒号组成&#xff0c;有三个表达式&#xff0c;有三个操作符&#xff0c;所以条件操作符是唯一的一个三目操作符&#xff0c;exp1为真&#xff0c;exp2则计算&#xff0c;exp3不算&#xff0c;整个表达式的结果就是exp2的结果。exp1为假&#xff0c;exp2…

【M波段2D双树(希尔伯特)小波多分量图像去噪】基于定向M波段双树(希尔伯特)小波对多分量/彩色图像进行降噪研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

如何使用CSS实现一个瀑布流布局?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用CSS实现瀑布流布局⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚…