Hystrix简单学习-1


声明:本文转载自https://my.oschina.net/hanchao/blog/1593340,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

Hystrix是Netflix开源的一款容错框架,包含常用的容错方法:线程隔离、信号量隔离、降级策略、熔断技术。在高并发访问下,系统所依赖的服务的稳定性对系统的影响非常大,依赖有很多不可控的因素,比如网络连接变慢,资源突然繁忙,暂时不可用,服务脱机等。我们要构建稳定、可靠的分布式系统,就必须要有这样一套容错方法。

举例子:
1.
比如我们现在有3个业务调用分别是查询订单、查询商品、查询用户,且这三个业务请求都是依赖第三方服务-订单服务、商品服务、用户服务。三个服务均是通过RPC调用。当查询订单服务,假如线程阻塞了,这个时候后续有大量的查询订单请求过来,那么容器中的线程数量则会持续增加直致CPU资源耗尽到100%,整个服务对外不可用,集群环境下就是雪崩。

pom.xml的依赖

  	<!-- 中央库:引入hystrix等-->      <repository>          <id>nexus</id>          <name>local private nexus</name>          <url>http://search.maven.org</url>          <releases>              <enabled>true</enabled>          </releases>          <snapshots>              <enabled>false</enabled>          </snapshots>      </repository>      		<!-- hystrix -->   		<hystrix.version>1.5.12</hystrix.version>            <dependency>             <groupId>com.netflix.hystrix</groupId>             <artifactId>hystrix-core</artifactId>             <version>${hystrix.version}</version>       </dependency>  

简单例子1:

package com.book.web.test.hystrix;  import java.util.concurrent.Future; import java.util.concurrent.TimeUnit;  import com.netflix.hystrix.HystrixCommand; import com.netflix.hystrix.HystrixCommandGroupKey; /**  * 入门  * @author liweihan  *  */ public class CommandHelloWorld extends HystrixCommand<String> { 	 	private final String name;  	protected CommandHelloWorld(String name) { 		//最少配置:指定命令组名 		super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")); 		this.name = name; 	} 	 	@Override 	protected String run() throws Exception { 		//a real example would do work like a network call here 		//依赖逻辑封装在run()方法中 		return "Hello " + name + "! thread: " + Thread.currentThread().getName(); 	} 	 	 	public static void main(String[] args) throws Exception{ 		/** 		 * 每个Command对象只能调用一次,不可以重复调用 		 * 重复调用对应的异常信息:This instance can only be executed once. 		 * Please instantiate a new instance 		 */ 		CommandHelloWorld commandHelloWorld = new CommandHelloWorld("Synchronous-hystrix"); 		//使用execute()同步调用代码,效果等同于:commandHelloWorld.queue().get(); 		String s = commandHelloWorld.execute(); 		System.out.println(" 同步 ====== " + s); 		 		//异步调用,可以自由控制获取结果的时机 		commandHelloWorld = new CommandHelloWorld("Asynchronous-hystrix"); 		Future<String> future = commandHelloWorld.queue(); 		//get()操作不能超过command定义的超时时间,默认为1秒 		s = future.get(100, TimeUnit.MILLISECONDS); 		System.out.println(" 异步 ====== " + s); 		 		 		System.out.println(" 主函数 ===== " + Thread.currentThread().getName()); 		/** 		 * 注意: 		 * 异步调用使用 command.queue()get(timeout, TimeUnit.MILLISECONDS); 		 * 同步调用使用command.execute() 等同于 command.queue().get(); 		 */ 	}  } 

简单例子2:

package com.book.web.test.hystrix;  import java.util.concurrent.TimeUnit;  import com.netflix.hystrix.HystrixCommand; import com.netflix.hystrix.HystrixCommandGroupKey; import com.netflix.hystrix.HystrixCommandKey; import com.netflix.hystrix.HystrixCommandProperties; import com.netflix.hystrix.HystrixThreadPoolKey; /**  * 常用属性  * @author liweihan  *  */ public class CommandHelloWorld2 extends HystrixCommand<String>{ 	 	private final String name;  	protected CommandHelloWorld2(String name) { 		super(//命令分组用于对依赖操作分组,便于统计,汇总等. 				Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("HelloWorldGroup"))  				//配置依赖超时时间,500毫秒 				.andCommandPropertiesDefaults(HystrixCommandProperties.Setter() 						.withExecutionTimeoutInMilliseconds(500)) 				 //HystrixCommondKey工厂定义依赖名称 				.andCommandKey(HystrixCommandKey.Factory.asKey("commandHelloWorld2")) 				//使用HystrixThreadPoolKey工厂定义线程池名称 				.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")));  		this.name = name; 	} 	 	@Override 	protected String getFallback() { 		return "execute Falled"; 	} 	 	@Override 	protected String run() throws Exception { 		//sleep 1秒 ,调用会超时 		TimeUnit.MILLISECONDS.sleep(100); 		return "Hello " + name + " thread : " + Thread.currentThread().getName(); 	} 	 	public static void main(String[] args) throws Exception {  		CommandHelloWorld2 commandHelloWorld2 = new CommandHelloWorld2("test-Fallback"); 		String s = commandHelloWorld2.execute(); 		System.out.println(" 同步 ====== " + s); 		 		/** 		 * 注意: 		 * 1.除了HystrixBadRequestException异常之外,所有从run()方法抛出的异常都算作失败, 		               并触发降级getFallback()和断路器逻辑。 		                2.HystrixBadRequestException用在非法参数或非系统故障异常等不应触发回退逻辑的场景。                        3.每个CommandKey代表一个依赖抽象,相同的依赖要使用相同的CommandKey名称。                                       依赖隔离的根本就是对相同CommandKey的依赖做隔离.                                                   4.CommandGroup是每个命令最少配置的必选参数,                                       在不指定ThreadPoolKey的情况下,字面值用于对不同依赖的线程池/信号区分                                                          5.当对同一业务依赖做隔离时使用CommandGroup做区分,            	但是对同一依赖的不同远程调用如(一个是redis 一个是http),            	可以使用HystrixThreadPoolKey做隔离区分.            	最然在业务上都是相同的组,但是需要在资源上做隔离时,            	可以使用HystrixThreadPoolKey区分.               	            6.以下四种情况将触发getFallback调用:              1.)run()方法抛出非HystrixBadRequestException异常。              2.)run()方法调用超时              3.)熔断器开启拦截调用              4.)线程池/队列/信号量是是否跑满                                         实现getFallback()后,执行命令时遇到以上4中情况将被fallback接管,                                         不会抛出异常或其他。                      	                                                                  		 */ 	} } 

简单例子3:

package com.book.web.test.hystrix;  import com.netflix.hystrix.HystrixCommand; import com.netflix.hystrix.HystrixCommandGroupKey; import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;  /**  * 请求缓存【个人不建议用,不便于管理】  * @author liweihan  *  */ public class CommandHelloWorld3 extends HystrixCommand<String>{ 	 	private final int id;  	protected CommandHelloWorld3(int id) { 		super(HystrixCommandGroupKey.Factory.asKey("RequestCacheCommand")); 		this.id = id; 	} 	 	@Override 	protected String run() throws Exception { 		System.out.println(Thread.currentThread().getName() + " execute id = " + id); 		return "execute=" + id; 	} 	 	//重写getCacheKey,实现区分不同请求的逻辑 	@Override 	protected String getCacheKey() { 		System.out.println(" --- "); 		return String.valueOf(id); 	}  	public static void main(String[] args) { 		HystrixRequestContext context = HystrixRequestContext.initializeContext(); 		 		try { 			CommandHelloWorld3 commandHelloWorld3_a = new CommandHelloWorld3(22); 			CommandHelloWorld3 commandHelloWorld3_b = new CommandHelloWorld3(22); 			 			System.out.println("a执行结果:" + commandHelloWorld3_a.execute()); 			System.out.println("a执行结果是否从缓存中获取:" + commandHelloWorld3_a.isResponseFromCache); 			 			System.out.println("b执行结果:" + commandHelloWorld3_b.execute()); 			System.out.println("b执行结果是否从缓存中获取:" + commandHelloWorld3_b.isResponseFromCache); 		} finally  { 			context.shutdown(); 		} 		 		context = HystrixRequestContext.initializeContext(); 		try { 			CommandHelloWorld3 commandHelloWorld3_c = new CommandHelloWorld3(22); 			 			System.out.println("c执行结果:" + commandHelloWorld3_c.execute()); 			System.out.println("c执行结果是否从缓存中获取:" + commandHelloWorld3_c.isResponseFromCache); 			 		} finally  { 			context.shutdown(); 		} 		 		/** 		 * 注意: 		 * 请求缓存可以让(CommandKey/CommandGroup)相同的情况下, 		 * 直接共享结果,降低依赖调用次数, 		 * 在高并发和CacheKey碰撞率高场景下可以提升性能. 		 */ 	} } 

简单例子4:

package com.book.web.test.hystrix;  import java.util.concurrent.TimeUnit;  import com.netflix.hystrix.HystrixCommand;  /**  * 测试4-使用ApiSetter设置参数  * @author liweihan  *  */ public class CommandHelloWorld4 extends HystrixCommand<String>{ 	 	private Integer id; 	 	public CommandHelloWorld4(Integer id) { 		super(setter()); 		this.id = id; 	} 	 	private static Setter setter() { 		return ApiSetter.setter("getNum"); 	}  	@Override 	protected String run() throws Exception { 		TimeUnit.MINUTES.sleep(3); 		System.out.println(Thread.currentThread().getName() + " execute id = " + id); 		return "run execute=" + id; 	} 	 	@Override 	protected String getFallback() { 		return "getFallback --" + id; 	} 	 	public static void main(String[] args) { 		CommandHelloWorld4 commandHelloWorld4_a = new CommandHelloWorld4(2); 		System.out.println("a执行结果:" + commandHelloWorld4_a.execute()); 	} } 
package com.book.web.test.hystrix;  import com.netflix.hystrix.HystrixCommand; import com.netflix.hystrix.HystrixCommand.Setter; import com.netflix.hystrix.HystrixCommandGroupKey; import com.netflix.hystrix.HystrixCommandKey; import com.netflix.hystrix.HystrixCommandProperties; import com.netflix.hystrix.HystrixThreadPoolKey; import com.netflix.hystrix.HystrixThreadPoolProperties;  /**  * 调用API设置的参数或公共参数  * @author liweihan  *  */ public class ApiSetter {      public static Setter setter(String commandKeyName,String threadPoolKeyName) {         return setter("ApiGroup",commandKeyName,threadPoolKeyName);     }      public static Setter setter(String commandKeyName) {         return setter(commandKeyName,"Api-Pool");     }      /**      * @author liweihan      * @time 2017/12/20 16:57      * @description     相关参数设置      * @param groupKeyName      服务分组名      * @param commandKeyName    服务标识名称      * @param threadPoolKeyName 线程池名称      * @return      */     public static Setter setter(String groupKeyName,String commandKeyName,String threadPoolKeyName) {         //服务分组         HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(groupKeyName);         //服务标识         HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(commandKeyName);         //线程池名称         HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(threadPoolKeyName);         //线程配置         HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter()                 .withCoreSize(25)                 .withKeepAliveTimeMinutes(5)                 .withMaxQueueSize(Integer.MAX_VALUE)                 .withQueueSizeRejectionThreshold(10000);          //命令属性的配置         HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter()                 .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)                 .withExecutionIsolationThreadInterruptOnTimeout(true)                 .withExecutionTimeoutInMilliseconds(3000) //设置超时时间为3秒时自动熔断                 .withCircuitBreakerErrorThresholdPercentage(20);//失败率达到20%自动熔断          //返回         return HystrixCommand.Setter                 .withGroupKey(groupKey) 				.andCommandKey(commandKey)                 .andThreadPoolKey(threadPoolKey)                 .andThreadPoolPropertiesDefaults(threadPoolProperties)                 .andCommandPropertiesDefaults(commandProperties);     } 	 	/** 	 * ☆参数说明: 	 	1.HystrixCommandGroupKey:服务分组,以上groupKey分组就包括多个服务,必填选项 	 	 	 	2.HystrixCommandKey:服务的名称,唯一标识,如果不配置,则默认是类名 	 	 	 	3.HystrixThreadPoolKey:线程池的名称,相同线程池名称的线程池是同一个,如果不配置,默认为分组名 	 	 	 	4.HystrixThreadPoolProperties:线程池的配置, 	 		coreSize配置核心线程池的大小, 	 		maxQueueSize线程池队列的最大大小, 	 		queueSizeRejectionThreshold,限制当前队列的大小, 	 		实际队列大小由这个参数决定,即到达队列里面条数到达10000,则都会被拒绝。 	 		 	 	5.HystrixCommandProperties:配置命令的一些参数, 	 		如executionIsolationStrategy,配置执行隔离策略,默认是使用线程隔离,THREAD即为线程池隔离, 	 		 	 		ExecutionIsolationThreadInterruptOnTimeout 使用线程隔离时,是否对命令执行超时的线程调用中断操作.默认:true 	 		和ExecutionTimeoutInMilliseconds配置了启用超时和最大执行时间,这里为3s, 	 		 	 		circuitBreakerErrorThresholdPercentage失败率配置,默认为50%, 	 		这里配置的为25%,即失败率到达25%触发熔断 	 */ 	 } 

简单例子5:

package com.book.web.test.hystrix;  import java.util.concurrent.TimeUnit;  import com.netflix.hystrix.HystrixCommand; import com.netflix.hystrix.HystrixCommandGroupKey; import com.netflix.hystrix.HystrixCommandKey; import com.netflix.hystrix.HystrixCommandProperties; import com.netflix.hystrix.HystrixThreadPoolKey; import com.netflix.hystrix.HystrixThreadPoolProperties;  /**  * 测试4-熔断测试  * @author liweihan  *  */ public class CommandHelloWorld5 extends HystrixCommand<String>{ 	private Integer id; 	 	public CommandHelloWorld5(Integer id) { 		super(setter()); 		this.id = id; 	} 	 	private static Setter setter() { 		return ApiSetter.setter("getNum"); 				 	}  	@Override 	protected String run() throws Exception { 		if (id % 2 == 0 && id <= 10) { //让小于等于10的偶数返回 			return "running run():" + id; 		} else { //让奇数或大于10的数进入fallback 			TimeUnit.MILLISECONDS.sleep(200); 			return  " XXX "; 		} 	} 	 	@Override 	protected String getFallback() { 		return " ====== CircuitBreaker fallback" + id + " ,是否进入熔断:" + super.isCircuitBreakerOpen(); 	} 	 	public static void main(String[] args) throws Exception { 		for(int i = 0; i < 30; i++) { 			System.out.println(new CommandHelloWorld5(i).execute()); 			/*Future<String> future =  new CommandHelloWorld5(i).queue();         	System.out.println(future.get());*/     	} 	} 	 	private static class ApiSetter {  	    public static Setter setter(String commandKeyName,String threadPoolKeyName) { 	        return setter("ApiGroup",commandKeyName,threadPoolKeyName); 	    }  	    public static Setter setter(String commandKeyName) { 	        return setter(commandKeyName,"Api-Pool"); 	    }  	    /** 	     * @author liweihan 	     * @time 2017/12/20 16:57 	     * @description     相关参数设置 	     * @param groupKeyName      服务分组名 	     * @param commandKeyName    服务标识名称 	     * @param threadPoolKeyName 线程池名称 	     * @return 	     */ 	    public static Setter setter(String groupKeyName,String commandKeyName,String threadPoolKeyName) { 	        //服务分组 	        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(groupKeyName); 	        //服务标识 	        HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(commandKeyName); 	        //线程池名称 	        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey(threadPoolKeyName); 	        //线程配置 	        HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter() 	        		//设置核心线程池的大小,默认为10 	                .withCoreSize(25) 	                 	                //设置存活时间,单位分钟。如果coreSize小于maximumSize,那么该属性控制一个线程从实用完成到被释放的时间。默认为1 	                .withKeepAliveTimeMinutes(5) 	                 	                //设置BlockingQueue最大的队列值,默认值为-1 	                .withMaxQueueSize(Integer.MAX_VALUE) 	                 	                //设置队列拒绝的阈值——一个为设置的拒绝访问的最大队列值,即使maxQueueSize还没有达到。 	                //当将一个线程放入队列等待执行时,HystrixCommand使用该属性 	                //注意:如果maxQueueSize设置为-1,该属性不可用 ,默认为5 	                .withQueueSizeRejectionThreshold(10000);  	        //命令属性的配置 	        HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter() 	                .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD) 	                //设置HystrixCommand.run()的执行是否有超时限制。默认是true 	                .withExecutionTimeoutEnabled(true) 	                 	                //使用线程隔离时,是否对命令执行超时的线程调用中断(Thread.interrupt())操作,默认是:true 	                //即:设置HystrixCommand.run()的执行是否在超时发生时被中断。 	                .withExecutionIsolationThreadInterruptOnTimeout(true)  	                 	                //设置调用者等待命令执行的超时限制,超过此时间,HystrixCommand被标记为TIMEOUT,并执行回退逻辑。默认是1000ms 	                //注意:超时会作用在HystrixCommand.queue(),即使调用者没有调用get()去获得Future对象。 	                .withExecutionTimeoutInMilliseconds(100)  	                 	                //使用线程隔离时,调用超时时间,默认:1秒  ,该方法已经不建议使用! //	                .withExecutionIsolationThreadTimeoutInMilliseconds(3000) 	                 	                //失败率达到20%熔断器启动,默认值是50 	                .withCircuitBreakerErrorThresholdPercentage(20) 	                 	                // 置为true时,所有请求都将被拒绝,直接到fallback 	                //.withCircuitBreakerForceOpen(true) 	                 	                //10秒内请求超过5个的话才会启动熔断器, 	                //熔断器在设置在一个滚动窗口中,打开断路器的最少请求数。 	                //默认20。也就是10秒钟内至少请求20次,熔断器才发挥起作用 , 	                //比如:如果值是20,在一个窗口内(比如10s),收到19个请求,即使这19个请求都失败了,熔断器也不会打开 	                //.withCircuitBreakerRequestVolumeThreshold(5) 	                 	                //是否启用熔断器,默认true. 启动  	                .withCircuitBreakerEnabled(true)  	                 	                //设置HystrixCommand.getCacheKey()是否启用, 	                //由HystrixRequestCache通过请求缓存提供去重复数据功能[默认为true] 	                .withRequestCacheEnabled(false) 	                ;  	        //返回 	        return HystrixCommand.Setter 	                .withGroupKey(groupKey) 					.andCommandKey(commandKey) 	                .andThreadPoolKey(threadPoolKey) 	                .andThreadPoolPropertiesDefaults(threadPoolProperties) 	                .andCommandPropertiesDefaults(commandProperties); 	    } 		 		/** 		 * ☆参数说明: 		 	1.HystrixCommandGroupKey:服务分组,以上pydyn分组就包括多个服务,必填选项 		 	 		 	2.HystrixCommandKey:服务的名称,唯一标识,如果不配置,则默认是类名 		 	 		 	3.HystrixThreadPoolKey:线程池的名称,相同线程池名称的线程池是同一个,如果不配置,默认为分组名 		 	 		 	4.HystrixThreadPoolProperties:线程池的配置, 		 		coreSize配置核心线程池的大小, 		 		maxQueueSize线程池队列的最大大小, 		 		queueSizeRejectionThreshold,限制当前队列的大小, 		 		实际队列大小由这个参数决定,即到达队列里面条数到达10000,则都会被拒绝。 		 		 		 	5.HystrixCommandProperties:配置命令的一些参数, 		 		如executionIsolationStrategy,配置执行隔离策略,默认是使用线程隔离,THREAD即为线程池隔离, 		 		 		 		ExecutionIsolationThreadInterruptOnTimeout 使用线程隔离时,是否对命令执行超时的线程调用中断操作.默认:true 		 		和ExecutionTimeoutInMilliseconds配置了启用超时和最大执行时间,这里为3s, 		 		 		 		circuitBreakerErrorThresholdPercentage失败率配置,默认为50%, 		 		这里配置的为25%,即失败率到达25%触发熔断 		 */ 		 	} } 

参考:

一、使用Netflix Hystrix编写弹性可容错的应用程序
http://blog.csdn.net/wsscy2004/article/details/50166267

二、Hystrix 使用与分析
http://blog.csdn.net/xiaoyu411502/article/details/50601687

<1.>参考
https://www.ihnbc.cn/

Hystrix使用入门手册
http://www.jianshu.com/p/b9af028efebb

使用Hystrix实现隔离
http://zhuanlan.51cto.com/art/201704/536307.htm

相关属相设置
http://www.jianshu.com/p/39763a0bd9b8

三、git地址
https://github.com/Netflix/Hystrix/wiki/Getting-Started

本文发表于2017年12月22日 00:33
(c)注:本文转载自https://my.oschina.net/hanchao/blog/1593340,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 1875 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1