springCloud入门(五)

我们上节实现了Feign远程调用,现在我们的系统已经是很完整了,所缺少的是系统的可用性:比如我们的用户服务,访问电影购票服务,电影购票系统突然宕机了,用户系统并不知道对方宕机了,还在持续的调用等待,当大量的用户都在访问时,用户系统很可能会CPU飙升,导致系统不可用,最终由于电影系统宕机的问题,也导致了用户系统跟着一块宕机了。这个时候就体现出来系统容错性的重要。
对于容错一般情况下有3种解决方案:
方案一:
超时机制:配置一下超时时间,例如1秒——每次请求在1秒内必须返回,否则到点就把线程阻断,释放资源!
方案二:
舱壁模式:一般来说,现代的轮船都会分很多舱室,舱室之间用钢板焊死,彼此隔离。这样即使有某个/某些船舱进水,也不会影响其他舱室,浮力够,船不会沉。这样每一个服务都是独立的线程池。
方案三:
断路器:现实世界的断路器大家肯定都很了解,每个人家里都会有断路器。断路器实时监控电路的情况,如果发现电路电流异常,就会跳闸,从而防止电路被烧毁。主要就是:实时监测应用,如果发现在一定时间内失败次数/失败率达到一定阈值,就“跳闸”,断路器打开——此时,请求直接返回,而不去调用原本调用的逻辑。
跳闸一段时间后(例如15秒),断路器会进入半开状态,这是一个瞬间态,此时允许一次请求调用该调的逻辑,如果成功,则断路器关闭,应用正常调用;如果调用依然不成功,断路器继续回到打开状态,过段时间再进入半开状态尝试——通过”跳闸“,应用可以保护自己,而且避免浪费资源;而通过半开的设计,可实现应用的“自我修复“。

springcloud 使用Hystrix来进行服务的容错

Hystrix是由Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。Hystrix主要通过以下几点实现延迟和容错。
包裹请求:使用HystrixCommand(或HystrixObservableCommand)包裹对依赖的调用逻辑,每个命令在独立线程中执行。这使用到了设计模式中的“命令模式”。
跳闸机制:当某服务的错误率超过一定阈值时,Hystrix可以自动或者手动跳闸,停止请求该服务一段时间。
资源隔离:Hystrix为每个依赖都维护了一个小型的线程池(或者信号量)。如果该线程池已满,发往该依赖的请求就被立即拒绝,而不是排队等候,从而加速失败判定。
监控:Hystrix可以近乎实时地监控运行指标和配置的变化,例如成功、失败、超时、以及被拒绝的请求等。
回退机制:当请求失败、超时、被拒绝,或当断路器打开时,执行回退逻辑。回退逻辑可由开发人员自行提供,例如返回一个缺省值。
自我修复:断路器打开一段时间后,会自动进入“半开”状态。
Eureka注册中心和服务提供者 代码不变
hystrix 代码如下:
pom引入

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>test-consumer-user-feign-hystrix</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>test-consumer-user-feign-hystrix</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- 引入Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--增加eurekaclient-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--增加feign 注解-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--增加 hystrix 注解-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
    </dependencies>

    <!-- 引入spring cloud的依赖,不能少,主要用来管理Spring Cloud生态各组件的版本 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.SR2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

启动类

package com.example.testconsumeruserfeignhystrix;

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

@SpringBootApplication
@EnableFeignClients
// hystrix 在启动类上添加 @EnableCircuitBreaker 注解
@EnableCircuitBreaker
public class TestConsumerUserFeignHystrixApplication {

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

}

实体类

package com.example.testconsumeruserfeignhystrix.pojo;

import lombok.*;

/**
 * 图书馆信息
 *
 */
@Getter
@Setter
@Builder
@NoArgsConstructor
// 为类提供一个全参的构造方法
@AllArgsConstructor
public class LibraryInfo {


    private Long id;

    /**
     * 图书馆名称
     */
    private String name;

    /**
     * 图书馆地址
     */
    private String address;

    /**
     * 总座位数
     */
    private Integer number;

    /**
     * 可预约数量
     */
    private Integer count;

}

feign

package com.example.testconsumeruserfeignhystrix.api;


import com.example.testconsumeruserfeignhystrix.pojo.LibraryInfo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name = "test-provider-library")
public interface LibraryFeignClient {

    /**
     *  注意 @PathVariable("id") 括号里面的ID不能省略
     * @param id
     * @return
     */
    @GetMapping("/library/{id}")
    LibraryInfo getFindById(@PathVariable("id") Long id);

}

controller

package com.example.testconsumeruserfeignhystrix.controller;


import com.example.testconsumeruserfeignhystrix.api.LibraryFeignClient;
import com.example.testconsumeruserfeignhystrix.pojo.LibraryInfo;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 用户控制类
 */
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {

    /**
     * 注入feign
     */
    @Autowired
    private LibraryFeignClient libraryFeignClient;

    @GetMapping("/library/{id}")
    // 指定降级方法
    @HystrixCommand(fallbackMethod ="findByIdFallback")
    public LibraryInfo findById(@PathVariable Long id){
        return libraryFeignClient.getFindById(id);
    }


    /**
     * 降级方法
     * @param id
     * @return
     */
    public LibraryInfo findByIdFallback(Long id,Throwable throwable){
        log.info("进入降级方法,原因是:{}",throwable);
        return new LibraryInfo(id,"默认图书馆","北京",1200,130);
    }


}

配置文件

server:
  port: 8005
spring:
  ## 指定注册到eureka server上的服务名称
  application:
    name: test-consumer-user-feign-hystrix
eureka:
  client:
    service-url:
      # 指定eureka server通信地址,注意/eureka/小尾巴不能少
      defaultZone: http://localhost:8761/eureka/
  instance:
    # 是否注册IP到eureka server,如不指定或设为false,那就会注册主机名到eureka server
    prefer-ip-address: true


依次启动 注册中心,和服务类 ,消费类
访问:http://localhost:8005/user/library/1
在这里插入图片描述
服务访问没有问题
然后把,服务类关掉,再访问
在这里插入图片描述
说明已经进入降级方法了

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值