关闭

使用Springboot和Hystrix构建API Gateway

标签: netflixapigatewayspringboothystrix
8116人阅读 评论(0) 收藏 举报
分类:

使用Hystrix构建API Gateway

随着MicroService架构越来越深入人心,如何构建一个高性能,错误容忍的API Gateway成了一个很多人都遇到的问题。Netflix开源了Hystrix来帮助我们实现API Gateway。

这里提供一个Springboot+Hystrix的例子:
https://github.com/qmhu/SpringHystrixSample

关于微服务可以看一下这个系列的文章,讲的非常好:
http://dockone.io/article/394


Hystrix

提供了以下重要功能:
- 同步/异步操作封装
- Fallback
- ThreadPool的隔离
- 请求Cache
- 请求合并

目录

一个例子

在pom.xml里引入springboot和hystrix的依赖

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-spring-boot</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.5.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.netflix.hystrix</groupId>
            <artifactId>hystrix-core</artifactId>
            <version>1.4.23</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.1</version>
        </dependency>
        <dependency>
            <groupId>com.netflix.hystrix</groupId>
            <artifactId>hystrix-metrics-event-stream</artifactId>
            <version>1.4.23</version>
        </dependency>
    </dependencies>


    <properties>
        <java.version>1.8</java.version>
    </properties>


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

</project>

启动springboot

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(Application.class, args);
    }

}

定义CommandHttpCall

  • 通过继承HystrixCommand定义了一个Command。这里封装了一个HttpCall的Command
  • 通过Setter配置了各种Group来做请求配置的隔离
  • 配置了熔断器(CircuitBreaker),如果请求达到了熔断的条件会自动触发熔断机制
  • 配置了fallback方法,如果熔断机制触发会返回fallback方法的结果
public class CommandHttpCall extends HystrixCommand<String>{

    private final String url;

    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(CommandHttpCall.class);

    public CommandHttpCall(String url) {
        super(
                Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("hystrix.command.http"))
                        .andCommandKey(HystrixCommandKey.Factory.asKey("hystrix.command.http"))
                        .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("hystrix.command.http"))
                        .andCommandPropertiesDefaults(
                                HystrixCommandProperties.Setter()
                                        .withCircuitBreakerRequestVolumeThreshold(2)
                                        .withCircuitBreakerSleepWindowInMilliseconds(60 * 1000).
                                        withFallbackEnabled(true).
                                        withExecutionIsolationThreadInterruptOnTimeout(true).withExecutionTimeoutInMilliseconds(5000)));
        this.url = url;
    }

    @Override
    protected String run() throws Exception {
        logger.info("Execution of Command: url={}", url);
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(url);
        try(CloseableHttpResponse response = httpclient.execute(httpGet)) {
            HttpEntity entity = (HttpEntity) response.getEntity();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
            String total = "";
            String line = bufferedReader.readLine();
            while (line != null){
                total += line;
                line = bufferedReader.readLine();
            }
            return total;
        }
    }

    @Override
    protected String getFallback() {
        return "failbackFor" + url;
    }



}

Future的方式进行异步调用

Hystrix提供了java concurrency包标准的Future接口来获取一个异步调用的结果,
这里首先请求了一个product service,等product service结果返回后再同时调用order service和cart service

@RequestMapping("/future")
public String getFuture() throws InterruptedException {
    Future<String> productSyncCall = new CommandHttpCall("http://localhost:8091/product").queue();

    try {
        String product = productSyncCall.get();
        System.out.println("sync get product" + product);
        Future<String> orderSyncCall = new CommandHttpCall("http://localhost:8091/order").queue();
        Future<String> cartSyncCall = new CommandHttpCall("http://localhost:8091/cart").queue();
        System.out.println("sync get order" + orderSyncCall.get());
        System.out.println("sync get cart" + cartSyncCall.get());
    } catch (ExecutionException e) {
        e.printStackTrace();
    }

    return new CommandHelloWorld("this is content for future").execute();
}

ObServe的方式进行异步调用

Hystrix还提供了Rxjava接口Observable的调用方式,这里首先同时调用了product和order service,等结果都complete后再调用cart service

@RequestMapping("/observe")
public String getObserve() throws InterruptedException {
    Observable<String> productCall = new CommandHttpCall("http://localhost:8091/product").observe();
    Observable<String> orderCall = new CommandHttpCall("http://localhost:8091/order").observe();
    Observable<String> cartCall = new CommandHttpCall("http://localhost:8091/cart").observe();

    List<Observable<String>> result = new ArrayList<>();
    result.add(productCall);
    result.add(orderCall);
    Observable.merge(result).subscribe(new Observer<String>() {

        @Override
        public void onCompleted() {
            System.out.println("product&order call complete");
            cartCall.subscribe(new Observer<String>() {
                @Override
                public void onCompleted() {
                    System.out.println("cart call complete");
                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onNext(String v) {
                    System.out.println("onNext: " + v);
                }
            });
        }

        @Override
        public void onError(Throwable e) {
            e.printStackTrace();
        }

        @Override
        public void onNext(String v) {
            System.out.println("onNext: " + v);
        }

    });

    return new CommandHelloWorld("this is content for observe").execute();
}

Dashboard

在spring boot里注册HystrixMetricsStreamServlet

@Configuration
@PropertySource("classpath:application.properties")
class HystrixConfiguration extends SpringBootServletInitializer {

    /**
     * to expose stream endpoint
     */
    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        return new ServletRegistrationBean(new HystrixMetricsStreamServlet(), "/hystrix.stream");
    }

}

配置好StreamServlet后就会在/hystrix.stream产生流数据,然后你只要再建一个dashboard并把当前的spring的url加入dashboard就可以看到很fancy的dashboard了。
搭建dashboard这块可以参考:
https://github.com/Netflix/Hystrix/tree/master/hystrix-dashboard

这里写图片描述

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:134560次
    • 积分:1624
    • 等级:
    • 排名:千里之外
    • 原创:32篇
    • 转载:0篇
    • 译文:0篇
    • 评论:35条
    文章分类
    最新评论