首页 > 代码库 > 第十九章 springboot + hystrix(1)

第十九章 springboot + hystrix(1)

hystrix是微服务中用于做熔断、降级的工具。

作用:防止因为一个服务的调用失败、调用延时导致多个请求的阻塞以及多个请求的调用失败。

1、pom.xml(引入hystrix-core包)

1          <!-- hystrix -->   2         <dependency>3             <groupId>com.netflix.hystrix</groupId>4             <artifactId>hystrix-core</artifactId>5             <version>1.5.2</version>6         </dependency>

2、application.properties

1 #hystrix2 hystrix.timeoutInMillions = 3000

说明:设置hystrix属性,如上是"服务调用超时时间",其他属性设置见:https://github.com/Netflix/Hystrix/wiki/Configuration

3、HyStrixProperties

package com.xxx.firstboot.hystrix;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;import lombok.Getter;import lombok.Setter;@Getter @Setter@Component@ConfigurationProperties(prefix = "hystrix")public class HyStrixProperties {    private int timeoutInMillions;}

4、MyHyStrixCommand

package com.xxx.firstboot.hystrix;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import com.netflix.hystrix.HystrixCommand;import com.squareup.okhttp.OkHttpClient;import com.squareup.okhttp.Request;import com.squareup.okhttp.Response;public class MyHystrixCommand extends HystrixCommand<Response> {    private static final Logger LOGGER = LoggerFactory.getLogger(MyHystrixCommand.class);    private String url;    public MyHystrixCommand(Setter setter, String url) {        super(setter);        this.url = url;    }    @Override    protected Response run() throws Exception {        LOGGER.info("服务正被调用,当前线程:‘{}‘", Thread.currentThread().getName());        Request request = new Request.Builder().url(url).build();        return new OkHttpClient().newCall(request).execute();    }    @Override    public Response getFallback() {        LOGGER.error("服务调用失败,service:‘{}‘");        return null;    }}

说明:

  • 该类是最关键的一个类。
  • 继承HystrixCommand<T>
  • 添加构造器,注意:无法添加无参构造器,因此该类无法作为spring的bean来进行管理
  • 程序开始时执行run(),当执行发生错误或超时时,执行getFallback()

5、HyStrixUtil

技术分享
package com.xxx.firstboot.hystrix;import java.util.concurrent.ExecutionException;import java.util.concurrent.Future;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import com.netflix.hystrix.HystrixCommand.Setter;import com.netflix.hystrix.HystrixCommandGroupKey;import com.netflix.hystrix.HystrixCommandKey;import com.netflix.hystrix.HystrixCommandProperties;import com.squareup.okhttp.Response;@Componentpublic class HystrixUtil {    @Autowired    private HyStrixProperties hp;        public Response execute(String hotelServiceName,                             String hotelServiceMethodGetHotelInfo,                             String url) throws InterruptedException, ExecutionException {        Setter setter = Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(hotelServiceName));//被调用服务        setter.andCommandKey(HystrixCommandKey.Factory.asKey(hotelServiceMethodGetHotelInfo));//被调用服务的一个被调用方法        setter.andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(hp.getTimeoutInMillions()));        return new MyHystrixCommand(setter, url).execute();//同步执行//        Future<Response> future = new MyHystrixCommand(setter, url).queue();//异步执行//        return future.get();//需要时获取    }}
View Code

说明:

  • hystrix的执行方式
    • 同步执行:超时时间起作用
    • 异步执行:超时时间不起作用(1.4.0之前的版本,在调用get()的时候开始计时起作用)
  • hystrix的隔离级别
    • HystrixCommandGroupKey:这个的名称设置为一个被调用的服务,eg.hotelService,所有这个服务下的方法都用同一个线程池(前提是没有配置ThreadPoolKey)
    • HystrixCommandKey:这个名称通常是被调用服务的一个方法的名字(实际上就是被调用服务某一个controller中的一个对外方法),eg.getHotelInfo()
    • ThreadPoolKey:这个用的很少,除非一个被调用服务中的有些被调用方法快、有的被调用方法慢,这样的话,就需要分别使用一个ThreadPoolKey,为每一个方法单独分配线程池

6、application.properties

1 service.hotel.name = hotelService2 service.hotel.method.getHotelInfo = getHotelInfo 

说明:定义被调用服务的服务名和被调用方法名,当然服务名也可以使用被调用服务的controller的简单类名。

7、HystrixController

技术分享
package com.xxx.firstboot.web;import java.io.IOException;import java.util.concurrent.ExecutionException;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;import com.squareup.okhttp.Response;import com.xxx.firstboot.hystrix.HystrixUtil;@RestController@RequestMapping("/hystrix")public class HystrixController {    @Value("${service.hotel.url}")    private String HOTEL_URL;    @Value("${service.hotel.name}")    private String hotelServiceName;        @Value("${service.hotel.method.getHotelInfo}")    private String hotelServiceMethodGetHotelInfo;        @Autowired    private HystrixUtil hystrixUtil;    @RequestMapping(value = "/firstHystrix", method = RequestMethod.GET)    public String getHotelInfo(@RequestParam("id") int id, @RequestParam("name") String name) {        String url = String.format(HOTEL_URL, id, name);        Response response = null;        try {            response = hystrixUtil.execute(hotelServiceName, hotelServiceMethodGetHotelInfo, url);            if (response != null) {                return response.body().string();            }        } catch (IOException e) {            e.printStackTrace();        } catch (InterruptedException e) {            e.printStackTrace();        } catch (ExecutionException e) {            e.printStackTrace();        } finally {            if (response != null && response.body() != null) {                try {                    response.body().close();// 资源关闭                } catch (IOException e) {                    e.printStackTrace();                }            }        }        return "获取酒店信息失败";    }}
View Code

说明:

  • 使用@value做属性注入,假设我们是在consul上配置了application.properties内容,当修改了属性文件的内容后,该服务也必须重启,因为@value只读一次(没测过,同事说的)
  • 使用spring的Environment进行注入,当修改了属性文件的内容后,服务不需要重启,会每五分钟重新刷一次(没测过,同事说的)
  • 使用boot构建一个属性收集类,如上边的HyStrixProperties类,不知道是否需要重启(没测过)

有测过的朋友和我讲一下,我有时间也会测一下。

下边是被调用服务的代码:

8、HotelController

技术分享
@RestController@RequestMapping("/hotel")@Api("HotelController相关api")public class HotelController {    @ApiOperation("获取酒店Hotel信息:getHotelInfo")    @RequestMapping(value="/getHotelInfo",method=RequestMethod.GET)    public Hotel getHotelInfo(@RequestParam("id") int id, @RequestParam("name") String name) {//        try {//            TimeUnit.MILLISECONDS.sleep(2000);//用于测试超时//        } catch (InterruptedException e) {//            e.printStackTrace();//        }        return new Hotel(id, name);    }}
View Code

测试:启动被调用服务-->启动调用服务

 

参考:

http://blog.csdn.net/xiaoyu411502/article/details/50601687 官方的中文总结

https://stonetingxin.gitbooks.io/hystrix/content/ 基本上是官方的中文翻译

https://github.com/Netflix/Hystrix/wiki/Configuration hystrix配置介绍

http://blog.vicoder.com/hystrix-configuration/ 配置介绍

http://www.insaneprogramming.be/blog/2014/08/19/hystrix-spring-boot/ boot集成hystrix

第十九章 springboot + hystrix(1)