第五章 5.4-5.8 微服务容错保护----Hystrix

书籍地址: Spring Cloud 微服务架构开发实战

5.4 服务隔离

Hystrix的核心就是 提供服务容错保护,并且设计原则中就有一条:防止任何单一依赖用掉整个容器(如Tomcat)的全部用户线程。
那么Hystrix是如何实现的呢?
答案就是 舱壁隔离模式(Bulkhead Isolation Pattern)
Hystrix使用该模式,可以对资源或失败单元进行隔离,避免一个服务的失效导致整个系统垮掉(雪崩效应).

Hystrix实现服务隔离的思路如下:

  • 使用命令模式(HystrixCommand/HystrixObservableCommand) 对服务调用进行封装,使每个命令在单独线程中/信号授权下执行。
  • 为每一个命令的执行提供一个小的线程池/信号量,当线程池/信号量已满时,立即拒绝执行该命令,直接转入服务降级处理。
  • 为每一个命令的执行提供超时处理,当调用超时时,直接转入服务降级处理。
  • 提供断路器组件,通过设置相关配置及实时的命令执行数据统计,完成服务健康数据分析,使得在命令执行过程中可以快速判断是否可以执行,还是执行服务降级处理。

5.4.1 线程池隔离与信号量隔离

Hystrix提供了线程池隔离(Thread Pools) 和信号量隔离(Semaphores) 两种服务隔离策略。

  • 线程池隔离:不同服务的执行使用不同的线程池,同时将用户请求的线程与具体业务执行的线程分开,业务执行的线程池可以控制在指定大小的范围内,从而使业务之间不受影响,达到隔离的效果。
  • 信号量隔离:用户请求线程和业务执行线程是同一线程,通过设置信号量的大小限制用户请求对业务的并发访问量,从而达到限流的保护效果。

使用线程池隔离的优点:

  • 应用系统会被完全保护起来,即使其中一个服务线程池满了,也不会影响到应用的其他部分。
  • 当引入一个新的客户端的时候,如果发生问题,只会影响到新的服务,并不会影响其他服务。
  • 当一个失败的服务恢复正常时,系统会立即恢复正常的性能。
  • 如果我们的应用系统一些参数配置错误,那么线程池的运行状况将会很快被检测出来,比如延迟,超时,拒绝等。同时可以通过动态属性是实质性来处理纠正错误的参数配置。
  • 如果服务的性能有变化需要调整,比如增加或者减少超时时间,更改重试次数,就可以通过线程池指标动态属性修改,而且不会影响其他服务请求。
  • 除了隔离优势外,Hystrix拥有专门的线程池可提供内置的并发功能,可以再同步调用之上构建异步外观模式,这样能很方便的做异步编程

使用线程池隔离的缺点:
使用线程池隔离主要缺陷就是,它增加了计算的开销,每个业务请求在执行的时候,会涉及请求排队,线程调度,上下文切换等处理,但是线程隔离的开销,却是在可接收范围之内的,不会产生重大的成本或性能影响。

5.4.2 服务隔离的颗粒度

服务隔离在默认情况下会根据 Command, Group 和 Thread-Pool的命令来控制。
Group从业务逻辑上划分某些Command 为一组,每个独立的外部依赖放置于一个独立的Command中,拥有唯一的Command名称,每个独立的Command和Thread Pool是一对一的关系,从而达到资源隔离的目的。

服务隔离颗粒度控制策略:

  • 服务分组+线程池:实现服务分组隔离的粗粒度控制,一个服务分组/系统配置一个隔离线程池即可。也可以不配置线程池名称或者配置为相同的线程池名称。
  • 服务分组+服务+线程池:实现服务隔离的细粒度控制,一个服务分组中的每一个服务 配置一个隔离线程池,为不同的命令实现配置不同的线程池名称即可。
  • 混合实现:一个服务分组配置一个隔离线程池,然后对重要服务单独设置隔离线程池。

5.4.3 服务隔离配置

  • execution.isolation.strategy:设定服务隔离策略. THREAD为线程池隔离,SEMAPHORE为信号量隔离,默认为THREAD
  • execution.isolation.thread.timeoutInMillseconds:用来设置线程池隔离和信号量隔离两种隔离策略的超时时间,单位为毫秒,默认值是 1000ms. 该值根据相应的业务和服务器所能承受的负载来设置,一般设置为比业务平均响应时间大20%~100%即可。
  • execution.isolation.semaphore.maxConcurrentRequests:该值设置使用信号量隔离时最大的信号量大小。当请求达到或超过该设置值后,其余就会被降级处理,默认值时10。
  • execution.timeout.enabled: 是否开启业务服务超时处理,默认值是 true。
  • execution.isolation.thread.interruptOnTimeout:当业务服务超时时,是否中断线程,默认值是 true。
  • execution.isolation.thread.interruptOnCancel:取消时是否终端业务服务的执行,默认值是false.

5.5 服务降级模式

5.5.1 快速失败

快速失败模式是指在服务降级处理逻辑中不提供任何处理,直接抛出一个异常。

public class CommandThatFailsFast extends HystrixCommand<String>{
	private final boolean throwException;
	//通过构造函数设置是否需要抛出异常
	public CommandThatFailsFast(boolean throwException){
		super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup));
		this.throwException = throwException;
	}
	@Override
	protected String run() {
	    //这里不做任何处理,直接抛出一个异常
		if(throwException) {
			throw new RuntimeException("failure from CommandThatFailsFast");
		}else{
			return "success";
		}
	}
}

5.5.2 静默失败

静默失败即当进行服务降级处理时返回空的结果,针对返回值类型,返回的可能是null, 空List 或者 空Map等

@Override
protected String getFallback(){
	return null;
}

//针对列表,返回空列表
@Override
protected List<String> getFallback(){
	return Collections.emptyList();
}

//针对HystrixObservableCommand,返回一个空Observable对象
@Override
protected Observable<String> getFallback(){
	return Observable.empty();
}

5.5.3 返回默认值

服务降级时返回静态的在代码中固定的值,这样就不会像静默失败处理方式一样导致功能或服务被删除,用户不会像静默失败那么看不到任何功能,而是现实一个默认的值或功能。

5.5.4 返回组装的值

当我们执行的结果返回的是一个包含多个字段的复杂对象时,就可以通过服务请求中的值及一些默认值来组装这个返回结果。
我们可以从以下几个地方获取返回结果需要的值:

  • cookies;
  • 服务请求的参数及Header;
  • 之前成功返回的结果中。

5.5.5 返回远程缓存

返回远程缓存是指在服务处理失败的情况下再发起一次远程请求,不过这次请求的是一个缓存,比如读取Redis中的缓存结果。

当使用远程缓存时,需要注意的是获取远程缓存又是一个远程调用,所以需要重新封装为Command进行调用。这时候需要注意,执行fallback的线程一定要与主线程区分开。否则可能会造成主线程休眠,线程池被耗光,也就是说在执行fallback的命令时,需要重新命名ThreadPoolKey;

5.5.6 主/从降级模式

开发者当开发一个系统时可能会为系统设置双通道架构—主/从模式或者主模式和故障转移。
有时候从模式或故障转移只是用来做失败处理。
有时候开发者在部署新功能时,为了防止发生错误,可以将原来的旧代码作为从模式,当新功能出现错误时就降级使用原功能。

5.6 请求缓存

对于缓存的重要性不言自明,Hystrix所提供的请求缓存可以在 CommandKey/CommandGroup相同的情况下,直接共享命令执行的结果,降低依赖调用次数,在高并发和CacheKey命中率高的场景下可以提升服务性能。

Hystrix的请求缓存处理是在 construct() 或 run() 方法调用之前,可以有效减少业务服务请求数,降低了服务的并发。

由于请求缓存,对于相同的Hystrix命令,在执行时不可能返回不同的值,因为第一个响应的结果被缓存,也就是说此时会真实的调用一次run()方法,并且仅执行一次。同一请求中后续所有相同的Hystrix调用都将直接返回该缓存中的值,从而保证了数据的一致性。

开启Hystrix请求缓存功能很简单,只需要在实现 HystrixCommandHystrixObservableCommand 时,实现 getCacheKey() 方法即可。
或者通过配置属性 requestCache.enabled,启用来配置是否启用请求缓存,默认是true

5.6.1 清除缓存

可以通过Hystrix的 HystrixRequestCache.clear() 方法清楚缓存

5.6.2 判断是否时从缓存中返回

HystrixCommand 中提供了 isResponseFromCache() 方法,可以用来判断是否从请求缓存中返回。

此外,注解

  • @CacheResult: 标记返回结果需要进行缓存,该注解要与**@hystrixCommand** 注解一起使用。
  • @CacheKey:用来标记如果构建缓存的值,其功能类似于 getCacheKey() 方法。
  • @CacheRemove : 用来标记在方法执行完毕后清除指定的缓存。

5.7 请求合并

Hystrix支持将多个请求自动合并为一个请求,通过合并可以减少 HystrixCommand 并发执行所需的线程和网络连接数量,极大的节省了开销,提高了系统效率。

请求合并是由Hystrix自动合并进行的,并不需要在开发时进行代码介入

这里只是说,合并请求不需要代码介入,但对于批量请求的处理,还是需要写一些代码的。

多个请求能够自动合并的前提是,请求之间要足够 “近”,即执行的间隔时长要足够小,默认为10ms,可以通过 hystrix.collapser.default.timerDelayInMilliseconds 进行设置。即执行间隔超过 10ms 的请求不会合并执行。

5.8 Hystrix监控

关于Dashboard 和 Turbine ,笔者在学习过程中遇到了很深的坑,至今还未解决,就不误人子弟了. 仅推荐两篇博文,供大家参考

Dashboard
https://blog.csdn.net/WYA1993/article/details/82419131

Turbine
https://blog.csdn.net/chengqiuming/article/details/81588477

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值