Spring Cloud Hystrix 断路器模式

项目源码下载:(访问密码:9987)
Spring-Cloud-Circuit-Breaker.zip

学习在调用底层微服务的同时利用调用的Spring Cloud Netflix堆栈组件之一Hystrix来实现断路器。在一些底层服务永久宕机/抛出错误的应用中,一般需要开启容错功能,我们需要自动回退到不同的程序执行路径。这与使用大量底层微服务的生态系统的分布式计算风格有关。这是断路器模式的帮助所在,也是构建此断路器的工具

Hystrix Example for real impatient

Hystrix 配置分四个主要步骤完成。

  1. 添加 Hystrix 启动器和仪表板依赖项。
    <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. 添加@EnableCircuitBreaker注释
  3. 添加@EnableHystrixDashboard注释
  4. 添加注释 @HystrixCommand(fallbackMethod = "myFallbackMethod")

什么是断路器模式?

如果我们在基于微服务的架构上设计我们的系统,我们通常会开发许多微服务,这些微服务将在实现某些业务目标时相互进行大量交互。现在,我们所有人都可以假设,如果所有服务都启动并运行并且每个服务的响应时间都令人满意,这将产生预期的结果。

现在,如果当前生态系统的任何服务出现问题并停止为请求提供服务,将会发生什么。这将导致超时/异常,并且由于这种单点故障,整个生态系统将变得不稳定。

在这里,断路器模式很方便,一旦看到任何此类情况,它就会将流量重定向到回退路径。它还密切监视有缺陷的服务,并在服务恢复正常后恢复流量。

因此,断路器是进行服务调用的方法的一种包装器,它监视服务运行状况,一旦出现问题,断路器就会跳闸,所有进一步调用都转到断路器回退并最终自动恢复一次服务回来了!!这很酷吧?
断路顺序
 

Hystrix 断路器示例

为了演示断路器,我们将创建以下两个微服务,其中第一个依赖于另一个。

  • 学生微服务– 这将提供Student实体的一些基本功能。这将是一个基于 REST 的服务。我们将从SchoolService调用此服务以了解断路器。它将8098在本地主机的端口上运行。
  • School Microservice – 又是一个简单的基于 REST 的微服务,我们将使用HystrixStudent将从这里调用服务,一旦学生服务不可用,我们将测试回退路径。它将在本地主机的 9098 端口上运行。

技术栈和演示运行时

 

技术栈和演示运行时

  • Java 1.8
  • Eclipse as IDE
  • Maven as build tool
  • Spring cloud Hystrix as circuit breaker framework
  • Spring boot
  • Spring Rest

创建学生服务

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

创建spring boot项目

从Spring Boot 初始值设定项门户创建一个具有三个依赖项的 Spring boot 项目,即WebRest RepositoriesActuator。给出其他maven GAV坐标并下载项目。
学生服务创建
解压缩该项目并将其作为现有的 maven 项目导入 Eclipse。在这一步中,所有必需的依赖项都将从 maven 存储库下载。
 

服务器端口设置

打开application.properties并添加端口信息。

server.port = 8098

这将使该应用程序在默认端口 8098 上运行。我们可以通过 -Dserver.port = XXXX在启动服务器时提供参数轻松覆盖它。
 

创建 REST API

现在添加一个 REST 控制器类,StudentServiceController并公开一个 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;
    }
}

构建和测试学生服务

现在mvn clean install使用 command进行最终构建并运行服务器java -jar target/spring-hystrix-student-service-0.0.1-SNAPSHOT.jar。这将在默认端口启动学生服务8098
打开浏览器并输入http://localhost:8098/getStudentDetailsForSchool/abcschool.
它应该在浏览器中显示以下输出 –
学生服务响应
 

创建学校服务 – Hystrix 已启用

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

生成spring boot项目

主要使用这些依赖项从Spring Boot 初始值设定项门户创建一个 Spring boot 项目。

  • Web – REST 端点
  • Actuator – 提供基本的管理 URL
  • Hystrix – 启用断路器
  • Hystrix Dashboard – 启用一个与断路器监控相关的仪表板屏幕

给出其他maven GAV坐标并下载项目。
学校服务项目创建

解压缩该项目并将其作为现有的 maven 项目导入到 Eclipse 中。在这一步中,所有必需的依赖项都将从 maven 存储库下载。

服务器端口设置

打开application.properties并添加端口信息。

server.port = 9098

这将使该应用程序在默认端口 9098 上运行。我们可以通过 -Dserver.port = XXXX在启动服务器时提供参数来轻松覆盖它。
 

启用 Hystrix 设置

打开SpringHystrixSchoolServiceApplication即生成的类,@SpringBootApplication并添加@EnableHystrixDashboard@EnableCircuitBreaker注释。
这将在应用程序中启用 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);
    }
}

添加 REST 控制器

添加SchoolServiceControllerRest Controller,我们将在其中公开/getSchoolDetails/{schoolname}端点,该端点将简单地返回学校详细信息及其学生详细信息。对于学生详细信息,它将调用已经开发的学生服务端点。我们将创建一个委托层StudentServiceDelegate.java来调用学生服务。这个简单的代码看起来像
SchoolServiceController.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);
    }
}

学生服务代表
我们将在这里做以下事情来启用 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();
    }
}

学校服务的构建和测试

现在mvn clean install使用 command进行最终构建并运行服务器java -jar target/spring-hystrix-school-service-0.0.1-SNAPSHOT.jar。这将在默认端口9098 中启动学校服务。
如上所述启动学生服务,然后通过打开浏览器并键入 来测试学校服务http://localhost:9098/getSchoolDetails/abcschool。它应该在浏览器中显示以下输出:学生服务响应内容

测试 Hystrix 断路器 – 演示

打开浏览器并输入http://localhost:9098/getSchoolDetails/abcschool.
它应该在浏览器中显示以下输出 –
学生断路有显示
现在我们已经知道 School 服务正在内部调用学生服务,并且它正在从该服务获取学生详细信息。因此,如果这两个服务都在运行,则学校服务将显示学生服务返回的数据,正如我们在上面的学校服务浏览器输出中看到的那样。这是电路关闭状态

现在让我们停止该服务的学生只需按CTRL + C在学生服务服务器控制台(停止服务器)和浏览器再次测试该学校的服务。这次它将返回回退方法响应。在这里,Hystrix 出现了,它频繁地监视学生服务,当它关闭时,Hystrix 组件已打开电路并启用回退路径。
这是浏览器中的回退输出。
输出
再次启动学生服务,稍等片刻,返回学校服务,它将再次以正常流程开始响应。
 

Hystrix 仪表板

由于我们添加了 hystrix 仪表板依赖项,因此 hystrix 在以下 URL 中提供了一个不错的仪表板和一个 Hystrix Stream:

  • http://localhost:9098/hystrix.stream – Hystrix 生成的连续流。它只是一个健康检查结果以及 Hystrix 正在监视的所有服务调用。示例输出在浏览器中看起来像 –Hystrix输出
  • http://localhost:9098/hystrix – 这是可视化仪表板初始状态。初始状态
  • 现在在仪表板中添加http://localhost:9098/hystrix.stream以获得由 Hystrix 组件监控的电路的有意义的动态视觉表示。在主页中提供 Stream 输入后的 Visual Dashboard –现在状态

总结

这就是创建 spring 可以 Hystrix 断路器的全部内容,我们已经测试了电路开放路径电路闭合路径。自己做设置,玩不同的组合服务状态,更清晰的整体概念。

项目源码下载:(访问密码:9987)
Spring-Cloud-Circuit-Breaker.zip

原创文章,作者:1402239773,如若转载,请注明出处:https://blog.ytso.com/243838.html

(0)
上一篇 2022年4月11日
下一篇 2022年4月11日

相关推荐

发表回复

登录后才能评论