Spring Cloud之Hystrix服务降级

Hystrix引入

在微服务场景中,由于大部分微服务采用同步接口调用,而且多个领域相关的微服务会部署在同一个进程中,很容易发生“雪崩效应”,即某个微服务提供者故障,导致调用该微服务的消费者、或者与故障微服务合设在同一个进程中的其它微服务发生级联故障,最终导致系统崩溃,在spring cloud中提供了一种机制,断路器即Hystrix

Hystrix简介

Hystrix也是Netflix套件的一部分。它的作用是当对某个服务的调用在一定的时间内(默认10s,由metrics.rollingStats.timeInMilliseconds配置),有超过一定次数(默认20次,由circuitBreaker.requestVolumeThreshold参数配置)并且失败率超过一定值(默认50%,由circuitBreaker.errorThresholdPercentage配置),该服务的断路器会打开。返回一个由开发者设定的fallback,在fallback中返回给用户一个指定的页面,不至于出现error页面,影响用户体验

Hystrix使用前

创建maven项目
在这里插入图片描述
在maven新项目中添加几个module,commons是公共依赖的包,consumer是消费者,provider是生产者,eurekaconsumer是服务注册中心(名字随便起的),先不管hystrix,我们对commons进行install安装到本地仓库中,便于在consumer、provider可以导入依赖,对provider进行install,我们先启动eurekaconsumer服务
在这里插入图片描述
在eurekaconsumer就只配置了application.properties

eureka.client.fetch-registry=false
eureka.client.register-with-eureka=false
spring.application.name=eureka
server.port=1111

eureka.client.service-url.defaultZone=http://localhost:1111/eureka

启动类中添加了@EnableEurekaServer注解,表示开启eureka注册服务

package com.zhouym.eurekaconsumer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaconsumerApplication {

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

}

接下来启动两个provider实例,在控制台中

E:\IDEA_WorkSpace\cloud\provider\target>java -jar provider-0.0.1-SNAPSHOT.jar --server.port=3001
E:\IDEA_WorkSpace\cloud\provider\target>java -jar provider-0.0.1-SNAPSHOT.jar --server.port=3002

此时访问eureka的后台服务http://localhost:1111/,就会发现注册的两个provider
provider中的接口

package com.zhouym.provider;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 〈〉
 *
 * @author zhouym
 * @create 2019/9/2
 * @since 1.0.0
 */
@RestController
public class ProviderController {

    @Value("${server.port}")
    Integer port;

    @GetMapping("/provider")
    public String provide(){
        return "provider:"+port;
    }
}

application.properties配置文件

spring.application.name=provider
server.port=3000
eureka.instance.hostname=localhost
eureka.client.service-url.defaultZone=http://localhost:1111/eureka

接下来我们开启consumer

package com.zhouym.consumer;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/**
 * 〈〉
 *
 * @author zhouym
 * @create 2019/8/31
 * @since 1.0.0
 */
@RestController
public class ConsumerController {

    @Autowired
    RestTemplate restTemplate;
    @GetMapping("/consumer4")
    public String consumer4(){
        return restTemplate.getForObject("http://provider/provider",String.class);
    }


}

application.properties配置文件

spring.application.name=consumer
server.port=4000
eureka.client.service-url.defaultZone=http://localhost:1111/eureka

启动运行类
访问http://localhost:4000/consumer4,看看页面效果
在这里插入图片描述
在这里插入图片描述
因为启动了两个provider实例,所以刷新后,返回的数据是在3001和3002切换,当我们关闭其中一个provider实例,再次刷新看看页面效果
在这里插入图片描述
再次刷新看看
在这里插入图片描述
出现了如上图的error页面,这严重会影响用户体验,在spring cloud中提供了一个hystrix组件,就是用来解决这个的

Hystrix引入后

创建一个Hystrix项目,引入web、eureka discovery client、hystrix依赖
在这里插入图片描述
在application.properties文件中配置如下信息

spring.application.name=hystrix
server.port=5000
eureka.client.service-url.defaultZone=http://localhost:1111/eureka

service层

package com.zhouym.hystrix;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

/**
 * 〈〉
 *
 * @author zhouym
 * @create 2019/9/2
 * @since 1.0.0
 */
@Service
public class HystrixService {


    @Autowired
    RestTemplate restTemplate;

    @HystrixCommand(fallbackMethod = "error")
    public String test(){
        return restTemplate.getForObject("http://provider/provider",String.class);

    }
    public String error(){
        return "error";
    }
}

controller层

package com.zhouym.hystrix;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 〈〉
 *
 * @author zhouym
 * @create 2019/9/2
 * @since 1.0.0
 */
@RestController
public class HystrixController {

    @Autowired
    HystrixService hystrixService;

    @GetMapping("/hello")
    public String hello(){
        return hystrixService.test();
    }

}

在启动类中添加@EnableCircuitBreaker,以及RestTemplate

package com.zhouym.hystrix;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableCircuitBreaker
public class HystrixApplication {

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

    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

}

启动hystrix运行类,访问页面http://localhost:5000/hello
在这里插入图片描述
在这里插入图片描述
此时我们关闭一个provider实例
在这里插入图片描述
刷新之后就访问到了我们指定的error页面了
在这里插入图片描述
再次刷新,断路器就会认为provider有一个服务已经掉线了,此后不会再去访问这个掉线的服务
多次刷新,访问到的仍是这个3001的页面
在这里插入图片描述

发布了207 篇原创文章 · 获赞 87 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/zhouym_/article/details/100228383