xqlee 1546 0 2017-07-22 20:58:56

文章位置:左搜> 编程技术> 正文

一、本博客讲解内容

  学习怎么利用spring cloud 的Hystrix组件,在调用底层微服务时实现断路器。通常需要在应用程序中启用容错功能,因为某些底层服务会永久地降低/抛出错误,因此我们需要自动返回不同的程序执行路径。这与使用大量底层微服务的生态系统的分布式计算风格有关。这就是断路器模式的作用,而Hystrix是建立断路器的一个工具。

二、Hystrix Example for real impatient

Hystrix配置主要分4个步骤。

2.1添加Hystrix starter 和dashboard的maven依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>

2.2添加注解 @EnableCircuitBreaker

2.3添加注解@EnableHystrixDashboard

2.4添加注解 @HystrixCommand(fallbackMethod = "myFallbackMethod")

三、什么是断路器模式?

    如果我们在基于微服务的体系结构上设计我们的系统,我们通常会开发许多微服务,这些服务将会在实现特定的业务目标时相互影响。现在,我们所有人都可以假设,如果所有服务都启动并运行,并且每个服务的响应时间都令人满意,那么这将给出预期的结果。

    如果当前生态系统中的任何服务都有一些问题,并且停止了对请求的服务,那么将会发生什么。这将导致时间/异常,整个生态系统将由于这一单点故障而变得不稳定。

    在这里,电路断路器模式很方便,当它看到任何这样的场景时,它会将流量重定向到一个后退的路径。此外,它还会密切监视有缺陷的服务,一旦服务恢复正常,就会恢复流量。

    断路器是一种包装方法的服务调用和监视服务健康,一旦它得到了一些问题,断路器旅行,所有进一步调用goto断路器回落,最后恢复后自动服务回来! !那很酷对吗?
seq

四、Hystrix Circuit 断路由的演示

对于演示电路断路器,我们将创建以下两个微服务,首先依赖于另一个。
  • 学生微服务——它将提供学生实体的一些基本功能。它将是一个基于REST的服务。我们将从学校的服务中调用这项服务来理解断路器。它将在本地主机端口8098上运行。
  • 学校微服务——再一次简单的基于REST的微服务,我们将使用Hystrix实现断路器。学生服务将从这里被调用,当学生服务不可用时,我们将测试下降的路径。它将在本地主机端口9098上运行。
演示所需要的环境:
  • Java 1.8
  • Eclipse as IDE
  • Maven as build tool
  • Spring cloud Hystrix as circuit breaker framework
  • Spring boot
  • Spring Rest

4.1创建学生服务

按照以下步骤创建和运行学生服务——一个简单的REST服务,提供学生实体的一些基本功能。


4.1.1创建spring boot项目

去spring boot的创建网站创建一个spring boot项目,包括以下依赖WebRest Repositoriesand Actuator。提供其他maven GAV坐标并下载该项目。
学生服务解压缩并将项目导入到Eclipse中,作为现有的maven项目。在此步骤中,将从maven存储库下载所有必需的依赖项。

4.1.2服务的端口设置

打开文件application.properties并且添加以下配置内容:
server.port = 8098
这将使该应用程序在缺省端口8098上运行。我们可以通过提供-Dserver来轻松地覆盖这一点。在启动服务器时Dserver.port=XXXX的参数。

4.1.3创建学生的微服务REST接口

现在,添加一个名为student servicecon掣的REST控制器类,并公开一个REST端点,以获取特定学校的所有学生详细信息。我们在这里暴露/ getStudentDetailsForSchool / { schoolname }端点服务于商业目的。为了简单起见,我们对学生的详细信息进行了编码。
StudentServiceController.java
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.example.howtodoinjava.springhystrixstudentservice.domain.Student;
 
@RestController
public class StudentServiceController {
 
    private static Map<String, List<Student>> schooDB = new HashMap<String, List<Student>>();
 
    static {
        schooDB = new HashMap<String, List<Student>>();
 
        List<Student> lst = new ArrayList<Student>();
        Student std = new Student("Sajal", "Class IV");
        lst.add(std);
        std = new Student("Lokesh", "Class V");
        lst.add(std);
 
        schooDB.put("abcschool", lst);
 
        lst = new ArrayList<Student>();
        std = new Student("Kajal", "Class III");
        lst.add(std);
        std = new Student("Sukesh", "Class VI");
        lst.add(std);
 
        schooDB.put("xyzschool", lst);
 
    }
 
    @RequestMapping(value = "/getStudentDetailsForSchool/{schoolname}", method = RequestMethod.GET)
    public List<Student> getStudents(@PathVariable String schoolname) {
        System.out.println("Getting Student details for " + schoolname);
 
        List<Student> studentList = schooDB.get(schoolname);
        if (studentList == null) {
            studentList = new ArrayList<Student>();
            Student std = new Student("Not Found", "N/A");
            studentList.add(std);
        }
        return studentList;
    }
}
Student.java
public class Student {
 
    private String name;
    private String className;
 
    public Student(String name, String className) {
        super();
        this.name = name;
        this.className = className;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getClassName() {
        return className;
    }
 
    public void setClassName(String className) {
        this.className = className;
    }
}

4.1.4测试学生微服务接口

    现在使用maven命令mvn clean install构建,并且使用命令java -jar target\spring-hystrix-student-service-0.0.1-SNAPSHOT.jar启动。这将启动默认端口8098的学生服务。
  用浏览器打开地址:http://localhost:8098/getStudentDetailsForSchool/abcschool.
  浏览器显示内容如下:
浏览器显示

4.2创建学校服务并启用Hystrix

与学生服务类似,为学校创建另一项微服务。它将在内部调用已开发的学生服务。

4.2.1生成spring boot项目

创建一个spring boot项目,并且添加以下依赖:
  • Web – REST Endpoints
  • Actuator – providing basic management URL
  • Hystrix – Enable Circuit Breaker
  • Hystrix Dashboard – Enable one Dashboard screen related to the Circuit Breaker monitoring
下载从spring boot创建器官网创建的项目
spring boot创建解压缩并将项目导入到Eclipse中,作为现有的maven项目。在此步骤中,将从maven存储库下载所有必需的依赖项。

4.2.2配置服务端口

打开配置文件application.properties 添加以下内容:
server.port = 9098
这将使该应用程序在缺省端口9098上运行。我们可以很容易地通过供给来覆盖-Dserver.port = XXXX启动服务器时的参数。

4.2.3启用Hystrix设置

  打开SpringHystrixSchoolServiceApplication ,也就是使用 @SpringBootApplication注解生成的类并且添加注解 @EnableHystrixDashboard 和 @EnableCircuitBreaker annotations.
  这将使Hystrix在应用程序中启用断路器,并将在Hystrix提供的本地主机上添加一个有用的指示板。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
 
@SpringBootApplication
@EnableHystrixDashboard
@EnableCircuitBreaker
public class SpringHystrixSchoolServiceApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(SpringHystrixSchoolServiceApplication.class, args);
    }
}

4.2.4添加controller

    添加学校serviceconcontroller Rest控制器,在这里我们将公开/getSchoolDetails/schoolname端点,它将简单地返回学校的详细信息和学生的详细信息。对于学生的详细信息,它将调用已经开发的学生服务端点。我们将创建一个委托层学生servicedelegate。java调用学生服务。这个简单的代码看起来就像:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.example.howtodoinjava.springhystrixschoolservice.delegate.StudentServiceDelegate;
 
@RestController
public class SchoolServiceController {
     
    @Autowired
    StudentServiceDelegate studentServiceDelegate;
 
    @RequestMapping(value = "/getSchoolDetails/{schoolname}", method = RequestMethod.GET)
    public String getStudents(@PathVariable String schoolname) {
        System.out.println("Going to call student service to get data!");
        return studentServiceDelegate.callStudentServiceAndGetData(schoolname);
    }
}

4.2.5StudentServiceDelegate

我们将在这里做下面的事情来支持Hystrix断路器。
  • 通过spring框架调用学生服务提供的RestTemplate
  • 添加Hystrix命令以启用回调方法 – @HystrixCommand(fallbackMethod = "callStudentServiceAndGetData_Fallback")这意味着我们需要添加另一种方法callStudentServiceAndGetData_Fallback 具有相同的签名,当实际的学生服务停止时将调用该签名。
  • 添加回调函数 - callStudentServiceAndGetData_Fallback他将会返回一些简单的默认值
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
 
@Service
public class StudentServiceDelegate {
 
    @Autowired
    RestTemplate restTemplate;
     
    @HystrixCommand(fallbackMethod = "callStudentServiceAndGetData_Fallback")
    public String callStudentServiceAndGetData(String schoolname) {
 
        System.out.println("Getting School details for " + schoolname);
 
        String response = restTemplate
                .exchange("http://localhost:8098/getStudentDetailsForSchool/{schoolname}"
                , HttpMethod.GET
                , null
                , new ParameterizedTypeReference<String>() {
            }, schoolname).getBody();
 
        System.out.println("Response Received as " + response + " -  " + new Date());
 
        return "NORMAL FLOW !!! - School Name -  " + schoolname + " :::  " +
                    " Student Details " + response + " -  " + new Date();
    }
     
    @SuppressWarnings("unused")
    private String callStudentServiceAndGetData_Fallback(String schoolname) {
 
        System.out.println("Student Service is down!!! fallback route enabled...");
 
        return "CIRCUIT BREAKER ENABLED!!! No Response From Student Service at this moment. " +
                    " Service will be back shortly - " + new Date();
    }
 
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

4.2.6构建并且测试学校服务

  使用maven命令mvn clean install来构建项目,并且使用命令java -jar target\spring-hystrix-school-service-0.0.1-SNAPSHOT.jar来启动项目.学校服务将会默认启动在9098端口。
  启动如上所述的学生服务,然后通过打开浏览器和类型来测试学校服务http://localhost:9098/getSchoolDetails/abcschool。它应该在浏览器中显示以下输出:
学校服务
 

五、测试Hystrix Circuit Breaker – Demo

打开链接http://localhost:9098/getSchoolDetails/abcschool.在浏览器应该显示:
多少

现在,我们已经知道学校服务在内部呼叫学生服务,它正在从那个服务中获取学生的详细信息。因此,如果两个服务都在运行,学校服务将显示学生服务返回的数据,正如我们在上面的学校服务浏览器输出中看到的那样。这是电路闭合状态。

 

现在,让我们停止学生服务,只需在学生服务服务器控制台中按CTRL+C(停止服务器),并从浏览器中再次测试学校服务。这一次,它将返回返回的方法响应。在这里,Hystrix进入了一幅画面,它在频繁的时间间隔内监控学生服务,而Hystrix的组件已经打开了电路和后退的道路。

 

下面是浏览器的输出结果。

回调
再次启动学生服务,等待几分钟,然后回到学校服务,它将再次开始正常的响应。

六、Hystrix Dashboard

在我们添加了hystrix指示板依赖的情况下,hystrix提供了一个不错的仪表盘和一个hystrix流。

http://localhost:9098/hystrix.stream这是Hystrix产生的连续流。这只是一个健康检查结果,以及所有被Hystrix监控的服务电话。示例输出将在浏览器中显示

监控http://localhost:9098/hystrix -这是可视指示板的初始状态。
控制3
现在,在仪表板中添加http://localhost:9098/hystrix.stream,以获得由Hystrix组件监视的电路的有意义的动态可视化表示。在主页上提供了流输入之后,可视化指示板。
444

八、总结

这都是关于创建弹簧的,可以是Hystrix断路器,我们已经测试了电路的开放路径和电路闭合路径。您自己的设置,并使用不同的组合服务状态来更清楚地说明整个概念。

如果您在执行本文时遇到任何困难,请添加注释。我们将乐于看到这个问题。


演示例子源码

原文地址:http://howtodoinjava.com/spring/spring-cloud/spring-hystrix-circuit-breaker-tutorial/