SpringCloud Alibaba版(中)

827 阅读18分钟

服务网关

Zuul路由网关(停更)

不学不用!了解一些!

Gateway新一代网关

分布式服务架构、微服务架构与 API 网关

在微服务架构里,服务的粒度被进一步细分,各个业务服务可以被独立的设计、开发、测试、部署和管理。这时,各个独立部署单元可以用不同的开发测试团队维护,可以使用不同的编程语言和技术平台进行设计,这就要求必须使用一种语言和平 台无关的服务协议作为各个单元间的通讯方式。

API 网关的定义

网关的角色是作为一个 API 架构,用来保护、增强和控制对于 API 服务的访问。

API 网关是一个处于应用程序或服务(提供 REST API 接口服务)之前的系统,用来管理授权、访问控制和流量限制等,这样 REST API 接口服务就被 API 网关保护起来,对所有的调用者透明。因此,隐藏在 API 网关后面的业务系统就可以专注于创建和管理服务,而不用去处理这些策略性的基础设施。

Gateway是什么

Spring Cloud Gateway是Spring官方基于Spring 5.0,Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。Spring Cloud Gateway作为Spring Cloud生态系中的网关,目标是替代ZUUL,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/埋点,和限流等。

Gateway9527初步搭建

1、创建cloud_gateway9527

2、依赖 (不需要web和actore依赖)

<dependencies>
        <!--gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--eureka-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </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>

3、配置文件


server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          #uri: http://localhost:8001          #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          #uri: http://localhost:8001          #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由
            #- After=2020-02-21T15:51:37.485+08:00[Asia/Shanghai]
            #- Cookie=username,zzyy
            #- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式

eureka:
  instance:
    hostname: cloud-gateway-service
  client: #服务提供者provider注册进eureka服务列表内
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

4、主启动类

@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class Cloud_GateWay9527 {
    public static void main(String[] args) {
        SpringApplication.run(Cloud_GateWay9527.class,args);
    }
}

路由没有业务类,就是一看门的。

5、测试

我们启动8001、7001和9527

添加网关前:http://localhost:8001/payment/get/4

添加网关后:http://localhost:9527/payment/get/4 这样就可以隐藏微服务的端口号。

image-20210123132117999

路由网关的两种配置方式

1、配置文件的方式,也就是前面的

2、就会说硬编码的方式。RouteLocator的Bean

@Configuration
public class GateWayConfog {
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder)
    {
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();

        routes.route("path_route_atguigu",
                r -> r.path("/guonei")
                        .uri("http://news.baidu.com/guonei")).build();

        return routes.build();
    }
}

Gateway配置动态网关

通过微服务名来实现动态路由

server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          #uri: http://localhost:8001          #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          #uri: http://localhost:8001          #匹配后提供服务的路由地址
          uri: lb://cloud-payment-service #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由
            #- After=2020-02-21T15:51:37.485+08:00[Asia/Shanghai]
            #- Cookie=username,zzyy
            #- Header=X-Request-Id, \d+  # 请求头要有X-Request-Id属性并且值为整数的正则表达式

eureka:
  instance:
    hostname: cloud-gateway-service
  client: #服务提供者provider注册进eureka服务列表内
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka


Gateway的Filter

自定义全局Filter

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Date;

/**
 * @auther zzyy
 * @create 2020-02-21 16:40
 */
@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter,Ordered
{

    /*
    * 访问方法需要验证用户名
    * */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
    {
        log.info("***********come in MyLogGateWayFilter:  "+new Date());
        
        String uname = exchange.getRequest().getQueryParams().getFirst("uname");

        if(uname == null)
        {
            log.info("*******用户名为null,非法用户,o(╥﹏╥)o");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }

        return chain.filter(exchange);
    }

    /*
    * 加载过滤器的顺序
    * */
    @Override
    public int getOrder()
    {
        return 0;
    }
}

分布式配置中心config

是什么

Spring Cloud Config用来为分布式系统中的基础设施和微服务应用提供集中化的外部配置支持,分为服务端和客户端两个部分。其中服务端又称为分布式配置中心,是一个独立的微服务应用,用来连接配置仓库并为客户端提供获取配置信息;而客户端则是微服务架构中的各个微服务应用或基础设施,它们通过指定配置中心来管理应用资源和业务相关的配置内容。服务器存储后端的默认实现使用git,也可以使用SVN仓库或者本地文件系统。

就是将配置文件统一管理,一处修改处处生效。

image-20210123150805384

服务端----总把头

环境搭建

在自己的gitee账户上创建一个仓库,然后将配置文件上传gitee.com/cbbgs/sprin…

也可以拉取到本地。

配置总控制中心的搭建

1、创建总配置中心cloud_config_center3344

2、导入依赖

<dependencies>
        <!--添加消息总线RabbitMQ支持-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <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>

3、书写配置文件

server:
  port: 3344

spring:
  application:
    name:  cloud-config-center #注册进Eureka服务器的微服务名
  cloud:
    config:
      server:
        git:
          uri: git@gitee.com:cbbgs/springcloud-config.git #Gitee上面的git仓库名字
          ####搜索目录
          search-paths:
            - springcloud-config
      ####读取分支
      label: master

#服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

4、书写启动类

@SpringBootApplication
/*添加服务端扫描*/
@EnableConfigServer
public class ConfigCenterMain3344 {

    public static void main(String[] args) {
        SpringApplication.run(ConfigCenterMain3344.class,args);
    }

}

5、测试

我们启动7001和3344进行测试

image-20210123155733414

成功访问到我们gitee仓库的配置。

访问规则:/分支/名字-环境.yml

config客服端配置

image-20210123160101124

1、创建客户端配置cloud_config_client3355

2、导入依赖

    <dependencies>
        <!--添加消息总线RabbitMQ支持-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <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>

3、书写客户端配置bootstrap.yml

server:
  port: 3355

spring:
  application:
    name: config-client
  cloud:
    #Config客户端配置
    config:
      label: master #分支名称
      name: config #配置文件名称
      profile: dev #读取后缀名称   上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
      uri: http://localhost:3344 #配置中心地址k

  #rabbitmq相关配置 15672是Web管理界面的端口;5672是MQ访问的端口
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

#服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

# 暴露监控端点
management:
  endpoints:
    web:
      exposure:
        include: "*"

4、主启动类

@EnableEurekaClient
@SpringBootApplication
public class ConfigClientMain3355
{
    public static void main(String[] args) {
            SpringApplication.run(ConfigClientMain3355.class, args);
    }
}

5、业务类,打印配置信息

@RestController
public class ConfigClientController
{
    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/configInfo")
    public String getConfigInfo()
    {
        return configInfo;
    }
}

6、测试

image-20210123162210867

存在的问题:如果在gitee上修改的配置文件,在配置中心的客户端是不能刷新出来的,需要重启客户端。怎么解决呢?

分布式配置客户端动态刷新

修改3355模块

修改yml,暴露监控断点

server:
  port: 3355

spring:
  application:
    name: config-client
  cloud:
    #Config客户端配置
    config:
      label: master #分支名称
      name: config #配置文件名称
      profile: dev #读取后缀名称   上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
      uri: http://localhost:3344 #配置中心地址k

  #rabbitmq相关配置 15672是Web管理界面的端口;5672是MQ访问的端口
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

#服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

##################新增###################################
# 暴露监控端点
management:
  endpoints:
    web:
      exposure:
        include: "*"

修改controller,添加注解@RefreshScope

@RestController
@RefreshScope  //新增
public class ConfigClientController
{
    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/configInfo")
    public String getConfigInfo()
    {
        return configInfo;
    }
}

手动刷新:curl -X POST "http://localhost:3355/actuator/refresh/"

image-20210123170831326

image-20210123170845715

这就请求到新 的了。避免了服务重启。

但是,如果image-20210123171336557

该怎么办,目前还办不到,需要我们的服务总线

服务总线Bus

image-20210123200221270

Bus之RabbitMQ环境安装

设计思想1

上面的流程中,虽然我们做到了利用一个消息总线触发刷新,而刷新所有客户端配置的目的,但是这种方式并不合适,如下:

  • 打破了微服务的职责单一性。微服务本身是业务模块,它本不应该承担配置刷新的职责。
  • 破坏了微服务各节点的对等性。
  • 如果客户端ip有变化,这时我们就需要修改WebHook的配置。

设计思想2

我们一般用思想二

Docker安装RabbitMQ

参考地址 blog.csdn.net/qq_34775355…

#拉取镜像                                                8         d23bdf5b1b1b   4 years ago   643MB
[root@cbbgs ~]# docker pull rabbitmq
Using default tag: latest
latest: Pulling from library/rabbitmq
f22ccc0b8772: Pull complete 
3cf8fb62ba5f: Pull complete 
e80c964ece6a: Pull complete 
c1d2d6c5864b: Pull complete 
0adcf6f8f5f2: Pull complete 
6d7425e3abe0: Pull complete 
b03e46685eee: Pull complete 
f83c4b83a829: Pull complete 
fab4bdeccdff: Pull complete 
02221abafa2c: Pull complete 
Digest: sha256:5a6e86289ee2d03a6889341bfb3a76943de1d0c4d01b777c4159a944d8d3e9cd
Status: Downloaded newer image for rabbitmq:latest
docker.io/library/rabbitmq:latest
#查看镜像
[root@cbbgs ~]# docker images
REPOSITORY                                           TAG       IMAGE ID       CREATED       SIZE
homemall-h                                           latest    8addc602c1ff   5 days ago    681MB
registry.cn-hangzhou.aliyuncs.com/cbbgs/homemall-h   latest    8addc602c1ff   5 days ago    681MB
homemall                                             latest    c3dd8526a983   6 days ago    724MB
registry.cn-hangzhou.aliyuncs.com/cbbgs/homemall     latest    c3dd8526a983   6 days ago    724MB
rabbitmq                                             latest    7471fb821b97   7 days ago    167MB
redis                                                latest    621ceef7494a   10 days ago   104MB
zookeeper                                            latest    28ffb774bc32   10 days ago   253MB
mysql                                                latest    d4c3cafb11d5   11 days ago   545MB
consul                                               latest    2823bc69f80f   5 weeks ago   120MB
java                                                 8         d23bdf5b1b1b   4 years ago   643MB
#运行容器
[root@cbbgs ~]# docker run -d -p 5672:5672 -p 15672:15672 rabbitmq
fbc4e7cc162f5476a6b461e2c4a13e7bcd2b87c90774088f8847a060927205ab
#查看后台的容器
[root@cbbgs ~]# docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED         STATUS         PORTS                                                                                              NAMES
fbc4e7cc162f   rabbitmq     "docker-entrypoint.s…"   5 seconds ago   Up 4 seconds   4369/tcp, 0.0.0.0:5672->5672/tcp, 5671/tcp, 15691-15692/tcp, 25672/tcp, 0.0.0.0:15672->15672/tcp   jolly_sinoussi
01b50d91518c   consul       "docker-entrypoint.s…"   2 days ago      Up 36 hours    8300-8302/tcp, 8301-8302/udp, 8600/tcp, 8600/udp, 0.0.0.0:8500->8500/tcp                           sad_swanson
3d6121d4f2c1   zookeeper    "/docker-entrypoint.…"   2 days ago      Up 2 days      2888/tcp, 3888/tcp, 0.0.0.0:2181->2181/tcp, 8080/tcp                                               dazzling_leakey
8137393ac557   redis        "docker-entrypoint.s…"   4 days ago      Up 4 days      0.0.0.0:6379->6379/tcp                                                                             silly_hoover
dca567a50338   homemall-h   "java -jar /app.jar …"   5 days ago      Up 5 days      0.0.0.0:8088->8088/tcp                                                                             objective_kalam
81cda9cbf07b   homemall     "java -jar /app.jar …"   6 days ago      Up 6 days      0.0.0.0:8084->80/tcp #进入rabbitmq                                                                              
[root@cbbgs ~]# docker exec -it fbc4e7cc162f /bin/bash

root@fbc4e7cc162f:/# rabbitmq-plugins enable rabbitmq_management
Enabling plugins on node rabbit@fbc4e7cc162f:
rabbitmq_management
The following plugins have been configured:
  rabbitmq_management
  rabbitmq_management_agent
  rabbitmq_prometheus
  rabbitmq_web_dispatch
Applying plugin configuration to rabbit@fbc4e7cc162f...
The following plugins have been enabled:
  rabbitmq_management

started 1 plugins.

就可以访问了image-20210123215523755

全局动态刷新

1、创建新模块cloud_config_clint3366

2、创建导入依赖

    <dependencies>
        <!--添加消息总线RabbitMQ支持-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bus-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <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>

3、书写配置

server:
  port: 3366

spring:
  application:
    name: config-client
  cloud:
    #Config客户端配置
    config:
      label: master #分支名称
      name: config #配置文件名称
      profile: dev #读取后缀名称   上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
      uri: http://localhost:3344 #配置中心地址

  #rabbitmq相关配置 15672是Web管理界面的端口;5672是MQ访问的端口
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

#服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

# 暴露监控端点
management:
  endpoints:
    web:
      exposure:
        include: "*"

4、书写启动类

@SpringBootApplication
@EnableEurekaClient
public class Cloud_config_Clent3366 {
    public static void main(String[] args) {
        SpringApplication.run(Cloud_config_Clent3366.class,args);
    }
}

5、书写控制类

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

    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/configInfo")
    public String configInfo()
    {
        return "serverPort: "+serverPort+"\t\n\n configInfo: "+configInfo;
    }

}
修改以前配置

1、修改config服务端3344的 依赖

添加rabbitmq相关配置和暴露

server:
  port: 3344

spring:
  application:
    name:  cloud-config-center #注册进Eureka服务器的微服务名
  cloud:
    config:
      server:
        git:
          uri: git@gitee.com:cbbgs/springcloud-config.git #Gitee上面的git仓库名字
          ####搜索目录
          search-paths:
            - springcloud-config
      ####读取分支
      label: master
#rabbitmq相关配置
rabbitmq:
  host: localhost
  port: 5672
  username: guest
  password: guest

#服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

##rabbitmq相关配置,暴露bus刷新配置的端点
management:
  endpoints: #暴露bus刷新配置的端点
    web:
      exposure:
        include: 'bus-refresh'

修改客户端3355

server:
  port: 3355

spring:
  application:
    name: config-client
  cloud:
    #Config客户端配置
    config:
      label: master #分支名称
      name: config #配置文件名称
      profile: dev #读取后缀名称   上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
      uri: http://localhost:3344 #配置中心地址k

  #rabbitmq相关配置 15672是Web管理界面的端口;5672是MQ访问的端口
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

#服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

# 暴露监控端点
management:
  endpoints:
    web:
      exposure:
        include: "*"

修改客户端3366

server:
  port: 3355

spring:
  application:
    name: config-client
  cloud:
    #Config客户端配置
    config:
      label: master #分支名称
      name: config #配置文件名称
      profile: dev #读取后缀名称   上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
      uri: http://localhost:3344 #配置中心地址k

  #rabbitmq相关配置 15672是Web管理界面的端口;5672是MQ访问的端口
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest

#服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

# 暴露监控端点
management:
  endpoints:
    web:
      exposure:
        include: "*"

这里没有区别,因为我之前导入的是全的。

测试启动 3344 3355 3366 7001

访问:http://localhost:3344/config-dev.yml http://localhost:3355/configInfo http://localhost:3366/configInfo

修改远程仓库的版本。我们将前面的3版本改成4.

我们只刷新一台机器就可以实现全部广播。curl -X POST "http://localhost:3355/actuator/refresh/"

image-20210124091336721

image-20210124091358333

这达到了一次修改,到处通知。

局部动态刷新

我们只想通知3355,不想通知3366

公式:curl -X POST "http://localhost:3344/actuator/bus-refresh/config-client:3355"

Stream消息驱动

image-20210123205121359

屏蔽底层消息中间件的差异,降低切换版本,统一消息的编程模型

中文指导手册:m.wang1314.com/doc/webapp/…

Binder可以理解为提供了Middleware操作方法的类。Spring Cloud 提供了Binder抽象接口以及KafKaRabbit MQ的Binder的实现。

image-20210123223938856 image-20210124101058087

创建三个项目cloud-stream-rabbitmq-provider8801 cloud-stream-rabbitmq-consumer8802 cloud-stream-rabbitmq-consumer8803

消息驱动之生产者

1、创建cloud-stream-rabbitmq-provider8801

2、导入依赖

<dependencies>
        <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.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</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>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.5.7</version>
        </dependency>
    </dependencies>

3、导入配置

server:
  port: 8801

spring:
  application:
    name: cloud-stream-provider
  cloud:
    stream:
      binders: # 在此处配置要绑定的rabbitmq的服务信息;
        defaultRabbit: # 表示定义的名称,用于于binding整合
          type: rabbit # 消息组件类型
          environment: # 设置rabbitmq的相关的环境配置
            spring:
              rabbitmq:
                host: 47.93.49.117
                port: 5672
                username: guest
                password: guest
      bindings: # 服务的整合处理
        output: # 这个名字是一个通道的名称
          destination: studyExchange # 表示要使用的Exchange名称定义
          content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain”
          binder: defaultRabbit # 设置要绑定的消息服务的具体设置

eureka:
  client: # 客户端进行Eureka注册的配置
    service-url:
      defaultZone: http://localhost:7001/eureka
  instance:
    lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
    lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
    instance-id: localhost  # 在信息列表时显示主机名称
    prefer-ip-address: true     # 访问的路径变为IP地址

4、启动类

@SpringBootApplication
@EnableEurekaClient
public class Cloud_stream_rabbit_provoder8801 {
    public static void main(String[] args) {
        SpringApplication.run(Cloud_stream_rabbit_provoder8801.class,args);
    }
}

5、业务类

发送消息的接口

public interface IMessageProvider {
    public String send();
}

发送消息的实现类

@EnableBinding(Source.class) //定义消息的推送管道
public class MessageProviderImpl implements IMessageProvider
{
    @Resource
    private MessageChannel output; // 消息发送管道

    @Override
    public String send()
    {
        String serial = new Random().toString();
        output.send(MessageBuilder.withPayload(serial).build());
        System.out.println("*****serial: "+serial);
        return null;
    }
}

controller

@RestController
public class SendMessageController
{
    @Resource
    private IMessageProvider messageProvider;

    @GetMapping(value = "/sendMessage")
    public String sendMessage()
    {
        return messageProvider.send();
    }

}

6、测试

启动7001 和8801

消息驱动的消费者

1、创建 cloud-stream-rabbitmq-consumer8802

2、导入依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</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>

3、导入配置

server:
  port: 8802

spring:
  application:
    name: cloud-stream-consumer
  cloud:
    stream:
      binders: # 在此处配置要绑定的rabbitmq的服务信息;
        defaultRabbit: # 表示定义的名称,用于于binding整合
          type: rabbit # 消息组件类型
          environment: # 设置rabbitmq的相关的环境配置
            spring:
              rabbitmq:
                host: 47.93.49.117
                port: 5672
                username: guest
                password: guest
      bindings: # 服务的整合处理
        input: # 这个名字是一个通道的名称
          destination: studyExchange # 表示要使用的Exchange名称定义
          content-type: application/json # 设置消息类型,本次为对象json,如果是文本则设置“text/plain”
          binder: defaultRabbit # 设置要绑定的消息服务的具体设置



eureka:
  client: # 客户端进行Eureka注册的配置
    service-url:
      defaultZone: http://localhost:7001/eureka
  instance:
    lease-renewal-interval-in-seconds: 2 # 设置心跳的时间间隔(默认是30秒)
    lease-expiration-duration-in-seconds: 5 # 如果现在超过了5秒的间隔(默认是90秒)
    instance-id: localhost  # 在信息列表时显示主机名称
    prefer-ip-address: true     # 访问的路径变为IP地址

4、启动类


@SpringBootApplication
public class Cloud_RabburMQ_Consumer8802 {


        public static void main(String[] args)
        {
            SpringApplication.run(Cloud_RabburMQ_Consumer8802.class,args);
        }

}

5、业务类

@Component
@EnableBinding(Sink.class)
public class ReceiveMessageListenerController
{
    @Value("${server.port}")
    private String serverPort;


    @StreamListener(Sink.INPUT)
    public void input(Message<String> message)
    {
        System.out.println("消费者1号,----->接受到的消息: "+message.getPayload()+"\t  port: "+serverPort);
    }

6、测试

image-20210124114533433

image-20210124114543443

分组消费与持久化

我们新建一个8803与8802一模一样只有端口不同。

测试运行之有两个问题,重复消费和消息持久化的问题。

重复消费

image-20210124121010809

同一个组是竞争关系,不会重复消费。

解决的办法就是分组。

分组

微服务应用放置于同一个group中,就能够保证消息只会被其中一个应用消费一次。不同的组是可以消费的,同一个组内会发生竞争关系,只有其中一个可以消费

修改配置类 ,把8802和8803放在一个组

image-20210124122140236

这样就不会重复消费

持久化

只要分组之后消息 就会持久化。

Sleuth分布式请求链路跟踪

在微服务框架中,一个客户端发起的请求在后端系统中会经过多个不同的服务节点调用来协同产生最后的请求结果,每一个前端请求都会形成一条复杂的分布式服务调用链路,链路中的任何一环出现高延时或错误都会引起整个请求最后的失败。SpringCloud Sleuth 提供了一套完整的服务跟踪的解决方案,在分布式系统中提供追踪解决方案并且兼容支持了zipkin 。官方文档地址:cloud.spring.io/spring-clou… 。一条链路通过Trace Id(类似于树结构的Span集合,表示一条调用链路,存在唯一标识)唯一标识,Span(表示调用链路来源,每个span就是一次请求信息)标识发起的请求信息,各Span通过parent id关联起来

docker安装zipkin

[root@cbbgs ~]# docker pull openzipkin/zipkin
Using default tag: latest
latest: Pulling from openzipkin/zipkin
85c4faba369c: Pull complete 
ab3ad91c6210: Pull complete 
f1b5a7ad9eac: Pull complete 
b537b11d70b5: Pull complete 
a950eaa7714c: Pull complete 
40c09f4d3bf5: Pull complete 
d7ab6ba0c34d: Pull complete 
4b755abb84fe: Pull complete 
d4d046ad588d: Pull complete 
Digest: sha256:1ae0572be3d26fd9ab3fd2da5e8feaa0ca0078dbc31e2ddfb881b1a56bc332b1
Status: Downloaded newer image for openzipkin/zipkin:latest
docker.io/openzipkin/zipkin:latest
[root@cbbgs ~]# docker run -d  -p 9411:9411 --name zipkin openzipkin/zipkin 

搭建链路监控

SpringCloud从F版起已不需要自己构建Zipkin server了,只需要调用jar包即可。

我们用8001修改

1、修改8 001的依赖

<!--包含了sleuth+zipkin-->
       <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>

2、修改8001的配置文件

server:
  port: 8001

spring:
  application:
    name: cloud-payment-service
    
    ###############新加入的########
  zipkin:
    base-url: http://localhost:9411
    sleuth:
      sampler:
      #采样率值介于 0 到 1 之间,1 则表示全部采集
      probability: 1
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource    # 当前数据源操作
   # driver-class-name: org.gjt.mm.mysql.Driver #mysql驱动包
    url: jdbc:mysql://47.93.49.117:3306/db2020?serverTimezone=UTC
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver


eureka:
  client:
    #表示是否将自己注册进EurekaServer默认为true。
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      #单机版
      defaultZone: http://localhost:7001/eureka
      # 集群版
      #defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
  instance:
    instance-id: payment8001
    #访问路径可以显示IP地址
    prefer-ip-address: true
    #Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
    #lease-renewal-interval-in-seconds: 1
    #Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
    #lease-expiration-duration-in-seconds: 2



mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.atguigu.springcloud.entity   #所有Entity别名类所在的包

3、修改controller

@GetMapping("/payment/zipkin")
    public String paymentZipkin()
    {
        return "hi ,i'am paymentzipkin server fall back,welcome to atguigu,O(∩_∩)O哈哈~";
    }

修改80

1、修改80的依赖和配置文件修改和8001相同。

2、修改 80的controller

image-20210124192518955

// ====================> zipkin+sleuth
    @GetMapping("/consumer/payment/zipkin")
    public String paymentZipkin()
    {
        String result = restTemplate.getForObject("http://localhost:8001"+"/payment/zipkin/", String.class);
        return result;
    }
image-20210124192229742 image-20210124192242307

SpringCloud Alibaba

官方文档:spring-cloud-alibaba-group.github.io/github-page…

github.com//alibaba/sp…

  • 服务限流降级:默认支持 WebServlet、WebFlux, OpenFeign、RestTemplate、Spring Cloud Gateway, Zuul, Dubbo 和 RocketMQ 限流降级功能的接入,可以在运行时通过控制台实时修改限流降级规则,还支持查看限流降级 Metrics 监控。
  • 服务注册与发现:适配 Spring Cloud 服务注册与发现标准,默认集成了 Ribbon 的支持。
  • 分布式配置管理:支持分布式系统中的外部化配置,配置更改时自动刷新。
  • 消息驱动能力:基于 Spring Cloud Stream 为微服务应用构建消息驱动能力。
  • 分布式事务:使用 @GlobalTransactional 注解, 高效并且对业务零侵入地解决分布式事务问题。。
  • 阿里云对象存储:阿里云提供的海量、安全、低成本、高可靠的云存储服务。支持在任何应用、任何时间、任何地点存储和访问任意类型的数据。
  • 分布式任务调度:提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。同时提供分布式的任务执行模型,如网格任务。网格任务支持海量子任务均匀分配到所有 Worker(schedulerx-client)上执行。
  • 阿里云短信服务:覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道

下载

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

Nacos服务注册和配置中心

Nacos:注册中心+配置中心

替代Eureka做注册中心,替代Config做配置中心

官方文档:nacos.io/zh-cn/

Nacos安装

下载地址:github.com/alibaba/nac… 或者百度云下载pan.baidu.com/s/1186nmlqP… 验证码:rest

解压运行即可,验证 http://localhost:8848/nacos

docker安装

[root@cbbgs ~]# docker pull docker.io/nacos/nacos-server 
Using default tag: latest
latest: Pulling from nacos/nacos-server
5ad559c5ae16: Pull complete 
e6d451344e2a: Pull complete 
b4c15146d205: Pull complete 
ce7d16db8053: Pull complete 
3c588a7e0a56: Pull complete 
19c711321114: Pull complete 
d5f56a3318c0: Pull complete 
4966d7169362: Pull complete 
f97f03ae04b8: Pull complete 
86b0718f6d82: Pull complete 
925ba62ff508: Pull complete 
Digest: sha256:c475da3829ff4568668bc47c9136168ffe93b06be8a4271627d68a68e70f5b98
Status: Downloaded newer image for nacos/nacos-server:latest
docker.io/nacos/nacos-server:latest
[root@cbbgs ~]# docker run --env MODE=standalone --name nacos -d -p 8848:8848 nacos/nacos-server
dc4dc9f4b34a7df5d584a2707862ac9636fc9c687ffea3b1dfeaa21c3ede2eeb
[root@cbbgs ~]# docker ps
CONTAINER ID   IMAGE               COMMAND                  CREATED       STATUS                 PORTS                               NAMES
0d671962f6d2   redis               "docker-entrypoint.s…"   3 hours ago   Up 3 hours             0.0.0.0:6379->6379/tcp              distracted_khayyam
824db89b0893   openzipkin/zipkin   "start-zipkin"           3 hours ago   Up 3 hours (healthy)   9410/tcp, 0.0.0.0:9411->9411/tcp    zipkin
2f3d2671aa1a   mysql               "docker-entrypoint.s…"   3 hours ago   Up 3 hours             0.0.0.0:3306->3306/tcp, 33060/tcp   mysql8


#我们查看发现并没有运行成功!查看日志发现
docker logs dc4dc9f4b34a

nacos is starting,you can check the /home/nacos/logs/start.out
OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x0000000080000000, 1073741824, 0) failed; error='Cannot allocate memory' (errno=12)
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 1073741824 bytes for committing reserved memory.
# An error report file with more information is saved as:
# /home/nacos/hs_err_pid20.log


###内存不足怎么解决呢?
#删掉,之前容器
#不作任何修改.启动时,默认内存参数是-Xms512m -Xmx512m -Xmn256m
#解决办法:修改内存参数
#重新运行
docker run -e JVM_XMS=256m -e JVM_XMX=256m --env MODE=standalone --name nacos -d -p 8848:8848 nacos/nacos-server

访问测试:http://47.93.49.117:8848/nacos/index.html#/login nacos/nacos

Nacos之服务提供者注册

1、创建cloudalibaba-provider-payment9001

2、父项目依赖加上

<!-- 统一管理jar包版本 -->
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <junit.version>4.12</junit.version>
    <log4j.version>1.2.17</log4j.version>
    <lombok.version>1.16.18</lombok.version>
    <mysql.version>8.0.22</mysql.version>
    <druid.version>1.1.16</druid.version>
    <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
  </properties>


  <!-- 子模块继承之后,提供作用:锁定版本+子modlue不用写groupId和version  -->
  <dependencyManagement>
    <dependencies>
      <!--spring boot 2.2.2-->
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.2.2.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <!--spring cloud Hoxton.SR1-->
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Hoxton.SR1</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <!--spring cloud alibaba 2.1.0.RELEASE-->
      <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>
      <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.version}</version>
      </dependency>
      <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>${druid.version}</version>
      </dependency>
      <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>${mybatis.spring.boot.version}</version>
      </dependency>
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
      </dependency>
      <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>${log4j.version}</version>
      </dependency>
      <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>${lombok.version}</version>
        <optional>true</optional>
      </dependency>
    </dependencies>
  </dependencyManagement>

3、9001的依赖

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

4、配置文件

server:
  port: 9001

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

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

5、主启动类


@EnableDiscoveryClient
@SpringBootApplication
public class PaymentMain9001
{
    public static void main(String[] args) {
            SpringApplication.run(PaymentMain9001.class, args);
    }
}

6、controller

@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、测试

启动9001,登录nacos http://47.93.49.117:8848/nacos/index.html#/login

image-20210124211824971

我们按照9001,我们再建一个cloudalibaba-provider-payment9002

Nacos消费者注册 和负载

Nacos自带负载均衡

1、创建cloudalibaba-consumer-nacos-order83

2、依赖

 <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.atguigu.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>

3、配置文件

server:
  port: 83


spring:
  application:
    name: nacos-order-consumer
  cloud:
    nacos:
      discovery:
        server-addr: 47.93.49.117:8848


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

4、主启动类

@EnableDiscoveryClient
@SpringBootApplication
public class OrderNacosMain83
{
    public static void main(String[] args)
    {
        SpringApplication.run(OrderNacosMain83.class,args);
    }
}

5、controller

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

    @Value("${service-url.nacos-user-service}")
    private String serverURL;

    @GetMapping(value = "/consumer/payment/nacos/{id}")
    public String paymentInfo(@PathVariable("id") Long id)
    {
        return restTemplate.getForObject(serverURL+"/payment/nacos/"+id,String.class);
    }

}

6、配置类

@Configuration
public class ApplicationContextConfig
{
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate()
    {
        return new RestTemplate();
    }
}

7、测试

启动9001,9002,83,登录nacos页面

image-20210124214149573

image-20210124214254327

Nacos之服务配置中心

基础配置

1、新建cloudalibaba-config-nacos-client3377

2、导入依赖

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

3、书写配置文件

bootstrap.yml

# nacos配置
server:
  port: 3377

spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      discovery:
        server-addr: 47.93.49.117:8848 #Nacos服务注册中心地址
      config:
        server-addr: 47.93.49.117:8848 #Nacos作为配置中心地址
        file-extension: yaml #指定yaml格式的配置
        #group: DEV_GROUP
        #namespace: 7d8f0f5a-6a53-4785-9686-dd460158e5d4


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

# nacos-config-client-test.yaml   ----> config.info

application.yml

spring:
  profiles:
    active: dev # 表示开发环境
    #active: test # 表示测试环境
    #active: info

4、启动类

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

5、业务类

@RestController
@RefreshScope //支持Nacos的动态刷新功能。
public class ConfigClientController
{
    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/config/info")
    public String getConfigInfo() {
        return configInfo;
    }
}

6、云端配置文件,也就是在nacos面板添加 cbbgs.cn:8848/nacos/index…

image-20210124232317554

image-20210124232901970

image-20210124232945539

7、测试;启动3377

image-20210124234129581

并且nacos自带自动刷新!

只需要在controller添加注解@RefreshScope //支持Nacos的动态刷新功能。

Nacos集群配置和持久化

Nacos集群部署

1个Nginx,三个Nacos,一个mysql

官方参考nacos.io/zh-cn/docs/…

Nacos默认自带 嵌入式数据库derby,如果集群部署数据就会不一致。

1、执行mysql脚本,windows下载的Nacos压缩包就带有mysql脚本。image-20210125090015065

或者是官方的数据库脚本。

github.com/alibaba/nac…

2、修改本地安装的配置文件。我安装的是dockerhttps://github.com/alibaba/nacos/blob/master/distribution/conf/application.properties

image-20210125090606898

找到关于数据库的配置。

#####配置文件application.properties
 #
# Copyright 1999-2018 Alibaba Group Holding Ltd.
#
# 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.
#

#*************** Spring Boot Related Configurations ***************#
### Default web context path:
server.servlet.contextPath=/nacos
### Default web server port:
server.port=8848

#*************** Network Related Configurations ***************#
### If prefer hostname over ip for Nacos server addresses in cluster.conf:
# nacos.inetutils.prefer-hostname-over-ip=false

### Specify local server's IP:
# nacos.inetutils.ip-address=


#*************** Config Module Related Configurations ***************#
### If use MySQL as datasource:
spring.datasource.platform=mysql

### Count of DB:
db.num=1

### Connect URL of DB:
db.url.0=jdbc:mysql://192.168.40.128:3306/nacos-mysql?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
 db.user.0=root
 db.password.0=123456
### Connection pool configuration: hikariCP
db.pool.config.connectionTimeout=30000
db.pool.config.validationTimeout=10000
db.pool.config.maximumPoolSize=20
db.pool.config.minimumIdle=2

#*************** Naming Module Related Configurations ***************#
### Data dispatch task execution period in milliseconds:
# nacos.naming.distro.taskDispatchPeriod=200

### Data count of batch sync task:
# nacos.naming.distro.batchSyncKeyCount=1000

### Retry delay in milliseconds if sync task failed:
# nacos.naming.distro.syncRetryDelay=5000

### If enable data warmup. If set to false, the server would accept request without local data preparation:
# nacos.naming.data.warmup=true

### If enable the instance auto expiration, kind like of health check of instance:
# nacos.naming.expireInstance=true

nacos.naming.empty-service.auto-clean=true
nacos.naming.empty-service.clean.initial-delay-ms=50000
nacos.naming.empty-service.clean.period-time-ms=30000


#*************** CMDB Module Related Configurations ***************#
### The interval to dump external CMDB in seconds:
# nacos.cmdb.dumpTaskInterval=3600

### The interval of polling data change event in seconds:
# nacos.cmdb.eventTaskInterval=10

### The interval of loading labels in seconds:
# nacos.cmdb.labelTaskInterval=300

### If turn on data loading task:
# nacos.cmdb.loadDataAtStart=false


#*************** Metrics Related Configurations ***************#
### Metrics for prometheus
#management.endpoints.web.exposure.include=*

### Metrics for elastic search
management.metrics.export.elastic.enabled=false
#management.metrics.export.elastic.host=http://localhost:9200

### Metrics for influx
management.metrics.export.influx.enabled=false
#management.metrics.export.influx.db=springboot
#management.metrics.export.influx.uri=http://localhost:8086
#management.metrics.export.influx.auto-create-db=true
#management.metrics.export.influx.consistency=one
#management.metrics.export.influx.compressed=true


#*************** Access Log Related Configurations ***************#
### If turn on the access log:
server.tomcat.accesslog.enabled=true

### The access log pattern:
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i %{Request-Source}i

### The directory of access log:
server.tomcat.basedir=


#*************** Access Control Related Configurations ***************#
### If enable spring security, this option is deprecated in 1.2.0:
#spring.security.enabled=false

### The ignore urls of auth, is deprecated in 1.2.0:
nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**

### The auth system to use, currently only 'nacos' is supported:
nacos.core.auth.system.type=nacos

### If turn on auth system:
nacos.core.auth.enabled=false

### The token expiration in seconds:
nacos.core.auth.default.token.expire.seconds=18000

### The default token:
nacos.core.auth.default.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789

### Turn on/off caching of auth information. By turning on this switch, the update of auth information would have a 15 seconds delay.
nacos.core.auth.caching.enabled=true

### Since 1.4.1, Turn on/off white auth for user-agent: nacos-server, only for upgrade from old version.
nacos.core.auth.enable.userAgentAuthWhite=true

### Since 1.4.1, worked when nacos.core.auth.enabled=true and nacos.core.auth.enable.userAgentAuthWhite=false.
### The two properties is the white list for auth and used by identity the request from other server.
nacos.core.auth.server.identity.key=
nacos.core.auth.server.identity.value=

#*************** Istio Related Configurations ***************#
### If turn on the MCP server:
nacos.istio.mcp.server.enabled=false



###*************** Add from 1.3.0 ***************###


#*************** Core Related Configurations ***************#

### set the WorkerID manually
# nacos.core.snowflake.worker-id=

### Member-MetaData
# nacos.core.member.meta.site=
# nacos.core.member.meta.adweight=
# nacos.core.member.meta.weight=

### MemberLookup
### Addressing pattern category, If set, the priority is highest
# nacos.core.member.lookup.type=[file,address-server]
## Set the cluster list with a configuration file or command-line argument
# nacos.member.list=192.168.16.101:8847?raft_port=8807,192.168.16.101?raft_port=8808,192.168.16.101:8849?raft_port=8809
## for AddressServerMemberLookup
# Maximum number of retries to query the address server upon initialization
# nacos.core.address-server.retry=5
## Server domain name address of [address-server] mode
# address.server.domain=jmenv.tbsite.net
## Server port of [address-server] mode
# address.server.port=8080
## Request address of [address-server] mode
# address.server.url=/nacos/serverlist

#*************** JRaft Related Configurations ***************#

### Sets the Raft cluster election timeout, default value is 5 second
# nacos.core.protocol.raft.data.election_timeout_ms=5000
### Sets the amount of time the Raft snapshot will execute periodically, default is 30 minute
# nacos.core.protocol.raft.data.snapshot_interval_secs=30
### raft internal worker threads
# nacos.core.protocol.raft.data.core_thread_num=8
### Number of threads required for raft business request processing
# nacos.core.protocol.raft.data.cli_service_thread_num=4
### raft linear read strategy. Safe linear reads are used by default, that is, the Leader tenure is confirmed by heartbeat
# nacos.core.protocol.raft.data.read_index_type=ReadOnlySafe
### rpc request timeout, default 5 seconds
# nacos.core.protocol.raft.data.rpc_request_timeout_ms=5000
####操作步骤

[root@cbbgs ~]# docker ps
CONTAINER ID   IMAGE                COMMAND                  CREATED        STATUS                  PORTS                               NAMES
5d9a27b9e400   nacos/nacos-server   "bin/docker-startup.…"   13 hours ago   Up 13 hours             0.0.0.0:8848->8848/tcp              nacos
0d671962f6d2   redis                "docker-entrypoint.s…"   16 hours ago   Up 16 hours             0.0.0.0:6379->6379/tcp              distracted_khayyam
824db89b0893   openzipkin/zipkin    "start-zipkin"           16 hours ago   Up 16 hours (healthy)   9410/tcp, 0.0.0.0:9411->9411/tcp    zipkin
2f3d2671aa1a   mysql                "docker-entrypoint.s…"   16 hours ago   Up 16 hours             0.0.0.0:3306->3306/tcp, 33060/tcp   mysql8
[root@cbbgs ~]# docker exec -it ^C
[root@cbbgs ~]# docker exec -it 5d9a27b9e400 /bin/bash
[root@5d9a27b9e400 nacos]# cd conf  
[root@5d9a27b9e400 conf]# rm -rf application.properties  #我们删掉以前的配置
[root@5d9a27b9e400 conf]# ls
1.4.0-ipv6_support-update.sql  nacos-logback.xml  schema.sql
[root@5d9a27b9e400 conf]# vim application.properties 
[root@cbbgs ~]# docker restart 5d9a27b9e400   #重启docker

重新链接 cbbgs.cn:8848/nacos发现以前的数….

这样配置好了一台nacos,我们需要三台,我们紧接着用docke的nacos容器run其余两台不一样的容器

#我们已经安装好了8848,我们接下来安装8847,8849,用配置8848同样的方法安装其余两台nacos
docker run -e JVM_XMS=256m -e JVM_XMX=256m -d -p 8847:8848 nacos/nacos-server



docker run -e JVM_XMS=256m -e JVM_XMX=256m --env MODE=standalone -e NACOS_SERVERS="47.93.49.117:8847 47.93.49.11:8848 47.93.49.11:8849" --name nacos8849 -d -p 8849:8848 nacos/nacos-server

可以配合Nginx使用,学生机无法演示,只能运行一个nacos.采坑。

Sentinel实现熔断与限流

是什么

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

image-20210125120925770

文档:github.com/alibaba/Sen…

docker安装sentinel

[root@cbbgs ~]# docker pull anjia0532/sentinel-docker
Using default tag: latest
latest: Pulling from anjia0532/sentinel-docker
e7c96db7181b: Pull complete 
f910a506b6cb: Pull complete 
c2274a1a0e27: Pull complete 
3efee2ecd933: Pull complete 
7a4e2dd51bad: Pull complete 
Digest: sha256:247b2ddb26de434bb298a9de72713ed2b22047c219eebe37e427281b86449b65
Status: Downloaded newer image for anjia0532/sentinel-docker:latest
docker.io/anjia0532/sentinel-docker:latest
[root@cbbgs ~]# docker images
REPOSITORY                  TAG       IMAGE ID       CREATED         SIZE
mysql                       latest    c8562eaf9d81   6 days ago      546MB
nacos/nacos-server          latest    9c0b55a5ab2c   9 days ago      935MB
redis                       latest    621ceef7494a   11 days ago     104MB
openzipkin/zipkin           latest    9b4acc3eb019   4 weeks ago     150MB
anjia0532/sentinel-docker   latest    5df305072cec   13 months ago   127MB
[root@cbbgs ~]# docker run -d -p 8858:8080 anjia0532/sentinel-docker
bd9d6cff6bb1a52da72a16044d2d4db42673b67a4b40323c27cf8c34df43bff5
[root@cbbgs ~]# docker ps

访问界面:cbbgs.cn:8858/

百度网盘地址:

blog.csdn.net/qq_42449963…

部署二:

用Dockerfile和运行的jar包

FROM java:8
COPY *.jar /app.jar
CMD ["--server.port=8080"]

EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
[root@cbbgs sentinel]# docker build -t sentinel .
Sending build context to Docker daemon   21.2MB
Step 1/5 : FROM java:8
8: Pulling from library/java
5040bd298390: Pull complete 
fce5728aad85: Pull complete 
76610ec20bf5: Pull complete 
60170fec2151: Pull complete 
e98f73de8f0d: Pull complete 
11f7af24ed9c: Pull complete 
49e2d6393f32: Pull complete 
bb9cdec9c7f3: Pull complete 
Digest: sha256:c1ff613e8ba25833d2e1940da0940c3824f03f802c449f3d1815a66b7f8c0e9d
Status: Downloaded newer image for java:8
 ---> d23bdf5b1b1b
Step 2/5 : COPY *.jar /app.jar
 ---> e633c39ec4c0
Step 3/5 : CMD ["--server.port=8080"]
 ---> Running in 82fe8bb195dd
Removing intermediate container 82fe8bb195dd
 ---> 77603d1b4674
Step 4/5 : EXPOSE 8080
 ---> Running in 8b0de37000bf
Removing intermediate container 8b0de37000bf
 ---> ff60683a144a
Step 5/5 : ENTRYPOINT ["java","-jar","/app.jar"]
 ---> Running in a1bab61e9211
Removing intermediate container a1bab61e9211
 ---> cecefdcb8491
Successfully built cecefdcb8491
Successfully tagged sentinel:latest
[root@cbbgs sentinel]# docker images
REPOSITORY                  TAG       IMAGE ID       CREATED          SIZE
sentinel                    latest    cecefdcb8491   34 seconds ago   664MB
mysql                       latest    c8562eaf9d81   6 days ago       546MB
nacos/nacos-server          latest    9c0b55a5ab2c   9 days ago       935MB
redis                       latest    621ceef7494a   12 days ago      104MB
openzipkin/zipkin           latest    9b4acc3eb019   4 weeks ago      150MB
anjia0532/sentinel-docker   latest    5df305072cec   13 months ago    127MB
java                        8         d23bdf5b1b1b   4 years ago      643MB
[root@cbbgs sentinel]# docker stop  5df305072cec
Error response from daemon: No such container: 5df305072cec
[root@cbbgs sentinel]# docker stop 5df305072cec
Error response from daemon: No such container: 5df305072cec
[root@cbbgs sentinel]# docker ps
CONTAINER ID   IMAGE                       COMMAND                  CREATED        STATUS       PORTS                               NAMES
bd9d6cff6bb1   anjia0532/sentinel-docker   "/bin/sh -c 'java ${…"   5 hours ago    Up 4 hours   0.0.0.0:8858->8080/tcp              busy_swartz
6ee306084739   nacos/nacos-server          "bin/docker-startup.…"   5 hours ago    Up 4 hours   0.0.0.0:8848->8848/tcp              nacos
2f3d2671aa1a   mysql                       "docker-entrypoint.s…"   25 hours ago   Up 4 hours   0.0.0.0:3306->3306/tcp, 33060/tcp   mysql8
[root@cbbgs sentinel]# docker stop bd9d6cff6bb1
bd9d6cff6bb1
[root@cbbgs sentinel]# docker run -d -p 8858:8080 sentinel
e1705e812540dd2737a6d85a0af7514968002160eec52ef32d6a610eafb73b1d
[root@cbbgs sentinel]# docker ps

sentinel初始化监控

1、创建cloudalibaba-sentinel-service8401

2、导入依赖

 <dependencies>
        <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
            <groupId>com.atguigu.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>

3、配置文件

server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: cbbgs.cn:8848 #Nacos服务注册中心地址
    sentinel:
      transport:
        dashboard: cbbgs.cn:8858 #配置Sentinel dashboard地址
        #clientIp: localhost  #监控的主机,开发时是本机
        port: 8719
      eager: true


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

4、启动类

@EnableDiscoveryClient
@SpringBootApplication
public class MainApp8401
{
    public static void main(String[] args) {
        SpringApplication.run(MainApp8401.class, args);
    }
}

5、业务类

conrtoller

@RestController
@Slf4j
public class FlowLimitController
{
    @GetMapping("/testA")
    public String testA()
    {
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB()
    {
        log.info(Thread.currentThread().getName()+"\t"+"...testB");
        return "------testB";
    }



}

6、测试,先访问 http://localhost:8401/testA

因为远程端的sentinel还没有解决,先用本地的sentinel演示

image-20210125192055191

流控规则

流控模式
1、QPS直接失败:每秒请求数

image-20210125142718339

image-20210125192353774

解释

我们设置阈值为1,意思就是每一秒只能请求一次,如果一秒内的请求次数超过阈值就会失败!

2、线程数

是当线程数达到阈值的时候就限流。

image-20210125194041436

将线程数设为1,我们开两个浏览器模拟一下两个线程。在controller里新增一个方法,我们让这个方法延迟执行

 @GetMapping("/testD")
    public String testD()
    {
        try { TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("testD 测试RT");

        log.info("testD 异常比例");
        //int age = 10/0;
        return "------testD";
    }

image-20210125194811165

image-20210125171607130

3、关联
image-20210125194957415

A惹事,B跟着挂。比如支付接口要崩了,就限制下单的接口不演示。

4、预热

一个系统的访问量突然暴涨,可能会把系统击垮,需要慢慢的上涨,也就是预热。

image-20210125200142090
5、排队

一个一个来执行

image-20210125200307512

sentinel降级

image-20210125174700168

image-20210125200744825

sentinel熔断技术没有半开技术。

1、RT(平均响应时间)

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

我们用testD来测试

image-20210125201245107

一秒打进来10个线程(大于5个)调用D,我们希望200毫秒完成任务。

永远一秒钟打进来10个线程(大于5个了)调用testD,我们希望200毫秒处理完本次任务, 后续我停止jmeter,没有这么大的访问量了,断路器关闭(保险丝恢复),微服务恢复OK 如果超过200毫秒还没处理完,在未来1秒钟的时间窗口内,断路器打开(保险丝跳闸)微服务不可用,保险丝跳闸断电了

2、异常比例

异常比例( DEGRADE_GRADE_EXCEPTION_RATIO):当资源的每秒请求量>=5,并且每秒异常总数占通过量的比值超过阈值(DegradeRule中的count)之后,资源进入降级状态,即在接下的时间窗口( DegradeRule中的 timewindow,以s为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是[0.0,1.0],代表0%- 100%。4900 ms,若需要变更此上限可以通过启动配置项-Dcsp.sentinel.statistic.max.rt=x来配置。

我们新增一个在testD int age = 10/0;

image-20210125201951738

单独访问一次,必然来一次报错一次(int age = 10/0),调一次错一次; 异常比例(DEGRADE_GRADE_EXCEPTION_RATI0 )∶当资源的每秒请求量>=5,并且每秒异常总数占通过量的比值超过阈值(DegradeRule中的count)之后,资源进入降级状态,即在接下的时间窗口( DegradeRule中的timeWindow,以s为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是[0.0,1.0],代表0%- 100%。开启jmeter后,直接高并发发送请求,多次调用达到我们的配置条件了。断路器开启(保险丝跳闸),微服务不可用了,不再报错error而是服务降级了。

3、异常数

异常数(DEGRADF_GRADF_EXCEPTION_COUNT):当资源近1分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若timeWindow 小于60s,则结束熔断状态后仍可能 再进入熔断状态。

我们新增:

 @GetMapping("/testE")
    public String testE()
    {
        log.info("testE 测试异常数");
        int age = 10/0;
        return "------testE 测试异常数";
    }

访问错误的数据5次之后进行熔断

热点key

何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

  • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
  • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

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

兜底的方法:

  • 系统默认的方法
  • 客户自定义的方法 之前的case,限流出问题后,都是用sentinel系统默认的提示:Blocked by Sentinel (flow limiting)

那么我们能不能自定?类似Hystrix,某个方法出问题了,就找对应的兜底降级方法?

从HystrixCommond到@SentinelResource

Sentinel热点参数限流

image-20210125204524636

在controller新增

/*
* 对 p1,p2进行监控
* 
* */
    @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")//一个是唯一标识,blockHandler是处理的方法,兜底的方法
    public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
                             @RequestParam(value = "p2",required = false) String p2)
    {
        //int age = 10/0;
        return "------testHotKey";
    }

		//兜底的方法
    public String deal_testHotKey (String p1, String p2, BlockException exception)
    {
        return "------deal_testHotKey,o(╥﹏╥)o";  //sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
    }

image-20210125205901241

我猛点,请求次数超过了请求的阈值,发生了错误。直接执行兜底的错误

image-20210125205949386

参数例外项

image-20210125210649811

image-20210125210837600

image-20210125210929116

SentinelResource

增加一个方法:RateLimitController.java

@RestController
public class RateLimitController
{
    @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 服务不可用");
    }

    @GetMapping("/rateLimit/byUrl")
    @SentinelResource(value = "byUrl")
    public CommonResult byUrl()
    {
        return new CommonResult(200,"按url限流测试OK",new Payment(2020L,"serial002"));
    }


   /* @GetMapping("/rateLimit/customerBlockHandler")
    @SentinelResource(value = "customerBlockHandler",
            blockHandlerClass = CustomerBlockHandler.class,
            blockHandler = "handlerException2")
    public CommonResult customerBlockHandler()
    {
        return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003"));
    }*/
}

这样就算一秒钟请求达到了1,也不会被限。

按资源名称限制没有斜杠

image-20210125222503663

当我们不写兜底方案时,就会用系统自带的。

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

我自定义一个CustomerBlockHandler类

public class CustomerBlockHandler
{
    public static CommonResult handlerException(BlockException exception)
    {
        return new CommonResult(4444,"按客戶自定义,global handlerException----1");
    }
    public static CommonResult handlerException2(BlockException exception)
    {
        return new CommonResult(4444,"按客戶自定义,global handlerException----2");
    }
}

在RateLimitController添加方法

 @GetMapping("/rateLimit/customerBlockHandler")
    @SentinelResource(value = "customerBlockHandler",
            blockHandlerClass = CustomerBlockHandler.class,  //兜底的类在哪里
            blockHandler = "handlerException2")  //这个兜底类的那个方法
    public CommonResult customerBlockHandler()
    {
        return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003"));
    }

image-20210125223444843

image-20210125223328610

服务熔断

不再复制代码!!!

 @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler",
//fallback 是业务异常。  //blockHandler只负责sentinel控制台配置违规


@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",
            exceptionsToIgnore = {IllegalArgumentException.class})
    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);
    }

忽略属性:

image-20210126145908877

//nacos-payment-provider  服务提供者的服务名    PaymentFallbackService  兜底的类
@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)
public interface PaymentService
{
    @GetMapping(value = "/paymentSQL/{id}")//需要调用的方法
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}