Spring Cloud 进阶--Rest微服务加入Hystrix断路器实现服务熔断与服务降级

                                 《 Hystrix断路器,实现服务的熔断与降级 》

 

前言

在上一篇文章中,主要完成了 《  Rest微服务加入Feign负载均衡客户端组件 》,并且完成了 《 Hystrix 基本理论概述 》的详细简介,本篇博客将带领读者完整在 Rest 微服务中集成 Hystrix 实现服务的熔断(服务端)与服务的降级(客户端),本篇博客主要主要涉及模块,包括:

  • 新增基于 Hystrix 的服务消费者模块,服务名称为 “ microservice-hystrix-8001 ”;
  • 修改整体微服务项目的公共子模块,供其它子模块引用,达到通用的目的,项目名为 “ microservice-api ”;
  • 新增支持 Feign 的服务消费者模块,服务名称为 “ microservice-feign-80 ”;

 

Hystrix断路器,实现服务的熔断与降级

1、Hystrix 服务熔断

新增 hystrix 服务提供者模块,参考一号服务提供者模块服务器 “ microservice-provider-8001 ” 新建模块 “ microservice-hystrix-8001 ” 模块,创建完成后,如下图:

Spring Cloud 进阶--Rest微服务加入Hystrix断路器实现服务熔断与服务降级_第1张图片

 

POM 内容修改,新增对 Hystrix 的支持,完整内容如下:


	4.0.0

	
		com.huazai.springcloud
		microservice
		${project.version}
	

	microservice-hystrix-8001
	服务提供者模块(包括Hystrix延迟和容错的开源库)-8001

	
		
		
			com.huazai.springcloud
			microservice-api
			${project.version}
		
		
		
			junit
			junit
		
		
		
			mysql
			mysql-connector-java
		
		
			com.alibaba
			druid
		
		
		
			ch.qos.logback
			logback-core
		
		
		
			org.mybatis.spring.boot
			mybatis-spring-boot-starter
		
		
			org.springframework.boot
			spring-boot-starter-jetty
		
		
			org.springframework.boot
			spring-boot-starter-web
		
		
			org.springframework.boot
			spring-boot-starter-test
		
		
		
			org.springframework.cloud
			spring-cloud-starter-eureka
		
		
			org.springframework.cloud
			spring-cloud-starter-config
		
		
		
			org.springframework.boot
			spring-boot-starter-actuator
		
		
			org.springframework.cloud
			spring-cloud-starter-eureka
		
		
		
			org.springframework.cloud
			spring-cloud-starter-ribbon
		
		
		
			org.springframework.cloud
			spring-cloud-starter-hystrix
		
		
		
			org.springframework
			springloaded
		
		
			org.springframework.boot
			spring-boot-devtools
		
	



 

yml 内容修改,将服务的实例ID修改为 “ microservice-hystrix-8001 ”,主要目的为体现出当前项目支持 Hystrix 的服务提供者,当然还可根据需求修改为其它,完整内容如下:

server:
  port: 8001
  
mybatis:
  config-location: classpath:mybatis/mybatis.cfg.xml        # mybatis配置文件所在路径
  type-aliases-package: com.huazai.springcloud.entity    # 所有Entity别名类所在包
  mapper-locations:
  - classpath:mybatis/mapper/**/*.xml                       # mapper映射文件
    
spring:
   application:
    name: microservice-provider # 该模块的服务提供者的应用名称必须一致
   datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包
    url: jdbc:mysql://***.***.***.***:*****/microservice-01              # 数据库名称
    username: *****
    password: ***********
    dbcp2:
      min-idle: 5                                           # 数据库连接池的最小维持连接数
      initial-size: 5                                       # 初始化连接数
      max-total: 5                                          # 最大连接数
      max-wait-millis: 200                                  # 等待连接获取的最大超时时间
      
eureka:
  client: #客户端注册进eureka服务列表内
    service-url: 
      defaultZone: http://www.eureka7001.com:7001/eureka/,http://www.eureka7002.com:7002/eureka/,http://www.eureka7003.com:7003/eureka/
       
  instance:
    instance-id: microservice-hystrix-8001
    prefer-ip-address: true

info:
  app.name: learning-microservice-springcloud
  company.name: huazai-studio
  build.artifactId: $project.artifactId$
  build.version: $project.version$
  
 
 

 

修改 Controller 类

新增注解 “ @HystrixCommand ” ,其目的为:在基于微服务架构风格的业务系统中,当服务消费者模块对服务提供者模块调用失败时,不会直接卡死或者直接抛出一大坨异常,而是自动调用使用 “ @HystrixCommand ” 注解标注的指定的目标方法,返回指定的什么内容,完整内容如下:

package com.huazai.springcloud.controller;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.huazai.springcloud.entity.Department;
import com.huazai.springcloud.service.DepartmentService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;

@RestController
@RequestMapping(value = "/department")
@SuppressWarnings("unused")
public class DepartmentController
{

	@Autowired
	private DepartmentService departmentService;

	@RequestMapping(value = "/add", method = RequestMethod.POST)
	@HystrixCommand(fallbackMethod = "processHystrix_add")
	public boolean add(@RequestBody Department department)
	{
		boolean result = departmentService.add(department);
		if (!result)
		{
			throw new RuntimeException(department.toString() + "/n---添加异常");
		}
		return result;
	}

	private boolean processHystrix_add(@RequestBody Department department)
	{
		return false;
	}

	@RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
	@HystrixCommand(fallbackMethod = "processHystrix_delete")
	public void delete(@PathVariable Long id)
	{
		departmentService.delete(id);
	}

	private void processHystrix_delete(@PathVariable Long id)
	{
		System.out.println(id + "删除异常");
	}

	@RequestMapping(value = "/update", method = RequestMethod.PUT)
	@HystrixCommand(fallbackMethod = "processHystrix_update")
	public void update(@RequestBody Department department)
	{
		departmentService.update(department);
	}

	private void processHystrix_update(@RequestBody Department department)
	{
		System.out.println(department.toString());
	}

	@RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
	@HystrixCommand(fallbackMethod = "processHystrix_get")
	public Department get(@PathVariable Long id)
	{
		Department department = departmentService.get(id);
		if (department == null)
		{
			throw new RuntimeException(id + "号的部门信息不存在");
		}
		return department;
	}

	private Department processHystrix_get(@PathVariable Long id)
	{
		// Department department = new Department(id, id + "号的部门信息不存在", "not this data in the MySQL");
		Department department = new Department(id + "号的部门信息不存在");
		return department;
	}

	@RequestMapping(value = "/list")
	@HystrixCommand(fallbackMethod = "processHystrix_list")
	public List list()
	{
		List departments = departmentService.list();
		if (departments.size() == 0)
		{
			throw new RuntimeException("部门信息获取异常");
		}
		return departments;
	}

	private List processHystrix_list()
	{
		List departments = new ArrayList<>();
		// Department department = new Department(id, id + "号的部门信息不存在", "not this data
		// in the MySQL");
		Department department = new Department("部门信息异常,无部门信息");
		departments.add(department);

		return departments;
	}

}

 

修改启动类,新增注解 “ @EnableCircuitBreaker ” ,表示开启对hystrixR熔断机制的支持,完整内容如下:

package com.huazai.springcloud;

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

/**
 * 
 * @author HuaZai
 * @contact [email protected]
 *          
    * @description *
  • Hystrix 熔断器 *
* @className MicroserviceHystrixApp_8001 * @package com.huazai.springcloud * @createdTime 2018年05月06日 下午2:21:44 * * @version V1.0.0 */ @SpringBootApplication @EnableEurekaClient // 本服务启动后会自动注册进eureka服务中 @EnableCircuitBreaker // 开启对hystrixR熔断机制的支持 public class MicroserviceHystrixApp_8001 { public static void main(String[] args) { SpringApplication.run(MicroserviceHystrixApp_8001.class, args); } }

 

测试基于 Hystrix 的服务熔断机制

先启动 Eureka 集群,再启动基于 Hystrix 的服务提供者,并注册进 Eureka 注册中心,如下图:

Spring Cloud 进阶--Rest微服务加入Hystrix断路器实现服务熔断与服务降级_第2张图片

 

启动消费在服务模块 “ microservice-consumer-80 ” ,并访问消费者服务器地址,当访问的数据存在时则正常显示,如下图:

Spring Cloud 进阶--Rest微服务加入Hystrix断路器实现服务熔断与服务降级_第3张图片

 

当访问的数据不存在或者出现异常时,会立即返回自定义的信息,不会出现访问延迟的显现,页面访问异常的现象,如下图:

Spring Cloud 进阶--Rest微服务加入Hystrix断路器实现服务熔断与服务降级_第4张图片

 

 

2、Hystrix 服务降级

服务降级处理是在客户端完成的,与服务端是不存在任何关系的,所以需要在公共子模块 “ microservice-api ” 中新增一个 Factory 类 “ DepartmentClientServiceFallbackFactory.java ” ,实现 “ FallbackFactory ” ,并重写 FallbackFactory 的 “ create ” 方法,当然里面的方法就需要根据实际的需求来自定义了,本次的完整类容如下:

package com.huazai.springcloud.factory;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Component;

import com.huazai.springcloud.entity.Department;
import com.huazai.springcloud.service.DepartmentClientService;

import feign.hystrix.FallbackFactory;

/**
 * 
 * @author HuaZai
 * @contact [email protected]
 *          
    * @description TODO *
* * @className DepartmentClientServiceFallbackFactory * @package com.huazai.springcloud.factory * @createdTime 2018年05月14日 下午7:48:16 * * @version V1.0.0 */ @Component public class DepartmentClientServiceFallbackFactory implements FallbackFactory { @Override public DepartmentClientService create(Throwable cause) { return new DepartmentClientService() { @Override public void update(Department department) { // TODO Auto-generated method stub } @Override public List list() { List departments = new ArrayList<>(); Department department = new Department("部门信息异常,无部门信息"); departments.add(department); return departments; } @Override public Department get(Long id) { Department department = new Department(id + "号的部门信息不存在"); return department; } @Override public void delete(Long id) { // TODO Auto-generated method stub } @Override public boolean add(Department department) { // TODO Auto-generated method stub return false; } }; } }

 

在接口类 “ DepartmentClientService ” 中的 “ @FeignClient ” 注解中新增 fallbackFactory 属性,并指向方才新增的 “ DepartmentClientServiceFallbackFactory ” 工厂类,完整内容如下:

package com.huazai.springcloud.service;

import java.util.List;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.huazai.springcloud.entity.Department;
import com.huazai.springcloud.factory.DepartmentClientServiceFallbackFactory;

/**
 * 
 * @author HuaZai
 * @contact [email protected]
 *          
    * @description TODO *
* @className DepartmentClientService * @package com.huazai.springcloud.service * @createdTime 2018年05月13日 下午8:21:01 * * @version V1.0.0 */ @FeignClient(value = "MICROSERVICE-PROVIDER/department", fallbackFactory = DepartmentClientServiceFallbackFactory.class) // 添加 Fallback,实现服务降级 public interface DepartmentClientService { @RequestMapping(value = "/add", method = RequestMethod.POST) public boolean add(@RequestBody Department department); @RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE) public void delete(@PathVariable(value = "id") Long id); @RequestMapping(value = "/update", method = RequestMethod.PUT) public void update(@RequestBody Department department); @RequestMapping(value = "/get/{id}", method = RequestMethod.GET) public Department get(@PathVariable(value = "id") Long id); @RequestMapping(value = "/list") public List list(); }

 

重新安装公共模块 “ microservice-api ” ,以供其它子模块引用,达到通用的目的,点击项目右键 -> Run As -> Maven clean/Maven install。

 

修改基于 Feign 的服务消费者模块 “ microservice-feign-80 ” ,修改 YML 配置文件,新增开启 Hystrix 支持的配置,完整内容如下:

server:
  port: 80
  
feign:
  hystrix:
    enabled: true
  
eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://www.eureka7001.com:7001/eureka/,http://www.eureka7002.com:7002/eureka/,http://www.eureka7003.com:7003/eureka/
    

 

测试基于 Hystrix 的服务降级机制

先启动 Eureka 集群,再一个服务提供者模块,查看 Eureka 集群服务注册列表内容,如下图:

Spring Cloud 进阶--Rest微服务加入Hystrix断路器实现服务熔断与服务降级_第5张图片

 

最后启动基于 Feign 的消费者服务器,正常访问消费者服务器地址,如下图:

Spring Cloud 进阶--Rest微服务加入Hystrix断路器实现服务熔断与服务降级_第6张图片

 

模拟服务提供者出项异常宕机的情况,手动关闭提供者服务器,再次消费者服务器地址,会得出另外一个结果,如下图:

Spring Cloud 进阶--Rest微服务加入Hystrix断路器实现服务熔断与服务降级_第7张图片

 

关于 Hystrix 的服务降级:

在上面通过手动关闭提供者服务器的形式,模拟在实际环境中,服务器宕机的情况,使消费者请求不达的情况。因为在消费者服务器客户端使用了 Hystrix 的服务降级机制,所以,当遇到服务器宕机,请求不达的情况下,消费者客户端直接返回事先预定义的响应内容,期间会停止几毫秒,一般用户根本不会察觉,客户端会在这短短的时间里裁定服务器是否死亡,之后用户再次刷新访问时,客户端则会立即返回,不会再次访问并裁定是否死亡。

 

 

 

GitHub 源码地址:源码Clone地址

项目源码地址(zip格式的工程包):源码包下载地址


好了,关于 Spring Cloud 进阶--Rest微服务加入Hystrix断路器,实现服务的熔断与降级 就写到这儿了,如果还有什么疑问或遇到什么问题欢迎扫码提问,也可以给我留言哦,我会一一详细的解答的。 
歇后语:“ 共同学习,共同进步 ”,也希望大家多多关注CSND的IT社区。


作       者: 华    仔
联系作者: [email protected]
来        源: CSDN (Chinese Software Developer Network)
原        文: https://blog.csdn.net/Hello_World_QWP/article/details/88087407
版权声明: 本文为博主原创文章,请在转载时务必注明博文出处!

你可能感兴趣的:(Spring,Cloud,Spring,Cloud,进阶之路)