SpringCloud Hystrix(断路器) 服务降级 和 服务熔断

26 篇文章 1 订阅
12 篇文章 2 订阅

1、服务降级

整体资源快不够了,忍痛将某些服务先关掉,待渡过难关,再开启。

服务降级的处理是在客户端实现完成的,与服务端没有关系。

1.1、举个例子

我们去银行排队办理业务,大部分的银行分为 普通窗口特殊窗口(如VIP窗口,老年窗口等)。

某天,银行大厅 普通窗口 排队的人过多,这时, 特殊窗口的工作人员 贴出告示:暂停服务,某时刻之后再开放 —— 这就是 服务降级
特殊窗口的工作人员就可以空出来去帮助 普通窗口 办理业务,提高办事效率,解决 普通窗口 排队人过多。

这就是 降级,降级的目的是为了解决整体项目的压力,而牺牲掉某个服务模块而采取的措施。

贴出告示:暂停服务,某时刻之后再开放 ,是给在特殊窗口 办理业务的人的一个告知响应。

2、服务熔断

一般是某个服务故障或者是异常引起的,类似现实世界中的 保险丝 ,当某个异常条件被触发,直接熔断该服务,而不是一直等待,直到该服务超时。

2.1、举个例子

生活中每家每户都在用电,小王家因电线老化、功率过大等原因导致跳闸停电,
而隔避的小李、小张家的用电是正常使用的。
电力公司没有因为小王家有故障线路而停掉其他人家的电,同时小王家没有使用有故障的电路的电。

这就是 熔断。

熔断的目的是当A服务模块中的某块程序出现故障后为了不影响其他客户端的请求而做出的及时回应。

3、总结

3.1、相同点:

  1. 目的很一致,都是从可用性可靠性着想,为防止系统的整体缓慢甚至崩溃,采用的技术手段;
  2. 最终表现类似,对于两者来说,最终让用户体验到的是某些功能暂时不可达或不可用;
  3. 粒度一般都是服务级别,当然,业界也有不少更细粒度的做法,比如做到数据持久层(允许查询,不允许增删改);
  4. 自治性要求很高,熔断模式一般都是服务基于策略的自动触发,降级虽说可人工干预,但在微服务架构下,完全靠人显然不可能,开关预置、配置中心都是必要手段 ;

3.2、区别:

  • 触发原因不太一样:
    服务降级一般是从 整体负荷考虑;
    服务熔断一般是 某个服务(下游服务)故障引起 ;

  • 管理目标的层次不太一样:
    降级一般需要对业务有层级之分(核心业务,非核心业务);
    熔断 其实是一个框架级的处理,每个微服务都需要(无层级之分),

4、 示例

4.1、 服务降级

1) 代码

Hystrix 与 Feign 配合使用

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
feign: 
  hystrix: 
    enabled: true

fallbackFactory=DeptClientServiceFallbackFactory.class 指定降级的调用类。

@FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory=DeptClientServiceFallbackFactory.class)
public interface DeptClientService {	
	
	@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
	public Dept get(@PathVariable("id") long id);

	@RequestMapping(value = "/dept/list", method = RequestMethod.GET)
	public List<Dept> list();

	@RequestMapping(value = "/dept/add", method = RequestMethod.POST)
	public boolean add(Dept dept);
}

DeptClientServiceFallbackFactory 的定义

@Component // 不要忘记添加,不要忘记添加
public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService> {
	
	@Override
	public DeptClientService create(Throwable throwable) {
		
		return new DeptClientService() {
			@Override
			public Dept get(long id) {
				return new Dept().setDeptno(id).setDname("该ID:" + id + "没有没有对应的信息,Consumer客户端提供的降级信息,此刻服务Provider已经关闭")
						.setDb_source("no this database in MySQL");
			}

			@Override
			public List<Dept> list() {
				return null;
			}

			@Override
			public boolean add(Dept dept) {
				return false;
			}
		};
	}
}
@RestController
public class DeptController {

	@Autowired
	private DeptClientService service ;

	@RequestMapping(value = "/consumer/dept/get/{id}")
	public Dept get(@PathVariable("id") Long id) {
		return service.get(id);
	}

	@RequestMapping(value = "/consumer/dept/list")
	public List<Dept> list() {
		return service.list();
	}

	@RequestMapping(value = "/consumer/dept/add")
	public Object add(Dept dept) {
		return service.add(dept);
	}
}

Dept 服务的代码

参考下面的 4.1、Hystrix 服务熔断

2)测试

请求 http://127.0.0.1/consumer/dept/get/{id}

当 Dept 服务正常运行时,无论id是否存在,都可能返回响应信息。

当 Dept 服务 关闭后,则返回 DeptClientServiceFallbackFactory 中定义的对应方法的响应信息

4.2、Hystrix 服务熔断

1) 代码:

<!-- hystrix -->
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
@RestController
public class DeptController {
	
	@Autowired
	private DeptService service;    //DeptService  中调用DeptDao ,DeptDao 调用的是通过 mybatis 调用mysql 数据库。 

	@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
	@HystrixCommand(fallbackMethod = "processHystrix_Get")       // processHystrix_Get 对应的响应方法
	public Dept get(@PathVariable("id") Long id) {
		Dept dept = this.service.get(id);
		if (null == dept) {
			throw new RuntimeException("该ID:" + id + "没有没有对应的信息");
		}
		return dept;
	}

	public Dept processHystrix_Get(@PathVariable("id") Long id) {
		return new Dept().setDeptno(id).setDname("该ID:" + id + "没有没有对应的信息,null--@HystrixCommand")
				.setDb_source("no this database in MySQL");
	}
}
@SpringBootApplication
@EnableEurekaClient // 本服务启动后会自动注册进eureka服务中
@EnableCircuitBreaker // 对hystrixR熔断机制的支持
public class DeptProvider8001_Hystrix_App {	
	public static void main(String[] args) {
		SpringApplication.run(DeptProvider8001_Hystrix_App.class, args);
	}	
}

2)测试:

请求 http://127.0.0.1/dept/get/{id}
当 id 的值 在数据库中有数据时,正常返回;

当 id 的值在数据库不存在时,则抛出 RuntimeException 异常时,被 @HystrixCommand 注释指定的 processHystrix_Get 方法拦截,并返回 processHystrix_Get() 中已经设定好的值。

3) 疑问:

当 则抛出 RuntimeException 等异常时,用统一的异常(下面有代码),也可以给出响应信息, 我感觉 Hystrix 的熔断 用处不大。

@ControllerAdvice
public class GlobalExceptionHandler {

	private static final Logger LOG = LoggerFactory.getLogger(GlobalExceptionHandler.class);
	
	@ResponseBody
	@ExceptionHandler(value={Exception.class,RuntimeException.class})
	public R handlerException(Exception ex) {
		ex.printStackTrace();
		LOG.error("handlerException 异常【{}】",ex);
		return R.exception();
	}
	
	//省略 .....
}
  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值