SpringCloud 2020笔记一

SpringCloud 2020笔记

代码链接:码云

一、Eureka梳理

  • 服务注册
  • 服务调用
  • 负载均衡

1、注册中心

① pom文件
<!-- 服务注册中心的服务端 eureka-server -->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
② yml文件
server:
  port: 7001


eureka:
  instance:
    hostname: eureka7001.com # eureka服务端的实例名称
  client:
    # false 表示不向注册中心注册自己
    register-with-eureka: false
    # false 表示自己就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      # 设置与Eureka Server 交互的地址查询服务和注册服务都需要依赖这个地址
      # http://${eureka.instance.hostname}:${server.port}
      defaultZone: http://eureka7002.com:7002/eureka/
③ 启动类

在这里插入图片描述

2、服务提供方

① pom
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
② yml文件
eureka:
  client:
    # 表示将自己注册到eureka注册中心
    register-with-eureka: true
    # 是否从Eureka Server中抓取已有的注册信息,默认为true,单节点无所谓,集群必须设置为true才能配合Ribbon负载均衡
    fetch-registry: true
    service-url:
#      defaultZone: http://localhost:7001/eureka/ 单机
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
  instance:
    instance-id: payment8001
    prefer-ip-address: true # 展示ip
③ 启动类

在这里插入图片描述

3、服务消费方

① pom
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
② yml
eureka:
  client:
    # true表示将自己注册到eureka注册中心
    register-with-eureka: false
    # 是否从Eureka Server中抓取已有的注册信息,默认为true,单节点无所谓,集群必须设置为true才能配合Ribbon负载均衡
    fetch-registry: true
    service-url:
      #      defaultZone: http://localhost:7001/eureka/ 单机
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
③ 启动类

在这里插入图片描述

④ 负载均衡

在这里插入图片描述

4、服务发现,在服务提供方添加

package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import com.atguigu.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;
 
@Slf4j
@RequestMapping("/paymentController")
@RestController
public class PaymentController {

    @Value(value = "${server.port}")
    private String serverPort;

    @Resource
    private DiscoveryClient discoveryClient;

    /**
     * 获取服务信息
     * @return
     */
    @GetMapping(value = "/discovery")
    public Object discovery(){

        // 获取eureka所有服务
        List<String> services = discoveryClient.getServices();
        for(String service : services){
            log.info("service==>" + service);
        }

        // 根据服务id获取对应的服务列表: spring.application.name
        List<ServiceInstance> serviceInstancesList = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        for(ServiceInstance instance : serviceInstancesList){
            log.info(instance.getUri() + "\t" + instance.getHost() + "\t" + instance.getPort());
        }
        return this.discoveryClient;
    }
}

5、Eureka自我保护

  • 默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。但是当网络分区发生故障(延时、卡顿、拥挤)时,微服务与Eureka Server之间无法正常通信,以上行为可能变得非常危险了—因为微服务本身其实是健康的,此时本不应该注销该微服务。Eureka通过“自我保护模式”来解决这个问题—当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个阶段就会进入自我保护模式。
  • 关闭自我保护(Eureka Server端)
    Eureka默认开启自我保护,可通过配置关闭
    eureka.server.enable-self-preservation = false
    
  • 客户端(服务提供者)设置心跳时间
# Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认30秒)
eureka.instance.lease-renewal-interval-in-seconds = 1
# Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认90秒),超时Eureka Server将剔除该服务
eureka.instance.lease-expiration-duration-in-seconds = 2

二、Zookeeper & Consul

1、Zookeeper

(1) zookeeper作为注册中心,在linux中安装

Zookeeper和Conusl作为注册中心集成到SpringBoot中相对Eureka较为简单,只需要将Zookeeper、Consul安装好,在代码中将服务提供方注册到zookeeper、consul即可

  • 安装环境
使用VMWare Workstation 虚拟机安装
系统:CentOS-6.8-x86_64-bin-DVD1.iso
JDK:jdk-8u301-linux-x64.tar.gz
Zookeeper:zookeeper-3.4.13.tar.gz
(2)服务提供方
① pom文件

添加zookeeper所需依赖

<!-- SpringBoot整合zookeeper客户端 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
    <!--先排除自带的zookeeper3.5.3-->
    <exclusions>
        <exclusion>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!--添加zookeeper3.4.13版本(与虚拟机中安装的zookeeper版本保持一致)-->
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.13</version>
</dependency>
② yml文件

服务名、zookeeper地址

# 服务别名,将provider注册到zookeeper
spring:
  application:
    name: cloud-provider-payment
  cloud:
    zookeeper:
      # zookeeper地址
      connect-string: 192.168.21.128:2181
③ 启动类

添加注解:@EnableDiscoveryClient

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * @Description
 * @Author xzkui
 * @Date 2021/9/2 18:30
 **/
@SpringBootApplication
@EnableDiscoveryClient  // 当使用consul或zookeeper作为注册中心时,该注解用于向注册中心注册服务
public class PaymentMain8004 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain8004.class, args);
    }
}
④ 最终效果

服务方启动后,会注册到zookeeper中,可在虚拟机中查看
使用 ls / 查看zookeeper所有节点,发现图中有一个services节点
在这里插入图片描述
查看services节点 ls /services,其中cloud-provider-payment即注册到zookeeper的微服务
在这里插入图片描述

(3) 服务消费方
① pom文件(与服务提供方添加的依赖一致)

添加zookeeper所需依赖

<!-- SpringBoot整合zookeeper客户端 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
    <!--先排除自带的zookeeper3.5.3-->
    <exclusions>
        <exclusion>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!--添加zookeeper3.4.13版本(与虚拟机中安装的zookeeper版本保持一致)-->
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.13</version>
</dependency>
② yml文件

添加zookeeper配置

# 服务别名,将provider注册到zookeeper
spring:
  application:
    name: cloud-consumer-order
  cloud:
    zookeeper:
      connect-string: 192.168.21.128:2181
③ 启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * @Description
 * @Author xzkui
 * @Date 2021/9/2 19:15
 **/
@SpringBootApplication
@EnableDiscoveryClient
public class OrderMainZk80 {
    public static void main(String[] args) {
        SpringApplication.run(OrderMainZk80.class, args);
    }
}
④ 最终效果

查看步骤参考服务提供方

2、Consul

(1) consul作为注册中心,在windows下安装

consul下载链接

  • 下载下来的是一个压缩包,解压后只有一个.exe文件

  • 解压后在.exe文件所在目录进入cmd,输入:consul agent -dev 启动consul,启动成功打印如下:
    在这里插入图片描述

  • 在浏览器访问consul界面查看服务
    默认地址:localhost:8500
    在这里插入图片描述

(2)服务提供方
① pom文件

添加consul所需依赖

<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-consul-discovery -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
② yml文件
spring:
  application:
    name: consul-provider-payment
    # consul 服务注册地址
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
③ 启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * @Description
 * @Author xzkui
 * @Date 2021/9/2 19:48
 **/
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMainConsul8006 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMainConsul8006.class, args);
    }
}
④ 最终效果

启动服务后可在consul管理界面查看
在这里插入图片描述

(3)服务消费方
① pom文件
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-consul-discovery -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
② yml文件
spring:
  application:
    name: consul-consumer-order
  # consul 服务注册地址
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
③ 启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * @Description
 * @Author xzkui
 * @Date 2021/9/2 19:59
 **/
@SpringBootApplication
@EnableDiscoveryClient
public class ConsulConsumerMain80 {
    public static void main(String[] args) {
        SpringApplication.run(ConsulConsumerMain80.class, args);
    }
}
④ 最终效果

在consul管理界面查看
在这里插入图片描述

3、注册一个RestTemplate,用于服务调用、负载均衡

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * @Description
 * @Author xzkui
 * @Date 2021/9/2 20:02
 **/
@Configuration
public class ApplicationContextConfig {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

三、OpenFeign

Open Feign作为服务消费方调用服务提供方相关接口(此处使用eureka作为服务注册中心)
在这里插入图片描述在这里插入图片描述

1、服务消费方pom文件添加依赖

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

2、服务消费方yml配置文件添加配置

server:
  port: 80

spring:
  application:
    name: cloud-feign-order-service

eureka:
  client:
    # true表示将自己注册到eureka注册中心
    register-with-eureka: false
    service-url:
      #      defaultZone: http://localhost:7001/eureka/ 单机
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
  #指的是建立连接所用的时间,适用于网络状况正常的情况下, 两端连接所用的时间
  ReadTimeout: 5000
  #指的是建立连接后从服务器读取到可用资源所用的时间
  ConnectTimeout: 5000

logging:
  level:
    # feign日志以 debug 级别监控 com.atguigu.springcloud.service.FeignOrderService 接口
    com.atguigu.springcloud.service.FeignOrderService: debug

3、服务消费方启动类

package com.atguigu.springcloud;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;


@SpringBootApplication
@EnableFeignClients // 启动feign
public class FeignOrderMain80 {
    public static void main(String[] args) {
        SpringApplication.run(FeignOrderMain80.class, args);
    }
}

4、添加feign接口

import com.atguigu.springcloud.config.FeignFallBack;
import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * @Description
 * @Date 2021/9/4 19:08
 * @Author xzkui
 **/
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE", fallback = FeignFallBack.class)
@RequestMapping("/paymentController")
public interface FeignOrderService {

    /**
     * 添加一条数据
     * @param payment
     * @return
     */
    @PostMapping(value = "/create")
    int create(Payment payment);

    /**
     * 根据id查找数据
     * @param id
     * @return
     */
    @GetMapping(value = "/getPaymentById")
    CommonResult getPaymentById(@RequestParam("id") Long id);
}

5、controller代码

import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.service.FeignOrderService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @Description
 * @Date 2021/9/4 19:12
 * @Author xzkui
 **/
@RestController
@RequestMapping("/feignOrderController")
public class FeignOrderController {

    @Resource
    private FeignOrderService feignOrderService;

    @GetMapping(value = "/getPaymentById")
    public CommonResult getPaymentById(@RequestParam("id") Long id){
        return feignOrderService.getPaymentById(id);
    }
}

6、配置open feign日志

在这里插入图片描述

(1)全局

package com.atguigu.springcloud.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Description
 * @Date 2021/9/4 19:56
 * @Author xzkui
 **/
@Configuration
public class FeignConfig {

    @Bean
    Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }
}
(2)针对某个类,在配置文件中配置
logging:
  level:
    # feign日志以 debug 级别监控 com.atguigu.springcloud.service.FeignOrderService 接口
    com.atguigu.springcloud.service.FeignOrderService: debug
7、open feign 超时机制

OpenFeign默认等待时间是1秒,超过1秒,直接报错

(1)设置超时时间,修改配置文件:

因为OpenFeign的底层是ribbon进行负载均衡,所以它的超时时间是由ribbon控制

#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
  #指的是建立连接所用的时间,适用于网络状况正常的情况下, 两端连接所用的时间
  ReadTimeout: 5000
  #指的是建立连接后从服务器读取到可用资源所用的时间
  ConnectTimeout: 5000

四、Hystrix

  • 服务降级:某个服务被调用时出现异常或者超时,返回一个友好结果提示,避免用户一直等待;
  • 服务熔断:
    • 当某个服务出现异常或者超时次数达到了设定的断路要求时,将拒绝所有请求该服务的请求,断路器打开,并进入一个休眠期,期间使用服务降级返回一个友好结果提示;
    • 休眠期到期后,断路器进入半开状态,会释放少量请求到原来的服务,如果请求正常,断路器将会关闭,如果请求再次出现异常,则断路器再次打开,并进入休眠期;
  • 服务限流

1、服务降级

  • 服务降级一般都在服务消费方进行配置
    • 消费方调用的服务超时,进行服务降级
    • 消费方调用的服务在调用过程中宕机,进行服务降级
    • 消费方调用的服务返回数据正常,消费方出现故障或者超时,进行服务降级
  • eureka作为注册中心、openfeign进行服务调用、hystrix服务降级
(1)pom文件
<!--新增hystrix-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
(2)yml文件
eureka:
  client:
    # true表示将自己注册到eureka注册中心
    register-with-eureka: false
    service-url:
      #      defaultZone: http://localhost:7001/eureka/ 单机
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

feign:
  hystrix:
    enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。
(3)启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @Description
 * @Date 2021/9/5 19:35
 * @Author xzkui
 **/
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableHystrix
public class ConsumerFeignHystrixMain80 {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerFeignHystrixMain80.class, args);
    }
}
(4)openfeign服务调用
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * @Description
 * @Date 2021/9/4 19:08
 * @Author xzkui
 **/
@Component
@FeignClient(value = "CLOUD-PAYMENT-HYSTRIX-SERVICE")
@RequestMapping("/hystrixProviderController")
public interface FeignOrderService {

    /**
     * hystrix正确调用接口
     * @param id
     * @return
     */
    @GetMapping("/paymentOkInfo")
    String paymentOkInfo(@RequestParam("id") Integer id);

    /**
     * hystrix超时接口
     * @param id
     * @return
     */
    @GetMapping("/paymentTimeOutInfo")
    String paymentTimeOutInfo(@RequestParam("id") Integer id);

    /**
     * 服务熔断
     * @param id
     * @return
     */
    @GetMapping("/paymentCircuitBreaker")
    String paymentCircuitBreaker(@RequestParam("id") Integer id);
}
(5)controller
import com.atguigu.springcloud.service.FeignOrderService;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @Description
 * @Date 2021/9/5 19:37
 * @Author xzkui
 **/
@RestController
@Slf4j
@RequestMapping("/feignHystrixController")
@DefaultProperties(defaultFallback = "globalFallbackMethod")
public class OrderFeignHystrixController {

    @Value("${server.port}")
    private String serverPort;

    @Resource
    private FeignOrderService feignOrderService;

    @GetMapping("/paymentOkInfo")
    @HystrixCommand(fallbackMethod = "fallBackMethod", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
    })
    public String paymentOkInfo(@RequestParam("id") Integer id){
        String result = feignOrderService.paymentOkInfo(id);
        return result;
    }

    @GetMapping("/paymentTimeOutInfo")
    @HystrixCommand(commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
    })
    public String paymentTimeOutInfo(@RequestParam("id") Integer id){
        int a = id / 0;
        String result = feignOrderService.paymentTimeOutInfo(id);
        return result;
    }

    public String fallBackMethod(@RequestParam("id") Integer id){
        return id + "fallback at " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    }

    public String globalFallbackMethod(){
        return "this is global fallback method !";
    }

    /**
     * 服务熔断
     * @param id
     * @return
     */
    @GetMapping("/paymentCircuitBreaker")
    @HystrixCommand(commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
    })
    public String paymentCircuitBreaker(@RequestParam("id") Integer id){
        return feignOrderService.paymentCircuitBreaker(id);
    }

}
(6)服务降级注解
① @HystrixCommand
  • 作用于用户所调用的方法
  • fallbackMethod 指定在服务降级时调用的方法;
  • commandProperties 可用于配置服务降级触发条件等配置;
② @DefaultProperties
  • 作用于类,用于指定全局默认的服务降级出发后执行的fallbackmethod;
  • 未添加@HystrixCommand注解的接口不会调用全局指定的fallbackmethod
③ 区别
  • 如果使用fallbackmethod指定了方法则不会执行全局默认的fallbackmethod
  • 使用了@HystrixCommand注解但未指定fallbackmethod则会执行全局默认的fallbackmethod

2、服务熔断

  • 服务熔断一般作用与服务提供方,是应对雪崩效应的一种微服务链路保护机制
    • 类比与保险丝,当失败的调用达到一定的阈值时,会触发熔断机制 ;
    • 熔断机制触发后,进入休眠期,拒绝所有访问请求,并使用服务降级返回提示;
    • 休眠期过后,释放少量请求(半开状态),如果请求正常,关闭熔断机制,反之重新触发熔断机制;
  • eureka作为服务注册、hystrix服务熔断
(1)pom文件
<!--新增hystrix-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
(2)yml文件
spring:
  application:
    name: cloud-payment-hystrix-service   # 微服务名称

eureka:
  client:
    # 表示将自己注册到eureka注册中心
    register-with-eureka: true
    # 是否从Eureka Server中抓取已有的注册信息,默认为true,单节点无所谓,集群必须设置为true才能配合Ribbon负载均衡
    fetch-registry: true
    service-url:
      #      defaultZone: http://localhost:7001/eureka/ 单机
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
(3)启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * @Description
 * @Date 2021/9/5 17:40
 * @Author xzkui
 **/
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
// 开启断路器功能
@EnableCircuitBreaker
public class HystrixPaymentMain8001 {
    public static void main(String[] args) {
        SpringApplication.run(HystrixPaymentMain8001.class, args);
    }
}
(4)服务熔断使用
① controller
package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.service.HystrixPaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @Description
 * @Date 2021/9/5 17:45
 * @Author xzkui
 **/
@RestController
@Slf4j
@RequestMapping("/hystrixProviderController")
public class HystrixProviderController {

    @Resource
    private HystrixPaymentService hystrixPaymentService;

    @Value("${server.port}")
    private String serverPort;

    @GetMapping("/paymentOkInfo")
    public String paymentOkInfo(@RequestParam("id") Integer id){
        String result = hystrixPaymentService.paymentOk(id);
        log.info("result ==> " + result);
        return result;
    }

    @GetMapping("/paymentTimeOutInfo")
    public String paymentTimeOutInfo(@RequestParam("id") Integer id){
        String result = hystrixPaymentService.paymentTimeOut(id);
        log.info("result ==> " + result);
        return result;
    }

    @GetMapping("/paymentCircuitBreaker")
    public String paymentCircuitBreaker(@RequestParam("id") Integer id){
        return hystrixPaymentService.paymentCircuitBreaker(id);
    }

}

② Service
/**
     * 服务熔断:此处的配置是,10请求中,超出60%的请求出现问题,则会熔断,熔断后即使请求正常也不会正常返回
     * 开启 -> 半开 -> 关闭
     * @return
     */
    @HystrixCommand(fallbackMethod = "paymentCircuitBreakerFallback", 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") // 失败率达到多少后跳闸60%
    })
    @Override
    public String paymentCircuitBreaker(Integer id){
        if(id > 0){
            throw new RuntimeException("test");
        }
        String serialNumber = IdUtil.simpleUUID();
        return Thread.currentThread().getName() + "\t" + "调用成功,流水号: " + serialNumber;
    }

    public String paymentCircuitBreakerFallback(Integer id){
        System.out.println("该服务已熔断,开启服务降级!!");
        return "该服务已熔断,开启服务降级!!";
    }
(5)服务熔断注解
  • 注解使用与服务降级基本一致,不同的是需要通过配置属性打开熔断器,并配置触发条件
  • 如何查看属性:通过查看HystrixCommandProperties,是一个抽象类,记录了需要配置的属性
(6)熔断类型
  • 熔断打开:请求不在进行调用当前服务,内部设置时钟一般为MTTR(平均故障处理时间),当打开时长达到所设时间,则进入半熔断状态;
  • 熔断关闭:熔断关闭后,服务正常调用;
  • 熔断半开:部分请求根据规则调用当前服务,如果请求成功且符合规则,则认为服务恢复正常,关闭熔断;
(7)整体流程
1、请求进来,首先查询缓存,如果缓存有,直接返回
如果缓存没有,--->2
2、查看断路器是否开启,如果开启的,Hystrix直接将请求转发到降级返回,然后返回;如果断路器是关闭的,判断线程池等资源是否已经满了,如果已经满了,也会走降级方法;如果资源没有满,判断我们使用的什么类型的Hystrix,决定调用构造方法还是run方法,然后处理请求;
3、然后Hystrix将本次请求的结果信息汇报给断路器,因为断路器此时可能是开启的 (因为断路器开启也是可以接收请求的);断路器收到信息,判断是否符合开启或关闭断路器的条件,
4、如果本次请求处理失败,又会进入降级方法; 如果处理成功,判断处理是否超时,如果超时了,也进入降级方法,最后,没有超时,则本次请求处理成功,将结果返回给controller

SpringCloud 2020笔记二

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值