Hystrix设计原则和目的以及资源隔离

                1.Hystrix是什么?

                            在分布式系统中,每个服务都可能会调用很多其他的服务,被调用的那些服务就是依赖服务,依赖服务出现一些故障是很正常的,因为不能保障100%的可用性。hystrix可以让我们在分布式系统中对服务间的调用进行控制,加入一些调用延迟或者依赖故障的容错机制。Hystrix通过将依赖服务进行资源隔离,当某个依赖服务出现故障的时候,防止故障在整个系统的依赖服务中蔓延,同时Hystrix还提供了fallback降级机制。(Hystrix保护系统高可用主要通过一下几点:资源隔离、限流、熔断、限流、运维监控)。


2.Hystrix的设计原则

                                1.对依赖服务调用时出现的延迟和失败进行容错保护。

                                2.在复杂的分布式系统中,阻止某一个依赖服务的故障在整个系统中蔓延

                                3.提供fall-fast(快速失败)和快速恢复的支持

                                4.提供fallback优雅的降级的支持

                                5.支持近实时的监控、报警一级运维操作


               3.Hystrix是如何实现的?

                                1.通过hystrixCommand或者HystrixObservableCommand来封装对外部依赖的访问请求,这个访问请求一般会运行在独立的线程中。

                                   

                                2.对于超出我们设定的阈(yu)值服务调用,直接进行超时返回,不允许它长时间的阻塞。

                                3.对每一个依赖服务进行资源隔离。通过线程池或者是semaphore这两种方式。

                                4.对依赖服务被调用的成功次数,失败次数,拒绝次数,超时次数进行统计。

                                5.如果对某一个依赖服务的调用失败次数超过了一点的阈值,Hystrix自动进行熔断,并在一段时间内对该服务的调用直接进行降级,一段时间后再自动尝试恢复

                                6.当对一个服务调用出现失败、被拒绝、超时、短路等异常情况时,自动调用fallback降级机制

                                7.对属性和配置的修改提供近实时的支持

              4.在eclipse中导入Hystrix的依赖(基于Spring boot)

导入依赖及可,如果下载不了,可以去maven中央仓库下载( http://mvnrepository.com/artifact/com.netflix.hystrix/hystrix-core/1.5.12
                                <dependency>
					<groupId>com.netflix.hystrix</groupId>
					<artifactId>hystrix-core</artifactId>
					<version>1.5.12</version>
				</dependency>

                                服务接口故障高并发情况下服务资源耗尽的场景

                               1.假设服务部署在tomcat服务器上,线程资源有50个,上面有多个服务,假设其中一个服务故障了,10个线程去调用这个服务,阻塞在了那,或出现了很长的延迟,高并发情况下,大量请求的涌入,导致tomcat服务器将大量的线程都去调用这个服务,都阻塞在了那。这个时候,调用一些其他服务的接口,这个时候,你的缓存服务就没有足够的线程去调用了。


解决方式:资源隔离
                                你调用服务的时候,不能在赤裸裸的直接调用了。应将服务接口调用的逻辑进行封装。

                               Hystrix 进行资源隔离的方法,其实是提供了一个command的抽象,你将对一个依赖服务的所有调用请求,全部隔离在同一份资源池内,对这个依赖服务的所有调用请求,全部走这个资源池的资源。(有两种方式,一种是线程池,一种是信号量)。

                                        线程池隔离技术:
                               对一个依赖服务,所有的调用请求,全部隔离到一个线程池内,对商品服务的每次调用请求都封装到一个command里面,每个command(每次服务调用请求)都是使用线程池内的一个线程去执行的。比如,对某个服务的请求并发量达到了100,线程池里面只有10个线程,那么最多只有这10个线程去执行。


1.HystrixCommand。简单的一个demo,这时用来获取一条数据的
                                public String changeProduct(Long productId){
					HystrixCommand<ProductInfo> productInfoCommand = new ProductInfoCommand(productId); 
					//当代码执行execute时,会尝试将productInfoCommand扔到ProductInfoCommandGroup(对应一个线程池)这个线程池中
					//用线程池里面的一个线程去执行run方法。
					ProductInfo productInfo =productInfoCommand.execute();
					System.out.println(productInfo);
					return "success";
				}

                                package com.hystrix.command;
				import com.alibaba.fastjson.JSONObject;
				import com.hystrix.model.ProductInfo;
				import com.netflix.hystrix.HystrixCommand;
				import com.netflix.hystrix.HystrixCommandGroupKey;

				public class ProductInfoCommand extends HystrixCommand<ProductInfo> {
				private Long productId;
                                public ProductInfoCommand(Long productId){
				super(HystrixCommandGroupKey.Factory.asKey("ProductInfoCommandGroup"));
				this.productId=productId;
				}

				//这里应该根据productId去进行查询,不过为了简单,直接用JSON数据
				@Override
				protected ProductInfo run() throws Exception {
					String productInfo = "{\"id\": " + productId + ", \"name\": \"iphone7手机\", \"price\": 5599, \"pictureList\":\"a.jpg,b.jpg\", \"specification\": \"iphone7的规格\", \"service\": \"iphone7的售后服务\", \"color\": \"红色,白色,黑色\", \"size\": \"5.5\", \"shopId\": 1, \"modifiedTime\": \"2017-01-01 12:00:00\"}";
					return JSONObject.parseObject(productInfo,ProductInfo.class);F
					}
				}

                                    2.HystrixObservableCommand:是设计用来获取多条数据的

                        

                                @RequestMapping("/productInfoBatch")
				@ResponseBody
				public String productInfoBatch(String productIds){
				HystrixObservableCommand<ProductInfo> productInfoBatchCommand = 
						new ProductInfoBatchCommand(productIds.split(",")); 
				Observable<ProductInfo> observable=productInfoBatchCommand.observe();
				observable.subscribe(new Observer<ProductInfo>(){

				        @Override
					public void onCompleted() {
					// 得到了所有要查询的商品的信息
												
				        }
				        @Override
				        public void onError(Throwable e) {
				        // TODO Auto-generated method stub
					e.printStackTrace();
				        }
				        @Override
				        public void onNext(ProductInfo productInfo) {
				            // 接口回调
					    System.out.println(productInfo);
				        }
				});
					return "success";
				}

                                package com.hystrix.command;
				import com.alibaba.fastjson.JSONObject;
				import com.hystrix.model.ProductInfo;
				import com.netflix.hystrix.HystrixCommand;
				import com.netflix.hystrix.HystrixCommandGroupKey;

				public class ProductInfoCommand extends HystrixCommand<ProductInfo> {

					private Long productId;				
					public ProductInfoCommand(Long productId){
						super(HystrixCommandGroupKey.Factory.asKey("ProductInfoCommand"));
						this.productId=productId;
					}
					@Override
					protected ProductInfo run() throws Exception {
						String productInfo = "{\"id\": " + productId + ", \"name\": \"iphone7手机\", \"price\": 5599, \"pictureList\":\"a.jpg,b.jpg\", 
                                                \"specification\": \"iphone7的规格\", \"service\": \"iphone7的售后服务\", \"color\": \"红色,白色,黑色\", \"size\": \"5.5\", \"shopId\": 1, \"modifiedTime\": \"2017-01-01 12:00:00\"}";
						return JSONObject.parseObject(productInfo,ProductInfo.class);
					}
				}

                    1.command的四种调用方式
    同步:new CommandCache(args).execute()
     注:如果你认为observable command只会返回一条数据,那么也可以调用上面的模式,去同步执行,返回一条数据
     new ObservableCommandCache(args).toBlocking.toFuture().get()
         异步:new CommandCache(args).queue()  
     对Command调用queue(),仅仅将command放入线程池的一个等待队列,就立即返回,拿到一个Future对象,后面可以执行其他的代码,然后过一段时间对future调用ger()方法获取数据,这个future就是JDK并发包里面的那个Future
      Future future = ProductInfoCommand.queue();
     new  ObservableCommandCache(args).toBlocking.toFuture()
      同理
    立即执行:Observable<String> f = new CommandCache(args).observe()
            立即执行construct方法去拿到所有的结果
    延迟执行:Observable<String> f = new ObservableCommandCache(agrs).toObservable()
          f.subscribe(new Observer<String>(){
     public void onCompleted(){


}
public void onError(){
e.printStackTrace();
}
public void onNext(){
 
}
    });

         默认的线程池大小是10个,即使服务接口故障了,最多只有10个线程会hang死,而对其他的线程无影响

                         //下一篇再讲解信号量以及信号量和线程池实现资源隔离的区别


猜你喜欢

转载自blog.csdn.net/qq_40280705/article/details/80471897