Spring Cloud学习 之 Spring Cloud Hystrix(基础知识铺垫)
Spring Boot版本:2.1.4.RELEASE
Spring Cloud版本:Greenwich.SR1
前述:
在微服务架构中,我们将系统拆分成了很多服务单元,各单元的应用间通过服务注册与订阅的方式互相依赖。由于每个单元都在不同的进行中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身的问题出现调用故障或延迟,而这些问题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断增加,最后就会因为等待出现故障的依赖方响应形成任务积压,最终导致自身服务的瘫痪。
举一个例子,在一个电商网站中,我们可能会将系统分成用户,订单,库存,积分,评论等一系列的服务单元。用户创建一个订单的时候,客户端将调用订单服务的创建订单接口,此时创建订单接口又会向库存服务来请求出货。此时若库存服务因自身处理逻辑等原因造成响应缓慢,会直接导致创建订单服务的线程被挂起,以等待库存申请服务的响应,在漫长的等待之后用户会因为请求库存失败而得到创建订单失败的结果,如果在高并发的情况下,因这些挂起的线程在等待库存服务的响应而未能释放,使得后续到来的创建订单请求被阻塞,最终导致订单服务也不可用。
在微服务架构中,存在那么多的服务单元,若一个单元出现故障,就很容易因依赖关系而引发故障的蔓延,最终导致整个系统的瘫痪,这样的架构相较传统架构更加的不稳定,为了解决这样的问题,产生了断路器等一系列的服务保护机制。
当某个服务发生故障后,通过断路器的故障监控,向调用方返回一个错误响应,而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。
针对上述问题,Spring Cloud Hystrix实现了断路器,线程隔离等一系列服务保护功能。它也是基于Netflix的开源框架Hystrix实现的,该框架的目标在于通过控制那些访问远程系统,服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix具备服务降级,服务熔断,线程和信号隔离,请求缓存,请求合并以及服务监控等强大功能。
快速入门:
如何使用hystrix:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
使用示例:
@RestController
@RequestMapping("/consumer")
@RequiredArgsConstructor
public class Controller { private final RestTemplate ribbonRestTemplate; @GetMapping("/get")
@HystrixCommand(fallbackMethod = "fallback")
public String consume() {
ResponseEntity<String> responseEntity = ribbonRestTemplate
.getForEntity("http://EUREKA-CLIENT/client/hello?who=小王",
String.class);
System.out.println(responseEntity.getBody());
return responseEntity.getBody();
}
// 当调用失败时(服务器发生异常)或者超出断路器最大等待时间,会执行这个回调方法
public String fallback() {
return "error";
}
}
命令模式:
先看下Nystrix官网的流程图,我们根据图中标志的顺序来解析每个环节

首先,创建一个HystrixCommand或者HystrixObservableCommand对象
首先,创建一个HystrixCommand或者HystrixObservableCommand对象用来表示对依赖服务的操作请求,同时传递所有需要的参数。从其命名我们就知道它是采用了”命令模式“来实现对服务调用操作的封装。而这两个command对象分别针对不同的应用场景
- HystrixCommand:用在依赖的服务返回单个操作结果的时候
- HystrixObservableCommand:用在依赖的服务返回多个操作结果的时候
什么是命令模式?
将来自客户端的请求封装成一个对象,从而可以让你使用不同的请求对客户端进行参数化。它可以被用于实现“行为请求者”与“行为实现者”的解耦,以便使两者可以适应变化。
我们需要知道:
- 命令模式是通过命令发送者和命令执行者的解耦来完成对命令的具体控制的。
- 命令模式是对功能方法的抽象,并不是对对象的抽象。
- 命令模式是将功能提升到对象来操作,以便对多个功能进行一系列的处理以及封装。
经典的命令模式包括4个角色:
- Command:定义命令的统一接口
- ConcreteCommand:Command接口的实现者,用来执行具体的命令,某些情况下可以直接用来充当Receiver。
- Receiver:行为实现者
- Invoker:行为请求者,是命令模式中最重要的角色。这个角色用来对各个命令进行控制。
先看下示例代码,我们再来分析这个设计模式:
/**
* 定义命令的统一接口
*
* @author dmz
* @date Create in 16:18 2019/5/18
*/
public interface Command {
/**
* 定义命令的抽象执行策略
*/
void execute();
}
/**
* Command接口的实现者,用来执行具体的命令,某些情况下可以直接用来充当Receiver。
*
* @author dmz
* @date Create in 16:18 2019/5/18
*/
public class ConcreteCommand implements Command {
private Receiver receiver;
public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.action();
}
}
/**
* 行为请求者
*
* @author dmz
* @date Create in 16:37 2019/5/18
*/
public class Invoker {
/**
* 行为请求者要持有需要请求的命令
*/
private Command command;
public void setCommand(Command command) {
this.command = command;
}
/**
* 行为请求者发起命令
*/
public void invoke() {
System.out.println("发起命令");
command.execute();
}
}
/**
* 行为实现者
*
* @author dmz
* @date Create in 16:22 2019/5/18
*/
public class Receiver {
public void action() {
System.out.println("执行业务逻辑");
}
}
/**
* @author dmz
* @date Create in 16:38 2019/5/18
*/
public class Main {
public static void main(String[] args) {
Command concreteCommand = new ConcreteCommand(new Receiver());
Invoker invoker = new Invoker();
invoker.setCommand(concreteCommand);
invoker.invoke();
}
}
从上面的示例中,我们可以看到Invoker跟Receiver通过Command接口实现了解耦。对于调用者来说,我们可以为其注入多个命令操作,比如新建文件,复制文件,删除文件这样三个操作,调用者只需要在需要的时候直接调用即可,而不需要知道这些操作命令实际是如何实现的。
关于命令模式,我们一直要知道它设计的初衷是什么,否则就会很混乱,每一个设计模式的出现都是为了解决特定情况下的某些问题,而不是凭空想象出来的,我们要能在合适的场景取采用合适的模式才算真正理解了这种设计模式。命令模式的初衷就是为了实现:对命令请求者(Invoker)和命令实现者(Receiver)的解耦,方便对命令进行各种控制。
在下面这些情况应考虑使用命令模式:
- 使用命令模式作为“回调(CallBack)”在面向对象系统中的替代,“CallBack”讲的便是先将一个函数登记上,然后在以后调用此函数。
- 需要在不同的时间指定请求,将请求排队。一个命令对象和原先的请求发出者可以有不同的生命期。换言之,原生的请求发出者可能已经不在了,而命令对象本身仍然是活动的。这时命令的接收者可以是在本地,也可以是在网络的另外一个地址上。命令对象可以在序列化后传送到另外一台机器上去
- 系统需要支持命令的撤销。命令对象可以把状态存储起来,等到客户端需要撤销命令所产生的效果时,可以调用undo()方法,把命令对象所产生的效果撤销掉。命令对象还可以提供redo()方法,以供客户端在需要时再重新实现命令效果。
- 如果要将系统中所有的数据更新到日志里,以便在系统奔溃时,可以根据数据读回所有的数据更新命令,重新调用Execute()方法一条条执行这些命令,从而恢复系统在奔溃前所作的数据更新
RxJava:
在Hystrix的底层实现中,大量的使用了RxJava,为了更容易的理解后续内容,在这里对RxJava的观察者-订阅者模式做一个简单的入门介绍。
RxJava 有以下三个基本的元素:
- 被观察者(Observable):
- 用来向订阅者Subscriber对象发布事件,Subscriber对象则在接受到对象后对其进行处理,而在这里指的事件通常就是对依赖服务的调用。
- 一个被观察者可以发出多个事件,知道结束或者发生异常。
- Observable对象每发出一个事件,就会调用对应观察者subscribe对象的onNext()方法
- 每一个Observable的执行,最后一定会通过调用subscribe.onCompleted()或者subscribe.onError()来结束该事件的操作流
- 观察者(Observer):
- 订阅(subscribe)
Spring Cloud学习 之 Spring Cloud Hystrix(基础知识铺垫)的更多相关文章
- Spring Cloud 学习 之 Spring Cloud Eureka(源码分析)
Spring Cloud 学习 之 Spring Cloud Eureka(源码分析) Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 ...
- Spring Cloud 学习 之 Spring Cloud Eureka(搭建)
Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 文章目录 搭建服务注册中心: 注册服务提供者: 高可用注册中心: 搭建服务注册中心: ...
- 学习 shell脚本之前的基础知识
转载自:http://www.92csz.com/study/linux/12.htm 学习 shell脚本之前的基础知识 日常的linux系统管理工作中必不可少的就是shell脚本,如果不会写sh ...
- 【转载】salesforce 零基础开发入门学习(二)变量基础知识,集合,表达式,流程控制语句
salesforce 零基础开发入门学习(二)变量基础知识,集合,表达式,流程控制语句 salesforce如果简单的说可以大概分成两个部分:Apex,VisualForce Page. 其中Apex ...
- Spring Cloud学习笔记--Spring Boot初次搭建
1. Spring Boot简介 初次接触Spring的时候,我感觉这是一个很难接触的框架,因为其庞杂的配置文件,我最不喜欢的就是xml文件,这种文件的可读性很不好.所以很久以来我的Spring学习都 ...
- spring cloud学习(六)Spring Cloud Config
Spring Cloud Config 参考个人项目 参考个人项目 : (希望大家能给个star~) https://github.com/FunriLy/springcloud-study/tree ...
- Spring Cloud 学习 (九) Spring Security, OAuth2
Spring Security Spring Security 是 Spring Resource 社区的一个安全组件.在安全方面,有两个主要的领域,一是"认证",即你是谁:二是& ...
- Spring Boot学习笔记---Spring Boot 基础及使用idea搭建项目
最近一段时间一直在学习Spring Boot,刚进的一家公司也正好有用到这个技术.虽然一直在学习,但是还没有好好的总结,今天周末先简单总结一下基础知识,等有时间再慢慢学习总结吧. Spring Boo ...
- Spring.NET学习笔记1——控制反转(基础篇)
在学习Spring.NET这个控制反转(IoC)和面向切面(AOP)的容器框架之前,我们先来看一下什么是控制反转(IoC). 控制反转(Inversion of Control,英文缩写为IoC),也 ...
- Spring 框架学习(1)--Spring、Spring MVC扫盲
纸上得来终觉浅,绝知此事要躬行 文章大纲 什么是spring 传统Java web应用架构 更强的Java Web应用架构--MVC框架 Spring--粘合式框架 spring的内涵 spring核 ...
随机推荐
- AJ学IOS(02)UI之按钮操作 点击变换 移动 放大缩小 旋转
不多说,先上图片看效果,AJ分享,必须精品 这个小程序主要实现点击方向键可以让图标上下左右动还有放大缩小以及旋转的功能,点击图片会显示另一张图片. 点击变换 其实用到了按钮的两个状态,再State C ...
- getline()和get()的使用区别
一.getline和get()的使用区别: 首先这两个函数都读取下一行输入,直到到达换行符:但是getline()函数会丢弃换行符,而get()将换行符保留在输入序列中 二.getline()函数的使 ...
- 使用SVG内置API计算图形或点经过transform之后的新坐标
一个应用场景是,点击一条路径,显示该路径的控制点.因为有transform变形( 平移.缩放.倾斜.旋转等变换),所以获取变形后的新坐标需要计算. 纯数学的方法,就是用2D变换矩阵的一些公式去运算,过 ...
- stand up meeting 11/19/2015
队员 今日工作 工作耗时/h 明日计划 计划耗时/h 冯晓云 利用昨天编写的调用必应词典API的DLL,完成了UWP版本查词APP的试水,证实了DLL可调和在线查词的可行性:和其他部分的同学就接口数据 ...
- Ubuntu搭建Redis 集群
1.源码编译 查看需要下载版本:http://download.redis.io/releases/ 本人保存路径:/usr/local/soft/ wget http://download.redi ...
- el-tab-pane label的文字内容怎样设间距
el-tab-pane label的文字内容怎样设间距 问题描述: 在使用element-ui的el-tab-pane做标签页时,label属性的位置与样式不能通过style样式直接解决 百度后几乎没 ...
- Python中的可视化神器!你知道是啥吗?没错就是pyecharts!
pyecharts是一款将python与echarts结合的强大的数据可视化工具,本文将为你阐述pyecharts的使用细则 前言 我们都知道python上的一款可视化工具matplotlib,而前些 ...
- SVM之不一样的视角
在上一篇学习SVM中 从最大间隔角度出发,详细学习了如何用拉格朗日乘数法求解约束问题,一步步构建SVM的目标函数,这次尝试从另一个角度学习SVM. 回顾监督学习要素 数据:(\(x_i,y_i\)) ...
- shift count is too large
STM8S是8 bit单片机在STM8S中 unsigned long是32位, unsigned short和unsigned int都是16位,unsigned char是8位. 以以下代码编译时 ...
- Go语言: 万物皆异步
来源:https://www.jianshu.com/p/62c0cd107da3 同步和异步.阻塞和非阻塞 首先要明确的是,同步(Synchronous)和异步(Asynchronous),阻塞(B ...