Spring Cloud Hystrix
接上篇:
Spring Cloud Eureka
使用命令开启两个服务提供者
java -jar .\hello-0.0.-SNAPSHOT.jar --server.port=
java -jar .\hello-0.0.-SNAPSHOT.jar --server.port=
运行ribbon-consumer,访问 http://localhost:9000/ribbon-consumer
停掉8081服务,刷新页面,会提示错误
改造ribbon-consumer项目
在pom中加入Hystrix
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
在启动类RibbonConsumerApplication 中加入@EnableCircuitBreaker注解
package org.mythsky.ribbonconsumer; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate; @EnableCircuitBreaker
@EnableDiscoveryClient
@SpringBootApplication
public class RibbonConsumerApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
} public static void main(String[] args) {
SpringApplication.run(RibbonConsumerApplication.class, args);
}
}
新增HelloService类,在helloService方法上增加@HystrixCommand
注解来制定回调方法
package org.mythsky.ribbonconsumer.service; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate; @Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "helloFallback")
public String helloService(){
return restTemplate.getForEntity("http://hello-service/hello",String.class).getBody();
} public String helloFallback(){
return "error";
}
}
修改ConsumerController
package org.mythsky.ribbonconsumer.controller; import org.mythsky.ribbonconsumer.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate; @RestController
public class ConsumerController {
@Autowired
HelloService helloService;
// RestTemplate restTemplate;
@RequestMapping(value = "/ribbon-consumer",method = RequestMethod.GET)
public String helloConsumer(){
// return restTemplate.getForEntity("http://hello-service/hello",String.class).getBody();
return helloService.helloService();
}
}
同样按上面方法启动8081和8082,打开http://localhost:9000/ribbon-consumer
然后停掉8081,多次刷新页面,会直接到error页
继续改造服务提供者hello-service,模拟服务阻塞,修改HelloController
@RequestMapping(value = "/hello",method = RequestMethod.GET)
public String index() throws Exception {
ServiceInstance instance=client.getLocalServiceInstance();
//让处理线程等待几秒钟
int sleepTime=new Random().nextInt(3000);
logger.info("sleepTime:"+sleepTime);
Thread.sleep(sleepTime); logger.info("/hello,host:"+instance.getHost()+", service_id:"+instance.getServiceId());
return "Hello world";
}
按上面的流程重新测试,Hystrix默认超时时间为2000ms,多刷新几次就能看到效果。
新建Spring boot 工程hystrix-dashboard,添加pom引用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>
在入口类添加@EnableHystrixDashboard注解
package org.mythsky.hystrixdashboard; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; @EnableHystrixDashboard
@SpringBootApplication
public class HystrixDashboardApplication { public static void main(String[] args) {
SpringApplication.run(HystrixDashboardApplication.class, args);
}
}
添加配置
spring.application.name=hystrix-dashboard
server.port=
启动项目,打开浏览器:http://localhost:2001/hystrix
修改ribbon-consumer的pom,添加引用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
启动ribbon-consumer,可以看到以下节点
在hystrix-dashboard界面输入监控地址:http://localhost:9000/hystrix.stream 再点击监控,刷新http://localhost:9000/ribbon-consumer 在dashboard界面即可看到相关信息
接下来体验集群监控
新建spring-boot项目turbine,添加pom引用
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-turbine</artifactId>
</dependency>
在入口类添加注解
package org.mythsky.tuibine; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.turbine.EnableTurbine; @EnableTurbine
@EnableDiscoveryClient
@SpringBootApplication
public class TuibineApplication { public static void main(String[] args) {
SpringApplication.run(TuibineApplication.class, args);
}
}
添加配置
server.port=
management.port= spring.application.name=tuibine eureka.client.service-url.defaultZone=http://localhost:1111/eureka/ turbine.app-config=ribbon-consumer
turbine.cluster-name-expression="default"
turbine.combine-host-port=true
启动项目,然后启动两个服务提供者和两个服务消费者
在dashboard中对turbine进行监控
hystrix源码分析
首先看@HystrixCommand,然后查看一下这个注解的引用,发现了HystrixCommandAspect,这个切面会拦截所有带@HystrixCommand注解的方法
@Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand)") public void hystrixCommandAnnotationPointcut() {
} @Pointcut("@annotation(com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser)")
public void hystrixCollapserAnnotationPointcut() {
} @Around("hystrixCommandAnnotationPointcut() || hystrixCollapserAnnotationPointcut()")
public Object methodsAnnotatedWithHystrixCommand(final ProceedingJoinPoint joinPoint) throws Throwable {
Method method = getMethodFromTarget(joinPoint);
Validate.notNull(method, "failed to get method from joinPoint: %s", joinPoint);
if (method.isAnnotationPresent(HystrixCommand.class) && method.isAnnotationPresent(HystrixCollapser.class)) {
throw new IllegalStateException("method cannot be annotated with HystrixCommand and HystrixCollapser " +
"annotations at the same time");
}
MetaHolderFactory metaHolderFactory = META_HOLDER_FACTORY_MAP.get(HystrixPointcutType.of(method));
MetaHolder metaHolder = metaHolderFactory.create(joinPoint);
HystrixInvokable invokable = HystrixCommandFactory.getInstance().create(metaHolder);
ExecutionType executionType = metaHolder.isCollapserAnnotationPresent() ?
metaHolder.getCollapserExecutionType() : metaHolder.getExecutionType(); Object result;
try {
if (!metaHolder.isObservable()) {
result = CommandExecutor.execute(invokable, executionType, metaHolder);
} else {
result = executeObservable(invokable, executionType, metaHolder);
}
} catch (HystrixBadRequestException e) {
throw e.getCause();
} catch (HystrixRuntimeException e) {
throw hystrixRuntimeExceptionToThrowable(metaHolder, e);
}
return result;
}
HystrixCommandAspect
默认走了这个方法
看下这个方法
public static Object execute(HystrixInvokable invokable, ExecutionType executionType, MetaHolder metaHolder) throws RuntimeException {
Validate.notNull(invokable);
Validate.notNull(metaHolder); switch (executionType) {
case SYNCHRONOUS: {
return castToExecutable(invokable, executionType).execute();
}
case ASYNCHRONOUS: {
HystrixExecutable executable = castToExecutable(invokable, executionType);
if (metaHolder.hasFallbackMethodCommand()
&& ExecutionType.ASYNCHRONOUS == metaHolder.getFallbackExecutionType()) {
return new FutureDecorator(executable.queue());
}
return executable.queue();
}
case OBSERVABLE: {
HystrixObservable observable = castToObservable(invokable);
return ObservableExecutionMode.EAGER == metaHolder.getObservableExecutionMode() ? observable.observe() : observable.toObservable();
}
default:
throw new RuntimeException("unsupported execution type: " + executionType);
}
}
如果是同步方法,执行return castToExecutable(invokable, executionType).execute();
再看看这里的execute,是HystrixExecutable 接口,定义如下
找一下接口的实现
HystrixCommand这个类在 com.netflix.hystrix 包中,下面是execute 方法
public R execute() {
try {
return queue().get();
} catch (Exception e) {
throw Exceptions.sneakyThrow(decomposeException(e));
}
}
下面是queue 方法
public Future<R> queue() {
/*
* The Future returned by Observable.toBlocking().toFuture() does not implement the
* interruption of the execution thread when the "mayInterrupt" flag of Future.cancel(boolean) is set to true;
* thus, to comply with the contract of Future, we must wrap around it.
*/
final Future<R> delegate = toObservable().toBlocking().toFuture(); final Future<R> f = new Future<R>() { @Override
public boolean cancel(boolean mayInterruptIfRunning) {
if (delegate.isCancelled()) {
return false;
} if (HystrixCommand.this.getProperties().executionIsolationThreadInterruptOnFutureCancel().get()) {
/*
* The only valid transition here is false -> true. If there are two futures, say f1 and f2, created by this command
* (which is super-weird, but has never been prohibited), and calls to f1.cancel(true) and to f2.cancel(false) are
* issued by different threads, it's unclear about what value would be used by the time mayInterruptOnCancel is checked.
* The most consistent way to deal with this scenario is to say that if *any* cancellation is invoked with interruption,
* than that interruption request cannot be taken back.
*/
interruptOnFutureCancel.compareAndSet(false, mayInterruptIfRunning);
} final boolean res = delegate.cancel(interruptOnFutureCancel.get()); if (!isExecutionComplete() && interruptOnFutureCancel.get()) {
final Thread t = executionThread.get();
if (t != null && !t.equals(Thread.currentThread())) {
t.interrupt();
}
} return res;
} @Override
public boolean isCancelled() {
return delegate.isCancelled();
} @Override
public boolean isDone() {
return delegate.isDone();
} @Override
public R get() throws InterruptedException, ExecutionException {
return delegate.get();
} @Override
public R get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return delegate.get(timeout, unit);
} }; /* special handling of error states that throw immediately */
if (f.isDone()) {
try {
f.get();
return f;
} catch (Exception e) {
Throwable t = decomposeException(e);
if (t instanceof HystrixBadRequestException) {
return f;
} else if (t instanceof HystrixRuntimeException) {
HystrixRuntimeException hre = (HystrixRuntimeException) t;
switch (hre.getFailureType()) {
case COMMAND_EXCEPTION:
case TIMEOUT:
// we don't throw these types from queue() only from queue().get() as they are execution errors
return f;
default:
// these are errors we throw from queue() as they as rejection type errors
throw hre;
}
} else {
throw Exceptions.sneakyThrow(t);
}
}
} return f;
}
看一下这里的toObservable()
final Func0<Observable<R>> applyHystrixSemantics = new Func0<Observable<R>>() {
@Override
public Observable<R> call() {
if (commandState.get().equals(CommandState.UNSUBSCRIBED)) {
return Observable.never();
}
return applyHystrixSemantics(_cmd);
}
};
可以看到hystrix底层大量使用了RxJava
写个测试代码
import rx.Observable;
import rx.Subscriber; public class ObServableTest {
public static void main(String[] args){
Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello RxJava");
subscriber.onNext("I am tom");
subscriber.onCompleted();
}
});
Subscriber<String> subscriber = new Subscriber<String>() {
@Override
public void onCompleted() {
System.out.println("订阅完成");
} @Override
public void onError(Throwable e) {
System.out.println("订阅出错");
} @Override
public void onNext(String s) {
System.out.println("订阅事件:"+s);
}
};
observable.subscribe(subscriber);
}
}
ObServableTest
运行可以看到
关于RxJava 可以参考:https://www.jianshu.com/p/414f755983f1
Spring Cloud Hystrix的更多相关文章
- 笔记:Spring Cloud Hystrix 异常处理、缓存和请求合并
异常处理 在 HystrixCommand 实现的run方法中抛出异常,除了 HystrixBadRequestException之外,其他异常均会被Hystrix 认为命令执行失败并触发服务降级处理 ...
- 笔记:Spring Cloud Hystrix 服务容错保护
由于每个单元都在不同的进程中运行,依赖通过远程调用的方式执行,这样就有可能因为网络原因或是依赖服务自身问题出现调用故障或延迟,而这些问题会直接导致调用方的对外服务也出现延迟,若此时调用方的请求不断增加 ...
- Spring Cloud 微服务笔记(六)Spring Cloud Hystrix
Spring Cloud Hystrix Hystrix是一个延迟和容错库,旨在隔离远程系统.服务和第三方库,阻止链接故障,在复杂的分布式系统中实现恢复能力. 一.快速入门 1)依赖: <dep ...
- 第五章 服务容错保护:Spring Cloud Hystrix
在微服务架构中,我们将系统拆分为很多个服务,各个服务之间通过注册与订阅的方式相互依赖,由于各个服务都是在各自的进程中运行,就有可能由于网络原因或者服务自身的问题导致调用故障或延迟,随着服务的积压,可能 ...
- 试水Spring Cloud Hystrix
Spring Cloud Hystrix是一个容错库,它实现了断路器模式,使得当服务发生异常时,会自动切断连接,并将请求引导至预设的回调方法. 服务端 在Spring Tool Suite的文件菜单中 ...
- spring cloud: Hystrix(五):如禁止单个FeignClient使用hystrix
spring cloud: Hystrix(五):如禁止单个FeignClient使用hystrix 首先application.yml / applicatoin.propreties的配置项:fe ...
- spring cloud: Hystrix(四):feign类似于hystrix的断容器功能:fallback
spring cloud: Hystrix(四):feign使用hystrix @FeignClient支持回退的概念:fallback方法,这里有点类似于:@HystrixCommand(fallb ...
- spring cloud: Hystrix(三):健康指数 health Indicator
spring cloud: Hystrix(三):健康指数 health Indicator ribbon+hystrix 当使用Hystrix时(spring-cloud-starter-hystr ...
- spring cloud: Hystrix(二):简单使用@HystrixCommand的commandProperties配置@HistrixProperty隔离策略
spring cloud: Hystrix(二):简单使用@HystrixCommand的commandProperties配置@HistrixProperty隔离策略 某电子商务网站在一个黑色星期五 ...
- spring cloud: Hystrix(一):简单使用
在微服务架构中,我们将系统拆分为很多个服务,各个服务之间通过注册与订阅的方式相互依赖,由于各个服务都是在各自的进程中运行,就有可能由于网络原因或者服务自身的问题导致调用故障或延迟,随着服务的积压,可能 ...
随机推荐
- 虚拟机CentOs的安装及大数据的环境搭建
大数据问题汇总 1.安装问题 1.安装步骤,详见文档<centos虚拟机安装指南> 2.vi编辑器使用问题,详见文档<linux常用命令.pd ...
- 诡异的 ERROR 1045 (28000): Access denied for user 错误
问题描述: 用户已建,权限已赋予.long long ago这个用户是可以正常访问的,但是今天它就不能访问了.报错如下: ERROR 1045 (28000): Access denied for u ...
- 30条SQL查询优化原则
在我们平常的SQL查询中,其实我们有许多应该注意的原则,以来实现SQL查询的优化,本文将为大家介绍30条查询优化原则. 首先应注意的原则 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 wher ...
- ArcMap等值面
先说一下题目,ArcMap中没有由栅格直接生成等值面的功能,但由栅格直接生成等值线的功能存在,可通过如下方式得到等值面: 1.提取等值线 由dem直接提取等值线:Spatial Analyst Too ...
- web项目文件夹上传
最近公司做工程项目,实现文件夹上传 网上找了很久,发现网上很多代码大都存在很多问题,不过还是让我找到了一个符合要求的项目. 对项目的文件夹上传功能做出分析,找出文件夹上传的原理,对文件夹的传输模式深入 ...
- 19-background
先来讲讲颜色表示法 一共有三种:单词.rgb表示法.十六进制表示法 rgb:红色 绿色 蓝色 三原色光学显示器,每个像素都是由三原色的发光原件组成的,靠明亮度不同调成不同的颜色的.用逗号隔开,r.g. ...
- Servlet组件之 jsp 技术
JSP 简称java服务器页面(java server page),jsp和servlet实现了我们的开发需求.对于jsp技术我们首先需要知道他的组成 HTML+java+jsp内置对象=jsp ...
- poj3061
#include<stdio.h> #include<iostream> using namespace std; #include<algorithm> cons ...
- 《mysql必知必会》学习_第10章_20180731_欢
第10章,计算字段. P64 select concat (vend_name,'(',vend_country,')') from vendors order by vend_name; # 拼接, ...
- fastscript例子一
fastscript例子一 fastscript例子一 unit Unit1; interface usesWinapi.Windows, Winapi.Messages, System.SysU ...