SpringCloud Alibaba 教程

SpringCloud-Alibaba GitHub官方地址:

https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md

SpringCloud-Alibaba 官方文档:

https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html

要用springCloud-Alibaba 首先需要引入alibaba提供的 dependencyManagement 控制版本

<dependencyManagement>
    
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-dependenciesartifactId>
        <version>2020.0.0version>
        <type>pomtype>
        <scope>importscope>
    dependency>
    
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloudgroupId>
            <artifactId>spring-cloud-alibaba-dependenciesartifactId>
            <version>2021.1version>
            <type>pomtype>
            <scope>importscope>
        dependency>
    dependencies>
dependencyManagement>

springBoot,springCloud和springCloud Alibaba之间的版本依赖关系:

https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说明

Spring Cloud Version Spring Cloud Alibaba Version Spring Boot Version
Spring Cloud 2020.0.0 2021.1 2.4.2
Spring Cloud Hoxton.SR9 2.2.6.RELEASE 2.3.2.RELEASE
Spring Cloud Greenwich.SR6 2.1.4.RELEASE 2.1.13.RELEASE
Spring Cloud Hoxton.SR3 2.2.1.RELEASE 2.2.5.RELEASE
Spring Cloud Hoxton.RELEASE 2.2.0.RELEASE 2.2.X.RELEASE
Spring Cloud Greenwich 2.1.2.RELEASE 2.1.X.RELEASE
Spring Cloud Finchley 2.0.4.RELEASE(停止维护,建议升级) 2.0.X.RELEASE
Spring Cloud Edgware 1.5.1.RELEASE(停止维护,建议升级) 1.5.X.RELEASE

Nacos服务注册与发现

Nacos官方文档:https://nacos.io/zh-cn/docs/what-is-nacos.html

注册中心

1 导入依赖

<dependency> 
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency> 
    <groupId>com.alibaba.cloudgroupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>

2 启动器上加**@EnableDiscoveryClient** 注解

3 yaml配置

spring:
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      discovery:
        #是否为临时节点,如果否则断线后不会删除,默认是临时节点(断线后自动删除)
        ephemeral: false

配置中心

导入依赖

测试发现springCloud 2021.1以后的版本需要额外引入spring-cloud-starter-bootstrap

<dependency>
    <groupId>com.alibaba.cloudgroupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>

<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-bootstrapartifactId>
dependency>

创建bootstrap.yml

spring:
  application:
    name: employee
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      username: nacos
      password: nacos
      config:
        file-extension: yaml

启动项目后会自动去nacos中拉取 employee.yaml的配置文件

拉取文件的规则是 s p r i n g . a p p l i c a t i o n . n a m e − {spring.application.name}- spring.application.name{spring.profiled.active}.${file.extension}

拉取其他配置文件

在项目中我们可能会将公共的配置抽取出来放在单独的配置文件中(如果common.yaml),nacos配置中心也能够通过配置读取这些额外的配置文件

shared-configs 和 extensionConfigs 的功能完全一样 不同的是 extensionConfigs 优先级高于 shared-configs:

默认的(emp-dev.yaml ) > extensionConfigs > shared-configs

spring:  
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      username: nacos
      password: nacos
      config:
        file-extension: yaml
        shared-configs:
          #优先级最低
          - dataId: common.properties
            refresh: true #如果设置为false这不会动态刷新
        extensionConfigs:
          - dataId: common2.properties
            refresh: true

@RefreshScope

通常我们会通过@Value引用配置文件的配置内容,但是没有动态刷新的功能,如果要动态刷新,得在类上加==@RefreshScope注解实现动态刷新==

Nacos数据库持久化支持

nacos 内嵌了数据库实现持久化机制,在0.7版本后还支持了外部的mysql数据库(mysql版本必须为5.6.5+)

配置msyql持久化

1:初始化 conf/nacos-mysql.sql 文件

2:在conf/application.properties 文件内配置 数据库连接,用户名和密码

spring.datasource.platform=mysql
#数据库数量 单机为1个
db.num=1 
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
db.user=root
db.password=root

注: nacos内部使用的数据库驱动的5版本的,因此不支持Mysql8版本,如果你的Mysql版本为8则需要替换数据库驱动:

在nacos根目录创建 plugins/mysql 文件夹 并放入新的mysql驱动jar包,application.properties内的数据库连接也要换成Mysql8的连接

这样nacos就会持久化到Mysql数据库中

nacos开启权限控制

配置nacos服务器的配置文件

nacos.core.auth.enabled=true

LoadBalancer负载均衡调用

SpringCloud新版本中弃用了Ribbon,由LoadBalancer替代

1 引入依赖:

<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-loadbalancerartifactId>
dependency>

2 添加@LoadBalanced

@LoadBalanced
public RestTemplate restTemplate(){
    return new RestTemplate();
}

方法一:直接通过服务名调用

	//直接通过 服务名调用
	@Autowired
    private RestTemplate restTemplate;
    @GetMapping("/get")
    public String getDept(){  //deptApp代表了服务名 
        return restTemplate.getForObject("http://deptApp/hello",String.class);
    }

方法二: 通过LoadBalancerClient 实现负载均衡

	//通过LoadBalancerClient 实现负载均衡
	@Autowired
    private RestTemplate restTemplate;
    @Autowired
    private LoadBalancerClient balancerClient;
    @GetMapping("/get")
    public String getDept(){ //获取Dept服务的信息
        ServiceInstance dept = balancerClient.choose("Dept");
        //获取ip和端口号 此时会调用负载均衡算法动态获取
        String url = String.format("http://%s:%s/%s",dept.getHost(),dept.getPort(),"hello");
        return restTemplate.getForObject(url,String.class);//调用
    }

Feign 服务调用

OpenFeign底层整合了LoadBalancer,以接口的形式调用微服务

引入依赖

<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-openfeignartifactId>
dependency>

使用:

  1. @EnableFeignClients 开启Feign功能
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class EmpApplication {
    public static void main(String[] args) {
        SpringApplication.run( EmpApplication.class,args);
    }
}
  1. 申明接口
//value指定要调用的微服务名
@FeignClient(value = "dept")
public interface DeptFeign {
    @GetMapping("/hello")
    public String hello();
}
  1. 使用
@Autowired
private DeptFeign deptFeign;

@GetMapping("/hello")
public String hello(){
    return deptFeign.hello();
}

Feign 配置

全局配置

@Configuration
public class DeptFeignConfig  implements RequestInterceptor{

    //feign在发送请求的时候回调用此方法,允许我们对请求进行操作
    @Override
    public void apply(RequestTemplate requestTemplate) {
        MethodMetadata methodMetadata = requestTemplate.methodMetadata();
        //获取请求方式
        Method method = methodMetadata.method();
        requestTemplate.query("token","abc");
        requestTemplate.header("token","123");
        //获取请求路径
        System.out.println("---->"+requestTemplate.request().url());
    }
	
    //开启feign日志
    //NONE:不输出日志
    //BASIC:输出请求方法、URL、响应状态码、执行时间
    //HEADERS:BASIC+及请求和响应头
    //FULL:请求和响应的heads、body、metadata
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.BASIC;
    }
	//设置调用超时时间
    @Bean
    public Request.Options feignOptions(){
        return new Request.Options(1, TimeUnit.SECONDS,2,TimeUnit.SECONDS,true);
    }
}

feign日志的日志级别为debug,但是SpringBoot的默认日志级别为InFo

需要配置才能打印出feign日志

#springboot 默认的日志级别是info,改为debug
logging:
  level: #指定这个包下的日子为debug
    org.gjw.feign.*: debug
#feign的日志级别还可以这样配置
feign:
  client:
    config:
      dept:
        #配置 调用 dept微服务超时时间
        connectTimeout: 100 #连接时间
        readTimeout: 1000 #执行时间

Feign支持对请求与响应进行GZIP压缩,以减少通信中的性能损耗,默认对请求和相应压缩是禁用的

如果要启用需要配置:

开启压缩可以有效节约网络资源,但是会增加CPU压力,建议把最小压缩的文档大小适度调大一点

feign:
  compression:
    request:
      enabled: true
      mime-types: text/xml,application/xml,application/json
      min-request-size: 4096
    response:
      enabled: true
      useGzipDecoder: true

如果要为每个微服务单独配置,则可以通过@FeignClient指定配置类

//使用 DeptFeignConfig 内的配置
@FeignClient(value = "dept",configuration = DeptFeignConfig.class)
public interface DeptFeign {
    @GetMapping("/hello")
    public String hello();
}

Sentinel 服务熔断

Sentinel官网: https://sentinelguard.io/zh-cn/

将服务交给Sentinel管控

1 导入依赖

 <dependency>
     <groupId>com.alibaba.cloudgroupId>
     <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>

2 配置 yaml

 sentinel:
      transport:
        dashboard: 127.0.0.1:8080 #配置Dashboard的ip和的客户
        port: 8719 # #配置与Dashboard交互的端口 随便定义一个即可(只要未被占用,如果被占用会自行+1寻找端口)

Sentinel流控规则(Flow)

1. QPS

指一秒内允许访问的次数,一旦超过规定次数直接进行流控
SpringCloud Alibaba 教程_第1张图片

2. 并发线程数

指处理请求的最大线程数,一旦线程数超过指定阈值直接流控

Sentinel 并发控制不负责创建和管理线程池,而是简单统计当前请求上下文的线程数目 (正在执行的调用数目),如果超出阈值,新的请求会被立即拒绝,效果类似于信号量隔离。并发数控制通常在调用端 进行配置。

SpringCloud Alibaba 教程_第2张图片

3. 流控模式-直接

流控模式的直接模式: 当访问的资源被流控后直接返回错误信息.

4. 流控模式-关联

流控模式的联模式: 当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。比如对数据库同一个字段的读操作和写 操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本 身带来的开销会降低整体的吞吐量。可使用关联限流来避免具有关联关系的资源之间过度的争抢,举例来说,read_db 和 write_db 这两个资源分别代表数据库读写,我们可以给 read_db 设置限流规则来达到写优先的目的:设置 流控模式为关联 write_db。这样当写库操作过于频繁时,读数据的请求会被限流。
SpringCloud Alibaba 教程_第3张图片

5.流控模式-链路

对一条链路的入口资源进行限流:

注意必须在application.yaml配置sentinel关闭接口收敛模式:

spring.cloud.sentinel.web-context-unify=false
SpringCloud Alibaba 教程_第4张图片

6. 流控效果-快速失败

当QPS超过任意规则的阈值后,新的请求就会被 立即拒绝,拒绝方式为抛出FlowException

7. 流控模式-预热

Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量 突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐 增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。 冷加载因子: codeFactor 默认是3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值,当接口一段时间不被访问又会进入冷启动状态,重新预热.

冷加载因子可以在客户端配置文件配置

spring.cloud.sentinel.flow.cold-factor: 3

8. 排队等待

匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,也即是让请 求以均匀的速度通过,对应的是漏桶算法。

排队等待主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下 来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的 请求。

@SentinelResource

-Dcsp.sentinel.statistic.max.rt=9999 设置 降级规则内的RT(基于响应时间的降级)最大值

授权规则: 需要实现RequestOriginParser

sentinle自定义被限流或熔断时抛出的异常

2.2.0一下版本 需要实现UrlBlockHandler接口

2.2.0以上 实现 BlockExceptionHandler接口

public class MyExceptionHandler implements BlockExceptionHandler {

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
        // FlowException  限流一次
        //ParamFlowException 参数限流异常
        //DegradeException  降级异常
        //AuthorityException 授权异常(黑白名单)
        //SystemBlockException 系统异常
        if(e instanceof FlowException){
            System.out.println("限流异常");
        }else if(e instanceof DegradeException){
            System.out.println("降级异常");
        }
    }
}

熔断规则(Degrade)

1. 慢调用比例

慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间), 请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并 且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态 (HALF­OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会 再次被熔断。
SpringCloud Alibaba 教程_第5张图片
以上配置表示:对/read_db接口进行统计,时间为5秒,5秒内如果接口处理时间超过100毫秒的比例为10%则对接口进行熔断.

2. 异常比例

异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例 大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF­OPEN 状 态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0], 代表 0% ­ 100%。
SpringCloud Alibaba 教程_第6张图片
该配置表示 /read_db 在1秒内发送异常的比例超过0.5后进行熔断,熔断时间为5秒

3. 异常数

异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探 测恢复状态(HALF­OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

注意:异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效
SpringCloud Alibaba 教程_第7张图片
以上配置表示: /read_db在5秒内发送异常此时超过1后(必须5次请求)进行熔断,时间为5秒

Seata 分布式事务

seata服务端搭建

1 下载

2.修改存储模式为db

seata支持3种存储模式:

  • file(默认): 在内存中操作全局事务会话信息并持久化到root.data文件内,性能较高
  • db: 全局事务会话信息通过db共享,性能较差
  • redis: 全局事务会话信息通过redis共享,性能高

修改模式为db:

打开config/file.conf,修改mode=db,然后修改db配置项内的信息,然后创建数据库并在数据库创建相应的表

该sql脚本位于seata源码下script\server\db\mysql.sql

CREATE TABLE IF NOT EXISTS `global_table`
(
    `xid`                       VARCHAR(128) NOT NULL,
    `transaction_id`            BIGINT,
    `status`                    TINYINT      NOT NULL,
    `application_id`            VARCHAR(32),
    `transaction_service_group` VARCHAR(32),
    `transaction_name`          VARCHAR(128),
    `timeout`                   INT,
    `begin_time`                BIGINT,
    `application_data`          VARCHAR(2000),
    `gmt_create`                DATETIME,
    `gmt_modified`              DATETIME,
    PRIMARY KEY (`xid`),
    KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),
    KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
    `branch_id`         BIGINT       NOT NULL,
    `xid`               VARCHAR(128) NOT NULL,
    `transaction_id`    BIGINT,
    `resource_group_id` VARCHAR(32),
    `resource_id`       VARCHAR(256),
    `branch_type`       VARCHAR(8),
    `status`            TINYINT,
    `client_id`         VARCHAR(64),
    `application_data`  VARCHAR(2000),
    `gmt_create`        DATETIME(6),
    `gmt_modified`      DATETIME(6),
    PRIMARY KEY (`branch_id`),
    KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
    `row_key`        VARCHAR(128) NOT NULL,
    `xid`            VARCHAR(96),
    `transaction_id` BIGINT,
    `branch_id`      BIGINT       NOT NULL,
    `resource_id`    VARCHAR(256),
    `table_name`     VARCHAR(32),
    `pk`             VARCHAR(36),
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_branch_id` (`branch_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8;

3 配置nacos注册中心和配置中心

配置Nacos注册中心: 负责事务参与者(微服务) 和TC通信

将Seata Server注册到Nacos,修改conf目录下的registry.conf,将type改为nacos,然后修改nacos的配置

配置Nacos配置中心

如果配置了seata server使用nacos作为配置中心,则配置信息会从nacos读取,file.conf可以不用配置。 只用配置registry.conf 使用nacos时也要注意group要和seata server中的group一致,默认group是"DEFAULT_GROUP"

1 修改 /seata/script/config-center/config.txt修改配置信息

config.txt位于seata的源码,必须下载源码才能操作

transport.type=TCP
transport.server=NIO
#注意guagnzou(事务分组名称)可以自定义,default要和register.conf内的nacos.cluster一致
service.vgroupMapping.guangzou=default
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false
#注意修改这里为db
store.mode=db		
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://localhost:3306/seata?useUnicode=true
store.db.user=root
store.db.password=root

2.执行nacos-config.sh脚本在nacos内生成配置文件

nacos-config.sh位于nacos的源码 script\config-center\nacos下

4 启动nacos服务端

以上步骤配置完成后即可执行bin/seata-server.bat 启动seata了

参数 全写 作用 备注
-h –host 指定注册到注册中心的ip 不指定获取当前ip,外网访问建议指定
-p –port 启动时的端口 默认8091
-m –storeMode 日志存储方式 支持file,db,redis默认为file
-n –serverNode 指定当前seata-server节点id 分布式使用,全局唯一默认1
-e –seataEnv 指定seata-server运行环境 如 dev,test 服务启动时会加载 registry-dev对应的配置

seata服务端使用

1. 引入依赖

在微服务中引入依赖

<dependency>
    <groupId>com.alibaba.cloudgroupId>
    <artifactId>spring-cloud-starter-alibaba-seataartifactId>
dependency>

2. 配置配置文件

spring:
  cloud:
    alibaba:
      seata:
        tx-service-group: guangzou #事务分组,要和config.txt内的分组保持一致
seata:
  registry:
    type: nacos #设置注册中心模式
    nacos:
      server-addr: 127.0.0.1:8848
      username: nacos
      password: nacos
      application: seata-server
      group: SEATA_GROUP #group要和register.conf保持一致
  config:
    type: nacos #配置中心配置
    nacos:
      server-addr: ${spring.cloud.nacos.server-addr}
      username: nacos
      password: nacos
      group: SEATA_GROUP  #group要和register.conf保持一致      

3.在数据库创建表

该sql脚本位于seata源码下的 script\client\at\db\mysql.sql

必须在所有操作到的数据库内创建!

CREATE TABLE IF NOT EXISTS `undo_log`
(
    `branch_id`     BIGINT(20)   NOT NULL COMMENT 'branch transaction id',
    `xid`           VARCHAR(100) NOT NULL COMMENT 'global transaction id',
    `context`       VARCHAR(128) NOT NULL COMMENT 'undo_log context,such as serialization',
    `rollback_info` LONGBLOB     NOT NULL COMMENT 'rollback info',
    `log_status`    INT(11)      NOT NULL COMMENT '0:normal status,1:defense status',
    `log_created`   DATETIME(6)  NOT NULL COMMENT 'create datetime',
    `log_modified`  DATETIME(6)  NOT NULL COMMENT 'modify datetime',
    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
  AUTO_INCREMENT = 1
  DEFAULT CHARSET = utf8 COMMENT ='AT transaction mode undo table';
  1. 使用@GlobalTransactional 开启事务

    远程服务对应的service方法也要加上

    @GlobalTransactional
    @Override
    public boolean buy(String name) {
        boolean flag = orderService.genOrder(name);

        int i=1/0;
        return flag ? baseMapper.minus(name) : flag;
    }

Gateway

spring Cloud Gateway 依赖

<dependency>
    <groupId>com.alibaba.cloudgroupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>

<dependency>
   <groupId>org.springframework.cloudgroupId>
      <artifactId>spring-cloud-starter-gatewayartifactId>
  dependency>

  <dependency>
     <groupId>org.springframework.cloudgroupId>
      <artifactId>spring-cloud-starter-loadbalancerartifactId>
  dependency>

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-webfluxartifactId>
dependency>

Predicates 断言

配置Predicates断言可以对请求进行拦截判断,只有断言通过才允许访问

Gatewary内置的断言:

时间断言 Before, After和Between

Before:在指定时间前允许访问

After:在指定时间后允许访问

Between:在指定时间范围内允许访问

配置的时间格式必须为 ZonedDateTime 格式 (可以用 ZonedDateTime.now()查看格式 )

predicates:
            - Path=/hello/**
            - Before=2020-04-13T21:27:04.242+08:00[Asia/Shanghai]
            - After=2020-04-13T21:27:04.242+08:00[Asia/Shanghai]
            - Between=2020-04-13T21:27:04.242+08:00[Asia/Shanghai],2020-04-13T21:27:04.242+08:00[Asia/Shanghai]

Cookie: 校验Cookie

spring:
  cloud:
    gateway:
      routes:
        # 匹配指定cookie的路由
      - id: cookie_route
        uri: http://www.taobao.com
        predicates:
        - Cookie=chocolate, abc #携带了chocolate并且值为正则表达式匹配的值(这是是abc)

Header: 校验请求头

spring:
  cloud:
    gateway:
      routes:
        # 匹配指定请求头的路由
      - id: header_route
        uri: http://www.jd.com/
        predicates: #有X-Request-Id请求头并且值为数字的
        - Header=X-Request-Id, \d+

Path:校验请求路径

spring:
  cloud:
    gateway:
      routes:
        # 匹配指定路径的路由
      - id: path_route
        uri: http://www.baidu.com
        predicates:
        - Path=/baidu/** #访问/baidu/转换到				http://www.baidu.com/baidu/**

Query: 校验参数

spring:
  cloud:
    gateway:
      routes:
        # 匹配指定请求参数的路由
      - id: cookie_route
        uri: http://tmall.com/
        predicates: #请求参数要有param1 并且为数字
        - Query=param1,\d+

Method: 匹配请求方法

spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: http://example.org
        predicates: #必须为get请求
        - Method=GET

RemoteAddr: 匹配ip地址

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: http://example.org
        predicates: #地址必须匹配
        - RemoteAddr=192.168.1.1/24

自定义 Predicates

gateway允许我们自定义断言工厂去创建我们自定义的断言,只需要实现AbstractRoutePredicateFactory即可

自定义类的名字必须以RoutePredicateFactory结尾

参照QueryRoutePredicateFactory创建我们自己的断言:

@Component
public class NameRoutePredicateFactory extends AbstractRoutePredicateFactory<NameRoutePredicateFactory.Config> {

    public NameRoutePredicateFactory() {
        super(NameRoutePredicateFactory.Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("name");
    }

    @Override
    public Predicate<ServerWebExchange> apply(NameRoutePredicateFactory.Config config) {
        return (GatewayPredicate) exchange -> {
            ServerHttpRequest request = exchange.getRequest();
            List<String> nameList = request.getQueryParams().get("name");
            //request参数内必须包含
            return CollUtil.isNotEmpty(nameList) && nameList.contains(config.getName());
        };
    }

    @Validated
    public static class Config {
        @NotEmpty
        private String name;


        public Config() {
        }

        public String getName() {
            return this.name;
        }

        public Config setName(String name) {
            this.name = name;
            return this;
        }

    }
}

使用:

spring:
  cloud:
    gateway:
      routes:
        - id: emp
          uri: lb://emp
          predicates:
            - Path=/emp/**
            - Name=zs #使用我们自己的断言
          filters:
            - StripPrefix=1

Filter过滤器

Spring Cloud Gateway 的 Filter 从作用范围可分为另外两种GatewayFilter 与 GlobalFilter。
GatewayFilter :应用到单个路由或者一个分组的路由上。
GlobalFilter :应用到所有的路由上。

局部过滤器

局部过滤器(GatewayFilter),是针对单个路由的过滤器。可以对访问的URL过滤,进行切面处理。在
Spring Cloud Gateway中通过GatewayFilter的形式内置了很多不同类型的局部过滤器。这里简单将
Spring Cloud Gateway内置的所有过滤器工厂整理成了一张表格,虽然不是很详细,但能作为速览使。

过滤器工厂 作用 参数
AddRequestHeader 为原始请求添加Header Header的名称及值
AddRequestParameter 为原始请求添加请求参数 参数名称及值
AddResponseHeader 为原始响应添加Header Header的名称及值
DedupeResponseHeader 剔除响应头中重复的值 需要去重的Header名称及去重策略
Hystrix 为路由引入Hystrix的断路器保护 HystrixCommand的名称
FallbackHeaders 为fallbackUri的请求头中添加具体的异常信息 Header的名称
PrefixPath 为原始请求路径添加前缀 前缀路径
PreserveHostHeader 为请求添加一个preserveHostHeader=true的属性,路由过滤器会检查该属性以决定是否要发送原始的Host
RequestRateLimiter 用于对请求限流,限流算法为令牌桶 keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus
RedirectTo 将原始请求重定向到指定的URL http状态码及重定向的url
RemoveHopByHopHeadersFilter 为原始请求删除IETF组织规定的一系列Header 默认就会启用,可以通过配置指定仅删除哪些Header
RemoveRequestHeader 为原始请求删除某个Header Header名称
RemoveResponseHeader 为原始响应删除某个Header Header名称
RewritePath 重写原始的请求路径 原始路径正则表达式以及重写后路径的正则表达式
RewriteResponseHeader 重写原始响应中的某个Header Header名称,值的正则表达式,重写后的值
SaveSession 在转发请求之前,强制执行WebSession::save操作
secureHeaders 为原始响应添加一系列起安全作用的响应头 无,支持修改这些安全响应头的值
SetPath 修改原始的请求路径 修改后的路径
SetResponseHeader 修改原始响应中某个Header的值 Header名称,修改后的值
SetStatus 修改原始响应的状态码 HTTP 状态码,可以是数字,也可以是字符串
StripPrefix 用于截断原始请求的路径 使用数字表示要截断的路径的数量
Retry 针对不同的响应进行重试 retries、statuses、methods、series
RequestSize 设置允许接收最大请求包的大小。如果请求包大小超过设置的值,则返回 413 Payload Too Large 请求包大小,单位为字节,默认值为5M
ModifyRequestBody 在转发请求之前修改原始请求体内容 修改后的请求体内容
ModifyResponseBody 修改原始响应体的内容 修改后的响应体内容
Default 为所有路由添加过滤器 过滤器工厂名称及值

使用:

通过 StripPrefix 实现 访问 /emp/a 会转发到emp访问的/a接口

spring:
  cloud:
    gateway:
      routes:
        - id: emp
          uri: lb://emp
          predicates:
            - Path=/emp/**
            - Name=zs
          filters:
            - StripPrefix=1

自定义局部过滤器

实现自定义的局部过滤器和 自定义断言一样,类名必须为GatewayFilterFactory后缀,然后实现AbstractGatewayFilterFactory,可以参照内置的过滤器实现自定义的过滤器

全局过滤器

全局过滤器对所有请求有效,不需要再配置文件进行配置。springCloud Gateway内置了很多全局过滤器:
SpringCloud Alibaba 教程_第8张图片

自定义全局过滤器

通过实现GlobalFilter 和 ordered 接口可以对请求在网关进行拦截 判断请求

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


    @Override //重写 GlobalFilter 接口方法
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        log.info("========***MyFilter**========");

        ServerHttpRequest request = exchange.getRequest();
        MultiValueMap<String, String> queryParams = request.getQueryParams();
        String name = queryParams.getFirst("name");
        log.info("data( name )==>"+name);
        if(name == null){ //没有用户名 拦截返回错误
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        } //放行
        return chain.filter(exchange);
    }

    @Override //重写 ordered的方法 返回本filter的加载顺序
    public int getOrder() {
        return 0;
    }
}

Gateway 其他配置

配置访问日志

要启动gateway的访问日志,需要设置 -Dreactor.netty.http.server.accessLogEnabled=true

这个配置是java属性,不能通过springboot配置

开启跨域支持

方式一: 通过代码配置

@Configuration
public class GwCorsFilter {

    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true); // 允许cookies跨域
        config.addAllowedOrigin("*");// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
        config.addAllowedHeader("*");// #允许访问的头信息,*表示全部
        config.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
        config.addAllowedMethod("OPTIONS");// 允许提交请求的方法类型,*表示全部允许
        config.addAllowedMethod("HEAD");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("DELETE");
        config.addAllowedMethod("PATCH");

        org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource source =
                new org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}

方式二: 通过yaml配置

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations: 
          '[/**]': 
            allowedOrigins: "*"
            allowedMethods:
              - GET
              - POST

Gateway整合 Sentinel

1 引入依赖

<dependency>
    <groupId>com.alibaba.cloudgroupId>
    <artifactId>spring-cloud-alibaba-sentinel-gatewayartifactId>
dependency>

<dependency>
    <groupId>com.alibaba.cloudgroupId>
    <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>

2 配置配置文件

spring:
  cloud:    
    sentinel:
      transport:
        dashboard: localhost:8080

Skywalking 链路追踪

skywalking是一个国产开源框架,2015年由吴晟开源 , 2017年加入Apache孵化器。skywalking是分布式系统的应用 程序性能监视工具,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。它是一款优秀的 APM(Application Performance Management)工具,包括了分布式追踪、性能指标分析、应用和服务依赖分析等。

官网:http://skywalking.apache.org/

下载:http://skywalking.apache.org/downloads/

Github:https://github.com/apache/skywalking

文档: https://skywalking.apache.org/docs/main/v8.4.0/readme

中文文档: https://skyapm.github.io/document-cn-translation-of-skywalking

SkyWalking 环境搭建部署

下载: https://skywalking.apache.org/downloads/
SpringCloud Alibaba 教程_第9张图片

下载好后直接进入bin目录点击start.bat即可启动,启动成功后通过浏览器访问808端口即可看到skywalking页面

如果启动时出错,能是前端项目的8080端口被占用,可以修改webapp内的webapp.yml的端口配置

Skywalking持久化跟踪数据

skysalking默认使用h2(内存数据库)进行数据存储,重启后日志会失效,我们可以换位mysql,Elasticsearch等数据库存储数据

使用mysql:

  1. 修改 config/application.yml 配置
storage:
  selector: ${SW_STORAGE:mysql} #默认是h2,修改为mysql
  1. 修改下面的mysql连接,用户名密码等
mysql:
    properties:
      jdbcUrl: ${SW_JDBC_URL:"jdbc:mysql://localhost:3306/swtest"}
      dataSource.user: ${SW_DATA_SOURCE_USER:root}
      dataSource.password: ${SW_DATA_SOURCE_PASSWORD:root}
      dataSource.cachePrepStmts: ${SW_DATA_SOURCE_CACHE_PREP_STMTS:true}
      dataSource.prepStmtCacheSize: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_SIZE:250}
      dataSource.prepStmtCacheSqlLimit: ${SW_DATA_SOURCE_PREP_STMT_CACHE_SQL_LIMIT:2048}
      dataSource.useServerPrepStmts: ${SW_DATA_SOURCE_USE_SERVER_PREP_STMTS:true}
    metadataQueryMaxSize: ${SW_STORAGE_MYSQL_QUERY_MAX_SIZE:5000}
    maxSizeOfArrayColumn: ${SW_STORAGE_MAX_SIZE_OF_ARRAY_COLUMN:20}
    numOfSearchableValuesPerTag: ${SW_STORAGE_NUM_OF_SEARCHABLE_VALUES_PER_TAG:2}
  1. 将mysql连接驱动放入 oap-libs 里面

  2. 重启 skywalking,会看到数据库内生成了很多表

微服务介入skywalking

sakwarlking 采用无侵入式的agent参数来实现,微服务在启动时加入agent参数即可注册进skywalking

 #!/bin/sh
# SkyWalking Agent配置
export SW_AGENT_NAME=springboot‐skywalking‐demo #服务名字,一般使用`spring.application.name`
export SW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800 #配置skywalking服务端地址
export SW_AGENT_SPAN_LIMIT=2000 #配置链路的最大Span数量,默认为 300。
export JAVA_AGENT=‐javaagent:/usr/local/soft/apache‐skywalking‐apm‐bin‐es7/agent/skywalking‐agent.jar #skywalking agen包的路径
java $JAVA_AGENT ‐jar springboot‐skywalking‐demo‐0.0.1‐SNAPSHOT.jar #jar启动

idea开发环境下可以如下配置

-Dserver.port=7002 -javaagent:C:\Users\19943\Desktop\springCloud\springCloud-Alibaba\App\apache-skywalking-apm-bin-es7\agent\skywalking-agent.jar -DSW_AGENT_NAME=dept -DSW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800

如果是gateway网关微服务还需要将agent\optional-plugins(可选插件)下的gateway.jar放入agent\plugins下开启spring-cloud-gateway的支持

自定义SkyWalking链路追踪

sakwalking默认只对controller接口进行调用记录,如果我们想对service层也进行监控,就需要自定义了

1 引入依赖

<dependency>
    <groupId>org.apache.skywalkinggroupId>
    <artifactId>apm‐toolkit‐traceartifactId>
    <version>8.5.0version> 
dependency>

2 在service层的方法上加上@Trace注解,让skywalking记录这个接口

我们还可以为追踪链路增加其他额外的信息,比如记录参数和返回信息。实现方式:在方法上增加@Tag或者@Tags。

 @Trace //使 skywalking管理此方法
@Tags({@Tag(key = "param", value = "arg[0]"), //配置要记录的参数
       @Tag(key = "user", value = "returnedObj")})//配置记录返回值
public boolean select(String name){
    return baseMapper.insert(new TableOrder(null,name)) == 1;
}

Skywalking集成日志框架

logback官方配置

log4j官方配置

log4j2j官方配置

springboot默认使用logback日志框架,这里使用logback记录日志

1 引入依赖

 <!‐‐ apm‐toolkit‐logback‐1.x ‐‐>
<dependency>
    <groupId>org.apache.skywalkinggroupId>
    <artifactId>apm‐toolkit‐logback‐1.xartifactId>
    <version>8.5.0version>
dependency>

2 添加logback-spring.xml文件,并配置 %tid 占位符


<configuration>
    <!‐‐ 引入 Spring Boot 默认的 logback XML 配置文件 ‐‐>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!‐‐ 日志的格式化 ‐‐>
        <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
            <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
                <Pattern>-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) [%tid]  %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wExlayout>
        encoder>
    appender>

    <!‐‐ 设置 Appender ‐‐>
    <root level="INFO">
        <appender‐ref ref="console"/>
    root>
configuration>

Skywalking通过grpc上报日志

gRPC报告程序可以将收集到的日志转发到SkyWalking OAP服务器上,然后我们直接通过skywalking即可看到日志

1 导入依赖

<dependency>
    <groupId>org.apache.skywalkinggroupId>
    <artifactId>apm-toolkit-logback-1.xartifactId>
    <version>8.5.0version>
dependency>

2.配置logback-spring.xml 新增 配置

<appender name="grpc-log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
    <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
        <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout">
            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{tid}] [%thread] %-5level %logger{36} -%msg%nPattern>
        layout>
    encoder>
appender>
<!‐‐ 设置 Appender ‐‐>
<root level="INFO">
    <appender‐ref ref="console"/>
    <appender‐ref ref="grpc-log"/>
root>

你可能感兴趣的:(SpringCloud,spring,spring,cloud,alibaba,分布式)