Hystrix针对不可用服务的保护机制以及引入缓存
之前我写过一篇博文,通过案例了解Hystrix的各种基本使用方式,在这篇文章里,我们是通过Hystrix调用正常工作的服务,也就是说,Hytrix的保护机制并没有起作用,这里我们将在HystrixProtectDemo.java里演示调用不可用的服务时,hystrix启动保护机制的流程。这个类是基于NormalHystrixDemo.java改写的,只是在其中增加了getFallback方法,代码如下。
1 //省略必要的package和import代码
2 public class HystrixProtectDemo extends HystrixCommand<String> {
3 RestClient client = null;
4 HttpRequest request = null;
5 //构造函数很相似
6 public HystrixDemoProtectDemo() {
7 super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
8 }
9 //initRestClient方法没变
10 private void initRestClient(){
11 //和NormalHystrixDemo.java一样,具体请参考代码
12 }
13 //run方法也没变
14 protected String run() {
15 //和NormalHystrixDemo.java一样,具体请参考代码
16 }
17 //这次多个了getFallback方法,一旦出错,会调用其中的代码
18 protected String getFallback() {
19 //省略跳转到错误提示页面的动作
20 return "Call Unavailable Service.";
21 }
22 //main函数
23 public static void main(String[] args) {
24 HystrixDemoProtectDemo normalDemo = new HystrixDemoProtectDemo();
25 normalDemo.initRestClient();
26 try {
27 Thread.sleep(1000);
28 } catch (InterruptedException e) {
29 e.printStackTrace();
30 }
31 String result = normalDemo.execute();
32 System.out.println("Call available function, result is:" + result);
33 }
34 }
这个类里的构造函数和NormalHystrixDemo.java很相似,而initRestClient和run方法根本没变,所以就不再详细给出了。
在第18行里,我们重写了HystrixCommand类的getFallback方法,在其中定义了一旦访问出错的动作,这里仅仅是输出一段话,在实际的项目里,可以跳转到相应的错误提示页面。
而main函数里的代码和NormalHystrixDemo.java里的完全一样,只是,在运行这段代码前无需运行HystrixServerDemo项目的启动类,这样服务一定是调用不到的。运行本段代码后,我们能看到如下的结果。
In run
Call available function, result is:Call Unavailable Service.
从第2行的输出上,我们能确认,一旦调用服务出错,Hystrix处理类能自动地调用getFallback方法。
如果这里没有定义getFallback方法,那么一旦服务不可用,那么用户可能在连接超时之后,在浏览器里看到一串毫无意义的内容,这样用户体验就很差,如果整个系统的其它容错措施也没到位,甚至就有可能导致当前和下游模块瘫痪。
相反,在这里由于我们在hystirx提供的getFallback方法里做了充分的准备,那么一旦出现错误,这段错误处理的代码能被立即触发,其效果就相当于熔断后继的处理流程。
由getFallback出面,友好地告知用户出问题了,以及后继该如何处理,这样一方面能及时熔断请求从而保护整个系统,另一方面不会造成因体验过差而用户大规模流失的情况。
如果每次请求都要走后台应用程序乃至再到数据库检索一下数据,这对服务器的压力太大,有时候这一因素甚至会成为影响网站服务性能的瓶颈。所以,大多数网站会把一些无需实时更新的数据放入缓存,前端请求是到缓存里拿数据。
Hystrix在提供保护性便利的同时,也能支持缓存的功能,在下面的HystrixCacheDemo.java里,我们将演示Hystrix从缓存中读取数据的步骤,代码如下。
1 //省略必要的package和import代码
2 public class HystrixCacheDemo extends HystrixCommand<String> {
3 //用户id
4 Integer id;
5 //用一个HashMap来模拟数据库里的数据
6 private HashMap<Integer,String> userList = new HashMap<Integer,String>();
7 //构造函数
8 public HystrixCacheDemo(Integer id) {
9 super(HystrixCommandGroupKey.Factory.asKey("RequestCacheCommand"));
10 this.id = id;
11 userList.put(1, "Tom");
12 }
在第3行里,我们定义了一个用户id,并在第6行定义了一个存放用户信息的HashMap。
在第8行的构造函数里,我们在第10行里用参数id来初始化了本对象的id属性,并在第11行里,通过put方法模拟地构建了一个用户,在项目里,用户的信息其实是存在数据库里的。
13 protected String run() {
14 System.out.println("In run");
15 return userList.get(id);
16 }
如果不走缓存的话,第13行定义run函数将会被execute方法触发,在其中的第15行里,我们通过get方法从userList这个HashMap里获得一条用户数据,这里我们用get方法来模拟根据id从数据库里获取数据的诸多动作。
17 protected String getCacheKey() {
18 return String.valueOf(id);
19 }
第17行定义的getCacheKey方法是Hystrix实现缓存的关键,在其中我们可以定义“缓存对象的标准”,具体而言,我们在这里是返回String.valueOf(id),也就是说,如果第二个HystrixCacheDemo对象和第一个对象具有相同的String.valueOf(id)的值,那么第二个对象在调用execute方法时,就可以走缓存。
public static void main(String[] args) {
21 //初始化上下文,否则无法用缓存机制
22 HystrixRequestContext context = HystrixRequestContext.initializeContext();
23 //定义两个具有相同id的对象
24 HystrixCacheDemo cacheDemo1 = new HystrixCacheDemo(1);
25 HystrixCacheDemo cacheDemo2 = new HystrixCacheDemo(1);
26 //第一个对象调用的是run方法,没有走缓存
27 System.out.println("the result for cacheDemo1 is:" + cacheDemo1.execute());
28 System.out.println("whether get from cache:" + cacheDemo1.isResponseFromCache);
29 //第二个对象,由于和第一个对象具有相同的id,所以走缓存
30 System.out.println("the result for cacheDemo2 is:" + cacheDemo2.execute());
31 System.out.println("whether get from cache:" + cacheDemo2.isResponseFromCache);
32 //销魂上下文,以清空缓存
33 context.shutdown();
34 //再次初始化上下文,但由于缓存已清,所以cacheDemo3没走缓存
35 context = HystrixRequestContext.initializeContext();
36 HystrixCacheDemo cacheDemo3 = new HystrixCacheDemo(1);
37 System.out.println("the result for 3 is:" + cacheDemo3.execute());
38 System.out.println("whether get from cache:" + cacheDemo3.isResponseFromCache);
39 context.shutdown();
在第20行的main方法里,我们定义了如下的主要逻辑。
第一,在第22行,通过initializeContext方法,初始化了上下文,这样才能启动缓存机制。,在第24和25行里,我们创建了两个不同名的,但相同id的HystrixCacheDemo对象。
第二,在第27行里,我们通过cacheDemo1对象的execute方法,根据id查找用户,虽然我们在这里是通过run方法里第15行的get方法从HashMap里取数据,但大家可以把这想象成从数据表里取数据。
第三,在第30行里,我们调用了cacheDemo2对象的execute方法,由于它和cacheDemo1对象具有相同的id,所以这里并没有走execute方法,而是直接从保存cacheDemo1.execute的缓存里拿数据,这就可以避免因多次访问数据库而造成了系统损耗。
第四,我们在第33行销毁了上下文,并在第35行里重新初始化了上下文,之后,虽然在第36行定义的cacheDemo3对象的id依然是1,但由于上下文对象被重置过,其中的缓存也被清空,所以在第37里执行的execute方法并没有走缓存。
运行上述代码,我们能看到如下的输出,这些打印结果能很好地验证上述对主要流程的说明。
1 In run
2 the result for cacheDemo1 is:Tom
3 whether get from cache:false
4 the result for cacheDemo2 is:Tom
5 whether get from cache:true
6 In run
7 the result for 3 is:Tom
这里请大家注意,在缓存相关的getCacheKey方法里,我们不是定义“保存缓存值”的逻辑,而是定义“缓存对象的标准”,初学者经常会混淆这点。具体而言,在这里的getCacheKey方法里,我们并没有保存id是1的User对象的值(这里是Tom),而是定义了如下的标准:只要两个(或多个)HystrixCacheDemo对象具有相同的String.valueOf(id)的值,而且缓存中也已经存有id的1的结果值,那么后继对象则可以直接从缓存里读数据。
在上文里,我们演示了通过Hystrix调用可用以及不可用服务的运行结果,并在调用过程中引入了缓存机制,这里,我们将在上述案例的基础上归纳Hystrix的一般工作流程。
第一,我们可以通过extends HystrixCommand<T>的方式,让一个类具备Hystrix保护机制的特性,其中T是泛型,在上述案例中我们用到的是String。
第二,一旦继承了HystrixCommand之后,我们就可以通过重写run方法和getFallback方法来定义调用“可用”和“不可用”服务的业务功能代码,其中,这两个方法的返回值需要和第一步里定义的泛型T一致。而在项目里,我们一般在getFallback方法里,定义“服务不可用”时的保护措施(也就是后文里将要提到的降级措施)。
第三,我们还可以通过缓存机制来降低并发情况下对服务器的压力,在Hystrix里,我们可以在getCacheKey里定义“判断可以走缓存对象的标准”。
在使用缓存是,请注意两点,第一需要开启上下文,第二,Hystrix会根据定义在类里的属性判断多次调用的对象是否是同一个,如果是,而且之前被调用过,则可以走缓存。
本文谢绝转载。
Hystrix针对不可用服务的保护机制以及引入缓存的更多相关文章
- 用 Hystrix 构建高可用服务架构
1 hystrix是什么 在分布式系统中,每个服务都可能会调用很多其他服务,被调用的那些服务就是依赖服务,有的时候某些依赖服务出现故障也是很正常的. Hystrix 可以让我们在分布式系统中对服务间的 ...
- spring cloud 入门系列四:使用Hystrix 实现断路器进行服务容错保护
在微服务中,我们将系统拆分为很多个服务单元,各单元之间通过服务注册和订阅消费的方式进行相互依赖.但是如果有一些服务出现问题了会怎么样? 比如说有三个服务(ABC),A调用B,B调用C.由于网络延迟或C ...
- SpringCould-------使用Hystrix 实现断路器进行服务容错保护
消费: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.or ...
- 白话SpringCloud | 第五章:服务容错保护(Hystrix)
前言 前一章节,我们知道了如何利用RestTemplate+Ribbon和Feign的方式进行服务的调用.在微服务架构中,一个服务可能会调用很多的其他微服务应用,虽然做了多集群部署,但可能还会存在诸如 ...
- 第五章 服务容错保护:Spring Cloud Hystrix
在微服务架构中,我们将系统拆分为很多个服务,各个服务之间通过注册与订阅的方式相互依赖,由于各个服务都是在各自的进程中运行,就有可能由于网络原因或者服务自身的问题导致调用故障或延迟,随着服务的积压,可能 ...
- Spring Cloud(四):服务容错保护 Hystrix【Finchley 版】
Spring Cloud(四):服务容错保护 Hystrix[Finchley 版] 发表于 2018-04-15 | 更新于 2018-05-07 | 分布式系统中经常会出现某个基础服务不可用 ...
- Spring Cloud Hystrix 服务容错保护
目录 一.Hystrix 是什么 二.Hystrix断路器搭建 三.断路器优化 一.Hystrix 是什么 在微服务架构中,我们将系统拆分成了若干弱小的单元,单元与单元之间通过HTTP或者TCP等 ...
- 笔记:Spring Cloud Hystrix 服务容错保护
由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身问题出现调用故障或延迟,而这些问题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断增加 ...
- 《springcloud 四》服务保护机制
服务保护机制SpringCloud Hystrix 微服务高可用技术 大型复杂的分布式系统中,高可用相关的技术架构非常重要. 高可用架构非常重要的一个环节,就是如何将分布式系统中的各个服务打造成高可用 ...
随机推荐
- Future模式衍生出来的更高级的应用
再上一个场景:我们自己写一个简单的数据库连接池,能够复用数据库连接,并且能在高并发情况下正常工作. 实现代码1: package test; import java.util.concurrent.C ...
- 腾讯AI开放平台的使用
一.腾讯AI开放平台 https://ai.qq.com/ 二.腾讯AI平台支持的功能 三.签名机制 1.计算步骤 用于计算签名的参数在不同接口之间会有差异,但算法过程固定如下4个步骤. 1.将< ...
- BZOJ.4137.[FJOI2015]火星商店问题(线段树分治 可持久化Trie)
BZOJ 洛谷 一直觉得自己非常zz呢.现在看来是真的=-= 注意题意描述有点问题,可以看BZOJ/洛谷讨论. 每个询问有两个限制区间,一是时间限制\([t-d+1,t]\),二是物品限制\([L,R ...
- BZOJ5465 : [APIO 2018] 选圆圈
假设最大的圆半径为$R$,以$2R$为大小将地图划分为一个个格子,那么每个圆只需要检查圆心在附近$9$个格子内部的所有圆. 在当前圆的半径不足$\frac{R}{2}$时重构网格,那么最多重构$O(\ ...
- FlowerVisor理解
Ï来自FlowVisor: A Network Virtualization Layer这篇论文的理解 1. 简介 论文讲述如何虚拟化一个网络,并描述一个特殊的系——FlowVisor 网络虚拟化用来 ...
- js计算发表的时间...分钟/小时以前/以后
网上找的都好复杂,这本来就是个粗略显示通俗的时间,绕来绕去都晕了 function timeAgo(o){ var n=new Date().getTime(); var f=n-o; var bs= ...
- js == 运算规则解析
1.先了解一下基本类型和复杂类型划分的依据 JS中的值有两种类型:原始类型(Primitive).对象类型(Object).原始类型包括:Undefined.Null.Boolean.Number和S ...
- Java_循环
遍历数组: 一个栗子: public class Test01 { public static void main(String[] args) { int[] aa = {19,92,12,03,4 ...
- session源码剖析
session机制采用的是一种在客户端与服务端之间保持状态的解决方案,由于采用服务器端保持状态的方案在客户端也要保存标识,session机制也要借助于cookie机制达到目的.session保存了客户 ...
- MySQL视图更新
昨天在写美团2019秋招笔试题的时候遇到了关于视图是否能更新的问题,突然感觉这个问题之前复习的时候重点关注过,但是却又想不全.今天特地搜了一些资料总结一下.本文主要说明视图的更新限制,如需关于视图的更 ...