SpringCloud2组件之Hystrix详解

开发环境:

  • 开发工具:IntelliJ IDEA
  • Java版本:1.8
  • Spring Boot版本:2.1.6.RELEASE
  • Spring Cloud版本:Greenwich.SR1

工程简介:

  在SpringCloud2组件之Ribbon详解SpringCloud2组件之Feign详解中,我们通过Ribbon和Feign实现了微服务之间的调用。然而,在互联网中,可能存在某一个服务在某个时刻压力变大导致服务缓慢,甚至出现故障,导致服务不能响应。特别是在分布式系统中,如果一个服务不可用,而其他微服务还大量地调用这个不可用的微服务,也会导致其本身不可用,其自身不可用之后又可能继续蔓延到其他与之相关的服务上,这样就导致更多的微服务不可用,最终导致分布式服务瘫痪。为了防止这样的蔓延,Spring Cloud提供了断路器组件—Hystrix。
  在微服务系统之间大量调用可能导致服务消费者自身出现瘫痪的情况下,断路器就会将这些积压的请求做限制请求处理,来保证自身服可用,而不会蔓延到其他微服务系统上。通过这样的断路机制可以保持各个微服务之间持续可用。
  Hystrix处理限制请求的方式有很多,如降级、限流、缓存等。在这里,主要介绍下最为常用的降级服务。所谓降级服务,就是当请求其他微服务出现超时或者发生故障时,就会使用自身服务的其他方法进行响应。

1、创建Spring Boot工程

  通过Spring Cloud的Ribbon和Feign组件来实现client-product微服务调用client-user微服务。这里,我们不测试这两个组件的负载均衡功能(详见SpringCloud2组件之Ribbon详解SpringCloud2组件之Feign详解这两篇博客),只是单纯的实现微服务之间的调用,使用Hystrix实现超时进行降级服务。

(1)工程目录
(2)server-eureka组件选择
(2)client-user组件选择
(3)client-product组件选择

  组件选择完成后,需在pom.xml修改Hystrix的依赖,解决jar包冲突问题,如下:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <exclusions>
        <exclusion>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
        </exclusion>
    </exclusions>
</dependency>

2、配置server-eureka微服务

(1)server-eureka目录
(2)application.yml
server:
  #服务端口
  port: 9000
spring:
  application:
    #服务名称
    name: server
eureka:
  #配置环境
  environment: dev
  #配置数据中心
  datacenter: nanjing
  instance:
    #注册服务器名称
    hostname: localhost
  client:
    #是否注册到服务中心
    register-with-eureka: false
    #是否检索服务
    fetch-registry: false
    service-url:
      #客户端服务域
      defaultZone: http://localhost:9000/eureka/
(3)ServerEurekaApplication
package com.ming.eureka;

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

@SpringBootApplication
@EnableEurekaServer //开启Eureka服务端
public class ServerEurekaApplication {

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

3、配置client-user微服务

(1)client-user目录
(2)application.yml
server:
  #服务端口
  port: 7000
spring:
  #服务名称
  application:
    name: user
eureka:
  client:
    service-url:
      #服务注册地址
      defaultZone: http://localhost:9000/eureka/
(3)ClientUserApplication
package com.ming.user;

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

@SpringBootApplication
@EnableEurekaClient  //开启Eureka客户端
public class ClientUserApplication {

    public static void main(String[] args) {
        SpringApplication.run(ClientUserApplication.class, args);
    }
}
(4)UserController
package com.ming.user.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

   @RequestMapping("/timeout")
    public String timeout() {
		
		//调用服务时间
        Timestamp time = new Timestamp(System.currentTimeMillis());
        //生成一个2000之内的随机数
        long ms = (long) (2000 * Math.random());
        System.out.println("服务耗时:" + ms + " ms");
        try {
            Thread.sleep(ms);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("调用服务时间:" + time + ",服务耗时:" + ms + " ms");
        return "调用服务时间:" + time + " -> 未超时,服务正常";
    }
}

4、配置client-product微服务

(1)client-product目录
(2)application.yml
server:
  #服务端口
  port: 8000
spring:
  #服务名称
  application:
      name: product
eureka:
  client:
    service-url:
      #服务注册地址
      defaultZone: http://localhost:9000/eureka/
(3)ClientUserApplication
package com.ming.product;

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

@SpringBootApplication
@EnableEurekaClient //开启Eureka客户端
@EnableFeignClients //开启Feign客户端
@EnableCircuitBreaker //开启Hystrix断路器
public class ClientProductApplication {

    public static void main(String[] args) {
        SpringApplication.run(ClientProductApplication.class, args);
    }
}
(4)RestConfig
package com.ming.product.config;

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;

@Configuration
public class RestConfig {

    @Bean
    @LoadBalanced //提供客户端负载均衡
    public RestTemplate initRestTemplate() {
        return new RestTemplate();
    }
}
(5)FeignService
package com.ming.product.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;

@FeignClient("USER") //开启Feign客户端,USER是client-user微服务的serviceId
public interface FeignService {

    //对应要调用的client-user微服务控制层请求方法
    @RequestMapping("/timeout")
    String timeout();
}
(6)ProductController
package com.ming.product.controller;

import com.ming.product.service.FeignService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class ProductController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private FeignService feignService;

    @RequestMapping("/testHystrixByRibbon")
    //设置出现超时(默认1000ms)断路时,跳转的服务降级方法
    @HystrixCommand(fallbackMethod = "error")
    /*@HystrixCommand(fallbackMethod = "error", commandProperties = {
            //设置超时时间为2000ms
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000")
    })*/
    public String testHystrixByRibbon() {
 
   		//USER是client-user微服务的serviceId
        return restTemplate.getForObject("http://USER/timeout", String.class);
    }

    @RequestMapping("/testHystrixByFeign")
    //设置出现超时(默认1000ms)断路时,跳转的服务降级方法
    @HystrixCommand(fallbackMethod = "error")
    /*@HystrixCommand(fallbackMethod = "error", commandProperties = {
            //设置超时时间为2000ms
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000")
    })*/
    public String testHystrixByFeign() {
        return feignService.timeout();
    }

    //服务降级方法
    private String error() {
        return "超时,服务异常";
    }
}

5、测试工程

  依次点击ServerEurekaApplication、ClientProductApplication、ClientUserApplication,工程都启动成功后。在浏览器地址栏访问 http://localhost:9000,其结果如下:

在浏览器地址栏访问 http://localhost:8000/testHystrixByRibbon,其结果如下:

查看控制台,其结果如下:

在浏览器地址栏访问 http://localhost:8000/testHystrixByFeign,其结果如下:

查看控制台,其结果如下:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值