第一部分:尚硅谷周阳老师SpringCloud学习整理笔记第一部分

经过5天的学习,目前学到了P92,刚刚结束了SpringCloud Stream,由于还有一些别的事情所以进度有点慢,笔记也整理得有点潦草。第一部分篇幅逐渐臃肿,故下面的笔记,分享于这篇博客。

笔记供自己日后复习,若有需要也供大家参考。若有不足,还请指正。

十三、Hystrix

Hystrix介绍

在微服务场景中,通常会有很多层的服务调用。如果一个底层服务出现问题,故障会被向上传播给用户。我们需要一种机制,当底层服务不可用时,可以阻断故障的传播。这就是断路器的作用。他是系统服务稳定性的最后一重保障。

在springcloud中断路器组件就是Hystrix。Hystrix也是Netflix套件的一部分。他的功能是,当对某个服务的调用在一定的时间内(默认10s),有超过一定次数(默认20次)并且失败率超过一定值(默认50%),该服务的断路器会打开。返回一个由开发者设定的fallback。

fallback可以是另一个由Hystrix保护的服务调用,也可以是固定的值。fallback也可以设计成链式调用,先执行某些逻辑,再返回fallback。

Hystrix的作用

  1. 对通过第三方客户端库访问的依赖项(通常是通过网络)的延迟和故障进行保护和控制。

  2. 在复杂的分布式系统中阻止级联故障。

  3. 快速失败,快速恢复。

  4. 回退,尽可能优雅地降级。

  5. 启用近实时监控、警报和操作控制。

官网:https://github.com/Netflix/Hystrix/wiki

参考博客:https://www.cnblogs.com/cjsblog/p/9391819.html

https://blog.csdn.net/tongtong_use/article/details/78611225

服务降级

三种情况:

  1. 访问超时

  2. 运行错误

  3. 宕机

实例代码:

/**
 * 访问超时
 *
 * @param id
 * @return
 */
 @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
    })
public String paymentInfo_TimeOut(Integer id) {
    int timeNumber = 5;
    try {
        TimeUnit.SECONDS.sleep(timeNumber);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return "线程池:" + Thread.currentThread().getName() + "paymentinfo_Timeout,id:" + id + "\t" + "耗时(秒)" + timeNumber;
}
​
private String paymentInfo_TimeOutHandler(Integer id) {
    return "线程池:" + Thread.currentThread().getName() + "paymentInfo_TimeOutHandler,id:" + id + "\t";
}

主启动类

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

问题:

1、每个方法有一个对应的处理方法,代码膨胀。

2、处理方法和主业务逻辑混合在一起

解决方案:

@DefaultProperties(defaultFallback="")

1、类上加上注解:

@RestController
@RequestMapping("/consumer")
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class OrderHystrixController {

2、默认全局处理方法

/**
 * 全局fallback方法
 *
 * @return
 */
private String payment_Global_FallbackMethod() {
    return "Global异常处理信息,请稍后再试。";
}

3、@HystrixCommand//不加属性代表使用默认的全局处理方法。

 

服务熔断

//====服务熔断
​
/**
 * 在10秒窗口期中10次请求有6次是请求失败的,断路器将起作用
 *
 * @param id
 * @return
 */
@HystrixCommand(
        fallbackMethod = "paymentCircuitBreaker_fallback", commandProperties = {
        @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),// 是否开启断路器
        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),// 请求次数
        @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),// 时间窗口期/时间范文
        @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60")// 失败率达到多少后跳闸
}
)
public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
    if (id < 0) {
        throw new RuntimeException("*****id不能是负数");
    }
    String serialNumber = IdUtil.simpleUUID();
    return Thread.currentThread().getName() + "\t" + "调用成功,流水号:" + serialNumber;
}
​
public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id) {
    return "id 不能负数,请稍后重试,o(╥﹏╥)o id:" + id;
}

Hystrix断路器使用时最常用的三个重要指标参数

在微服务中使用Hystrix 作为断路器时,通常涉及到以下三个重要的指标参数(这里是写在@HystrixProperties注解中,当然实际项目中可以全局配置在yml或properties中)

1、circuitBreaker.sleepWindowInMilliseconds

断路器的快照时间窗,也叫做窗口期。可以理解为一个触发断路器的周期时间值,默认为10秒(10000)

2、circuitBreaker.requestVolumeThreshold

断路器的窗口期内触发断路的请求阈值,默认为20。换句话说,假如某个窗口期内的请求总数都不到该配置值,那么断路器连发生的资格都没有。断路器在该窗口期内将不会被打开。

3、circuitBreaker.errorThresholdPercentage

断路器的窗口期内能够容忍的错误百分比阈值,默认为50(也就是说默认容忍50%的错误率)。打个比方,假如一个窗口期内,发生了100次服务请求,其中50次出现了错误。在这样的情况下,断路器将会被打开。在该窗口期结束之前,即使第51次请求没有发生异常,也将被执行fallback逻辑。


综上所述,在以上三个参数缺省的情况下,Hystrix断路器触发的默认策略为:

在10秒内,发生20次以上的请求时,假如错误率达到50%以上,则断路器将被打开。(当一个窗口期过去的时候,断路器将变成半开(HALF-OPEN)状态,如果这时候发生的请求正常,则关闭,否则又打开)

 

十四、GateWay

 

 

暂时省略

 

 

 

 

 

十五、Spring Config

简介:在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。Spring Cloud Config项目是就是这样一个解决分布式系统的配置管理方案。它包含了Client和Server两个部分,server提供配置文件的存储、以接口的形式将配置文件的内容提供出去,client通过接口获取数据、并依据此数据初始化自己的应用。

 

入门示例:

1、在github上新建一个仓库,如图所示

 

 

2、复制新建的git地址

 

3、在本地新建git仓库并clone

 

4、新建开发、生产、测试配置文件,并提交到github

参考下图:

命令:git add .

git commit

git push origin master

 

5、新建配置中心模块3344 cloud-config-center3344

添加依赖:

<dependencies>

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

yml文件配置

server:
  port: 3344
​
spring:
  application:
    name: cloud-config-center
  cloud:
    config:
      server:
        git:
          skipSslValidation: true # 跳过ssl认证
          uri: https://github.com/Jiaru0314/springcloud-config.git
          search-paths:
            - springcloud-config
      label: master
​
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka

主启动类

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

Spring Cloud Config 有它的一套访问规则,我们通过这套规则在浏览器上直接访问就可以。

/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties

{application} 就是应用名称,对应到配置文件上来,就是配置文件的名称部分,例如我上面创建的配置文件。

{profile} 就是配置文件的版本,我们的项目有开发版本、测试环境版本、生产环境版本,对应到配置文件上来就是以 application-{profile}.yml 加以区分,例如application-dev.yml、application-sit.yml、application-prod.yml。

{label} 表示 git 分支,默认是 master 分支,如果项目是以分支做区分也是可以的,那就可以通过不同的 label 来控制访问不同的配置文件了。

 

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

结果:

config:
  info: master branch,springcloud-config/config-dev.yml version=7

配置成功,但是这样还存在一个问题,就是当我们github上更新配置后,我们的服务要重新启动才能使用新的配置,否则配置无法生效。解决方案就是动态的修改配置。

使用标签:@RefreshScope

步骤:

  1. pom文件引入actuator依赖

  2. 修改yml,暴露监控端口

    #暴露监控端点
    management:
      endpoints:
        web:
          exposure:
            include: "*"
    
    
  3. @RefreshScope修饰控制类

  4. cmd下 执行

    curl -X POST "http://localhost:3355/actuator/refresh"
    
    

    3355模块重新获取配置信息

十六、Bus消息中心

1、首先配置RabbitMQ

下载erlang 地址:http://erlang.org/download/otp_win64_21.3.exe 傻瓜式安装即可

下载RabbitMQ 地址:https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.8.2/rabbitmq-server-3.8.2.exe 傻瓜式安装即可

进入rabbitmq安装目录下的sbin目录:输入

 rabbitmq-plugins enable rabbitmq_management

 

双击RabbitMQ service start

浏览器输入:localhost:15672 如果出现如下页面,则安装成功

 

输入账号和密码:guest、guest 可以看到RabbitMQ的主界面

2、参照3355模块新建3366模块

3344模块添加新依赖:

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

3344新添yml:

rabbitmq:
  host: localhost
  port: 5672
  username: guest
  password: guest


# 暴露bus刷新配置的端点
management:
  endpoints:
    web:
      exposure:
        include: "bus-refresh"

3355、3366yml新增:

rabbitmq: #rabbitmq相关配置,15672是web管理端口,5672是mq访问端口
  port: 5672
  host: localhost
  username: guest
  password: guest

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

1、修改github中版本号

2、cmd 刷新3344

curl -X POST "http://localhost:3344/actuator/bus-refresh"

结果:3355、3366 都已经改变,一次修改、广播通知、到处运行。

上面是全局通知,但如果我们想定点通知该如何做呢?

定点通知:只通知3355,不通知3366

实现方法:cmd 刷新3344

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

 

第十五章 SpringCloud Stream

问题:为什么要引入SpringCloud Stream

举例:对于我们Java程序员来说,可能有时要使用ActiveMQ,有时要使用RabbitMQ,甚至还有RocketMQ以及Kafka,这之间的切换似乎很麻烦,我们很难,也没有太多时间去精通每一门技术,那有没有一种新技术的诞生,让我们不再关注具体MQ的细节,自动的给我们在各种MQ内切换。

简介:Spring Cloud Stream 是一个用来为微服务应用构建消息驱动能力的框架。它可以基于 Spring Boot 来创建独立的、可用于生产的 Spring 应用程序。Spring Cloud Stream 为一些供应商的消息中间件产品提供了个性化的自动化配置实现,并引入了发布-订阅、消费组、分区这三个核心概念。通过使用 Spring Cloud Stream,可以有效简化开发人员对消息中间件的使用复杂度,让系统开发人员可以有更多的精力关注于核心业务逻辑的处理。但是目前 Spring Cloud Stream 只支持 RabbitMQ 和 Kafka 的自动化配置。

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

 

Binder Implementations 绑定器

通过绑定器Binder作为中间件,实现了应用程序与消息中间件细节的解耦。

Input对应消息生产者

Output对应消息消费者

 

入门案例

  1. 新建子模块

    cloud-stream-rabbitmq-provider8801 消息生产模块

  2. pom

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

    server:
      port: 8801
    
    spring:
      application:
        name: cloud-stream-provider
      cloud:
        stream:
          binders: # 在此处配置要绑定的rabbitMQ的服务信息
            defaultRabbit: # 表示定义的名称,用于binding的整合
              type: rabbit # 消息中间件类型
              environment: # 设置rabbitMQ的相关环境配置
                spring:
                  rabbitmq:
                    host: localhost
                    port: 5672
                    username: guest
                    password: guest
          bindings: # 服务的整合处理
            output: # 这个名字是一个通道的名称
              destination: studyExchange # 表示要使用的exchange名称定义
              content-type: application/json # 设置消息类型,本次为json,文本则设为text/plain
              binder: defaultRabbit # 设置要绑定的消息服务的具体设置
    
    eureka:
      client:
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka
      instance:
        lease-renewal-interval-in-seconds: 2 # 设置心跳的间隔时间,默认30
        lease-expiration-duration-in-seconds: 5 # 超过5秒间隔,默认90
        instance-id: send-8801.com # 主机名
        prefer-ip-address: true # 显示ip
    
    
  4. 业务类

    1. 主启动类

    2. IMessageProvider接口

    3. public interface IMessageProvider {
          String send();
      }
    4. MessageProviderImpl实现类

      public class MessageProviderImpl implements IMessageProvider {
      @Override
      public String send() {
          return null;
          }
      }
    5. 控制层

      @RestController
      public class SendMessageController {
      ​
          @Autowired
          private IMessageProvider messageProvider;
      ​
          @GetMapping("/sendMessage")
          public String send() {
              return messageProvider.send();
          }
      }
  5. 启动rabbitMQ,7001,8801 访问localhost:8801/sendMessage

    返回结果:62b3cb3e-ca40-410e-a601-dc72dfd004b5

  6. 新建子模块

    cloud-stream-rabbitmq-consumer8802 消息消费模块

  7. pom文件同8801

  8. yml文件

    server:
      port: 8802
    ​
    spring:
      application:
        name: cloud-stream-consumer
      cloud:
        stream:
          binders: # 在此处配置要绑定的rabbitMQ的服务信息
            defaultRabbit: # 表示定义的名称,用于binding的整合
              type: rabbit # 消息中间件类型
              environment: # 设置rabbitMQ的相关环境配置
                spring:
                  rabbitmq:
                    host: localhost
                    port: 5672
                    username: guest
                    password: guest
          bindings: # 服务的整合处理
            input: # 这个名字是一个通道的名称
              destination: studyExchange # 表示要使用的exchange名称定义
              content-type: application/json # 设置消息类型,本次为json,文本则设为text/plain
              binder: defaultRabbit # 设置要绑定的消息服务的具体设置
              # group: spectrumrpcA
    ​
    eureka:
      client:
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka
      instance:
        lease-renewal-interval-in-seconds: 2 # 设置心跳的间隔时间,默认30
        lease-expiration-duration-in-seconds: 5 # 超过5秒间隔,默认90
        instance-id: receive-8802.com #主机名
        prefer-ip-address: true # 显示ip
  9. 业务类

    1. 主启动类

    2. 服务类

      /**
       * @ClassName: ReceiveMessageListenerController
       * @description:
       * @author: XZQ
       * @create: 2020/3/10 15:34
       **/
      @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);
          }
       
      }
  10. 启动8802,8801发送消息,可以看到8802可以接受到消息,案例完成。

消息重复消费

不同的组存在重复消费,相同的组之间竞争消费。

  1. 参照8802建立8803模块

  2. 8802、8803yml加入组名 spectrumrpcA

    bindings: # 服务的整合处理
            input: # 这个名字是一个通道的名称
              destination: studyExchange # 表示要使用的exchange名称定义
              content-type: application/json # 设置消息类型
              binder: defaultRabbit # 设置要绑定的消息服务的具体设置
              # group: spectrumrpcA
    
    
  3. 分别启动8802、8803

  4. 8801发送消息、发现只有一个模块收到消息

第十六章 SpringCloud Sleuth

 

未完待更新

 

 

 

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐