第一部分:尚硅谷周阳老师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
    @EnableCircuitBreakerpublic
    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

添加依赖:

    
<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>undefined</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@EnableConfigServerpublic 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 {@Overridepublic String send() {    return null;    }}
      
    5. 控制层

      @RestControllerpublic 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.  服务类
    
    ```html
    /** * @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);    } }
    ```
  1. 启动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

未完待更新