精华内容
下载资源
问答
  • Hystrix简单实现

    2019-11-22 16:30:43
    这次要简单实现Hystrix功能,在上篇博客的基础上改动几步就好了。 这里先简单说下自己Hystrix的理解: 它就和我们平时的生活中的断路器一样,每当线路中有电路发生短路时,为了防止危害,断路器就会开启来切断故障...

    项目结构可参考:上一篇博客

    这次要简单实现Hystrix功能,在上篇博客的基础上改动几步就好了。

    这里先简单说下自己对Hystrix的理解:

    它就和我们平时的生活中的断路器一样,每当线路中有电路发生短路时,为了防止危害,断路器就会开启来切断故障电路,它对电路起到了一种保护作用。同理,在微服务中,每个服务之间会相互调用,比如订单服务调用库存服务,如果在订单服务在调用库存服务时,库存服务发生故障,那么请求就会进入长时间的等待,长时间等待后,才会出现请求库存服务失败,进而创建订单失败结果。那么如果是在高并发的场景下,库存服务出现故障,会导致大量线程被占用而无法释放,越来越多的请求会被阻塞,最后会导致订单服务也不可用。如果服务的调用链路比较长的话,那么下游服务的故障就会渐渐的影响到上游的所有服务,导致服务雪崩。

    所以这时引入Hystrix(熔断器)来解决上述情况,当确定服务发生故障时,我们可以采用服务熔断和服务降级,设置降级的处理方式,这样上游服务在下游服务出现故障时,就不用长时间的等待下去,可以回调降级方法,及时给用户响应。更重要的是,它解决了可能出现的服务雪崩现象,维持了整个微服务的稳定性通知。当然Hystrix不止只有服务熔断,服务降级的功能,它还具备其他的类似请求缓存,请求合并等功能。

    • 服务熔断:这里要特别说下服务熔断,服务熔断有3种状态,分别是开启,关闭,半熔断,默认是关闭
    • 开启:在调用下游服务时,在规定的时间内,Hystrix默认是10秒,调用出错的比例达到一定得阈值,就会开启Hystrix,之后调用服务时都会调用降级方法。
    • 关闭:关闭就代表着服务是正常的,Hystrix不做任何限制。
    • 半熔断:为什么还会有这个状态,要知道,我们熔断器不可能是永久的,要是永久的话,那下游服务就没意义了,所以在开启Hystrix一段时间后,默认是5秒,Hystrix会进入
      半熔断的状态,它会尝试性的去调用被熔断的这个接口,如果成功率达标,那么就关闭Hystrix,正常调用服务,不再调用降级方法,反之则继续开启Hystrix。

    下面就是简单的Hystrix使用demo:

    首先导入Hystrix依赖:

       <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            </dependency>
    

    其次在spring boot启动类上增加注解@EnableCircuitBreaker开启熔断器:

    @EnableEurekaClient
    @SpringBootApplication
    @EnableCircuitBreaker
    public class RibbonClientApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(RibbonClientApplication.class, args);
        }
    
    }
    

    最后在调用的服务方法上增加@HystrixCommand(fallbackMethod = “fallback”),fallbackMethod里的值表示在该方法调用服务失败后,回滚调用的方法:

    @Service
    public class RibbonService {
        @Autowired
        private RestTemplate restTemplate;
    
        @HystrixCommand(fallbackMethod = "fallback")
        public String helloRibbon(String name) {
            return restTemplate.getForObject("http://eureka-client/helloWorld/" + name, String.class);
        }
    
        /**
         * 调用helloRibbon失败后的降级方法
         *
         * @param name
         * @return
         */
        public String fallback(String name) {
            return "error" + name;
        }
    }
    

    服务正常调用情况如图:
    在这里插入图片描述
    在这里插入图片描述

    断掉端口为8762的服务,效果如图:
    在这里插入图片描述
    在这里插入图片描述
    可以看到在8762端口的服务断掉后,我们调用时,页面并没有返回错误,而是给了我们降级方法的返回响应。这就说明Hystrix已经起到了作用。

    展开全文
  • Hystrix实现容错

    2018-06-02 20:16:20
    客户端整合Hystrix实现容错,通过简单地配置,为系统保驾护航
  • 保障 hystrix简单实现
  • 微服务(服务发现组件Eureka-负载均衡Ribbon-REST调用Feign-实现容错Hystrix) 简介: microservice-eureka-ribbon-feign-hystrix-demo 服务提供者:microservice-simple-provider-user(用户个人信息) 服务提供者...
  • 微服务实现请求合并(Hystrix)

    千次阅读 2019-01-26 23:02:41
    2 注解方式实现HystrixCommand 2.1 Consumer引入POM 2.2 编写请求合并代码  2.3 Consumer启动类&amp;配置 2.4 Provider服务详解 3 继承方式实现HystrixCommand 3.1 Consumer侧服务层支持批量请求 3.2 ...

    目录

    1 请求合并架构

    2 注解方式实现HystrixCommand

    2.1 Consumer引入POM

    2.2 编写请求合并代码

     2.3 Consumer启动类&配置

    2.4 Provider服务详解

    3 继承方式实现HystrixCommand

    3.1 Consumer侧服务层支持批量请求

    3.2 Consumer侧继承HystrixCommand

    3.3 Consumer侧继承HystrixCollapser

    3.4 Consumer侧Controller提供调用接口

    3.5 测试


    1 请求合并架构

    Consumer服务为避免大并发请求Provider服务,造成Provider服务器压力过大,进而导致Prvoider服务雪崩,故在Consumer服务侧采取请求合并策略,将一定时间内的请求进行合并,一次访问Provider获取数据。如下图形象的描述了请求合并的机制:

    2 注解方式实现HystrixCommand

    Hystrix提供了两种(注解、继承)方式来实现请求合并,本章以注解的方式来优雅的实现请求合并功能。

    2.1 Consumer引入POM

    主要引入Hystrix的依赖

                    <dependency>
    			<groupId>org.springframework.cloud</groupId>
    			<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    		</dependency>

    2.2 编写请求合并代码

    在BookService类中为getBook方法编写一个请求合并的代码getBookList,根据HystrixProperty属性设置将5s内的请求进行合并处理,且每次最大请求数量为200。另外,需要Provider服务支持http://localhost:9092/batchgetbook?ids=1,2  类型的请求。

    
    @Service
    public class BookService {
    	
    	@Autowired
    	private RestTemplate restTemplate;
    	
    	@Autowired
    	private LoadBalancerClient loadBalancerClient;
    	
    	/**
    	 * 可异步
    	 * */
    	@HystrixCollapser(batchMethod = "getBookList", scope=com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL,
    			collapserProperties={
    			//请求时间间隔在5s之内的请求会被合并为一个请求,为方便手动测试,将两个浏览器的请求进行合并,将时间设置得比较大,实际中
    			//需要设置得少,避免拉长每个请求的响应
    			@HystrixProperty(name="timerDelayInMilliseconds", value="5000"),
    			//在批处理中允许的最大请求数
    			@HystrixProperty(name="maxRequestsInBatch",value="200"),			
    	})
    	public Future<Book> getBook(Integer id){
    		System.out.println("============"+id);
    		return null;
    	}
    	
    	@HystrixCommand (commandProperties={
    			@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "4000")
    	})
    	public List<Book> getBookList(List<Integer> ids) {
    		System.out.println("====================get BookList===== " + ids);
    		
    		ServiceInstance si=loadBalancerClient.choose("bookshop-service-provider");
    		StringBuffer sb=new StringBuffer("");
    		sb.append("http://");
    		sb.append(si.getHost());
    		sb.append(":");
    		sb.append(si.getPort());
    		sb.append("/batchgetbook");
    		sb.append("?ids="+StringUtils.join(ids,","));
    		System.out.println(sb.toString());
    		
    		/**
    		 *封装返回对象为List<Book> 
    		 **/
    		ParameterizedTypeReference<List<Book>> responseType = new ParameterizedTypeReference<List<Book>>(){};
    		ResponseEntity<List<Book>> result = restTemplate.exchange(sb.toString(),HttpMethod.GET, null,responseType);
    		System.out.println("xxxxx :" +result.getStatusCode());
    		return result.getBody();		
    	
    	}
    
    }

    参数解释:

    请求合并参数
    参数作用默认值备注
    @HystrixCollapser  被@HystrixCollapser标注的方法,返回类型必须为Future,使用异步方法,否则无法进行请求合并.
    batchMethod请求合并的方法 方法只能接受一个参数,如果需要传递多个参数,封装成一个类参数
    scope请求范围REQUEST请求方式:分为REQUEST,GLOBAL
    REQUEST范围只对一个request请求内的多次服务请求进行合并。
    GLOBAL是应用中的所有线程的请求中的多次服务请求进行合并.
    timeDelayinMilliseconds请求时间间隔在10ms之内的请求会被合并为一个请求10ms建议尽量设置得小一点,如果并发量不大,没必要使用HystrixCollapser来处理.
    maxRequestsInBatch设置触发批处理执行之前,在批处理中允许的最大请求数Integer.MAX_VALUE 

     2.3 Consumer启动类&配置

    在启动类中启动Hystrix熔断和EurekaClient,启动Eureka主要是访问Provider提供的服务。

    @SpringBootApplication
    @EnableCircuitBreaker
    @EnableEurekaClient
    
    public class BookshopConsumerHystrixBatchApplication {
    	
    	@Bean
    	public RestTemplate createRt() {
    		return new RestTemplate();
    	}
    
    	public static void main(String[] args) {
    		SpringApplication.run(BookshopConsumerHystrixBatchApplication.class, args);
    	}
    
    }

    2.4 Provider服务详解

    Provider服务利用Feign和Eureka搭建出业务平台。此处简单的介绍其实现:由Controller API,Provider Service组成,Controller API设定每个请求的参数和请求方式以及Entity,Provider Service实现Controller API。(具体的实现架构可参见声明式服务调用的实现(Feign)及其优化(Ribbon)

    Controller API主要代码(未包含Book Entity):本次Consumer主要调用的是List<Book> batchGetBook(@RequestParam("ids") String ids)方法。

    package bookshop.api.controller;
    
    import java.util.List;
    
    import org.springframework.http.MediaType;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    
    import bookshop.api.entity.Book;
    
    
    public interface BookController {
    	
    	
    	@GetMapping(value="/getbooklist")
    	public List<Book> getBookList();
    
    	
    	@RequestMapping(value="/get",method=RequestMethod.GET)
    	public Book getBook(@RequestParam("id") Integer id);
    	
    	/**
    	 * 获取多参数的访问
    	 * */
    	//@RequestMapping(value="/getbook",method=RequestMethod.GET)未引入feign httpclient
    	@RequestMapping(value="/getbook",method=RequestMethod.GET,consumes=MediaType.APPLICATION_JSON_VALUE)
    	public Book getBook(Book book);
    	
    	
    	/**
    	 * id=1&bookName=abc&author=xiaoming
    	 * */
    	@RequestMapping(value="/getbook2",method=RequestMethod.GET)
    	public Book getBook(@RequestParam("id") Integer id, @RequestParam("bookName") String bookName, @RequestParam("author") String author);
    	
    	@RequestMapping(value="/addbook",method=RequestMethod.POST)
    	public Book addBook(@RequestBody Book book);
    	
    	/**
    	 * 用来接收批量处理的请求.
    	 * */
    	@RequestMapping(value="/batchgetbook", method=RequestMethod.GET)
    	public List<Book> batchGetBook(@RequestParam("ids") String ids);
    }
    

    Provider Controller具体实现上述BookController类,主要代码如下:

    package com.bookshop.provider.controller;
    
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    import bookshop.api.controller.BookController;
    import bookshop.api.entity.Book;
    
    
    @RestController
    public class BookControllerImp implements BookController {
    
    	@Override
    	public List<Book> getBookList() {
    		System.out.println("======================"+new Date());
    		try {
    			Thread.sleep(6000);
    		} catch (InterruptedException e) {
    			
    			e.printStackTrace();
    		}
    		
    		List<Book> list =  new ArrayList<Book>();
    		Book book = new Book();
    		book.setAuthor("小明");
    		book.setBookName("小明自传");
    		list.add(book);
    		return list;
    	}
    
    	@Override
    	public Book getBook(Integer id) {
    		Book book = new Book();
    		book.setId(id);
    		book.setAuthor("小明");
    		book.setBookName("小明自传");
    		return book;
    	}
    
    	@Override
    	//public Book getBook(Book book) {
    	public Book getBook(@RequestBody Book book) {
    		return book;
    	}
    
    	@Override
    	public Book getBook(Integer id, String bookName, String author) {
    		Book book = new Book();
    		book.setId(id);
    		book.setAuthor(author);
    		book.setBookName(bookName);
    		return book;
    	}
    
    	@Override
    	public Book addBook(@RequestBody Book book) {
    		return book;
    	}
    
    	@Override
    	public List<Book> batchGetBook(String ids) {
    		
    		List<Book> bookList = new ArrayList<Book>();
    		String idArray[] = ids.split(","); 
    		for (int i=0; i<idArray.length; i++) {
    			Book book = new Book();
    			book.setId(Integer.valueOf(idArray[i]));
    			book.setAuthor("Author" + idArray[i]);
    			book.setBookName("BookName"+idArray[i]);
    			bookList.add(book);
    		}
    		return bookList;
    	}		
    
    }
    

    3 继承方式实现HystrixCommand

    3.1 Consumer侧服务层支持批量请求

    需要提供支持批量访问Provider Service接口的服务层,用来向Provider Service发送批量参数。如http://localhost:9092/batchgetbook?ids=2,3发送批量参数ids给provider接口。具体实现如下:

    package com.bookshop.consumer.batch.service;
    
    import java.util.List;
    
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.client.ServiceInstance;
    import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
    import org.springframework.core.ParameterizedTypeReference;
    import org.springframework.http.HttpMethod;
    import org.springframework.http.ResponseEntity;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
    
    import bookshop.api.entity.Book;
    
    @Service
    public class BookBatchCommandService {
    	
    	@Autowired
    	private RestTemplate restTemplate;
    	
    	@Autowired
    	private LoadBalancerClient loadBalancerClient;
    
    	
    	public List<Book> getBookList(List<Integer> ids) {
    		System.out.println("====================get BookList===== " + ids);
    		
    		ServiceInstance si=loadBalancerClient.choose("bookshop-service-provider");
    		StringBuffer sb=new StringBuffer("");
    		sb.append("http://");
    		sb.append(si.getHost());
    		sb.append(":");
    		sb.append(si.getPort());
    		sb.append("/batchgetbook");
    		sb.append("?ids="+StringUtils.join(ids,","));
    		System.out.println(sb.toString());
    		
    		/**
    		 *封装返回对象为List<Book> 
    		 **/
    		ParameterizedTypeReference<List<Book>> responseType = new ParameterizedTypeReference<List<Book>>(){};
    		ResponseEntity<List<Book>> result = restTemplate.exchange(sb.toString(),HttpMethod.GET, null,responseType);
    		System.out.println("xxxxx :" +result.getStatusCode());
    		return result.getBody();		
    	
    	}
    	
    }
    

    3.2 Consumer侧继承HystrixCommand

    利用继承HystrixCommand方式实现熔断,其run方法调用BookBatchCommandService中的批量访问Provider方法,具体代码如下清单:

    package com.bookshop.consumer.batch.command;
    
    import java.util.List;
    
    
    
    
    
    
    import com.bookshop.consumer.batch.service.BookBatchCommandService;
    import com.netflix.hystrix.HystrixCommand;
    import com.netflix.hystrix.HystrixCommandGroupKey;
    import com.netflix.hystrix.HystrixCommandProperties;
    
    import bookshop.api.entity.Book;
    
    public class BookBatchCommand extends HystrixCommand<List<Book>> {    //List<Book>为返回的数据类型
    	
    	private List<Integer> ids;
    	private BookBatchCommandService bookcmdservice;
    
    	protected BookBatchCommand(BookBatchCommandService bookcmdservice, List<Integer> ids) {
    		super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("BookBatchCommand"))
    				.andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionIsolationThreadTimeoutInMilliseconds(4000)));
    		
    		this.ids = ids;
    		this.bookcmdservice = bookcmdservice;
    
    	}
    
    	@Override
    	protected List<Book> run() throws Exception {
    		return bookcmdservice.getBookList(ids); //调用BookBatchCommandService中的getBookList()方法
    	}
    
    }
    

    3.3 Consumer侧继承HystrixCollapser

    用继承HystrixCollapser方式实现将一定时间窗口内的多个单独请求装载成一个批量请求并将批量请求获取的返回数据拆分到每个单独的请求中。其具体实现如下代码清单以及注释说明:

    package com.bookshop.consumer.batch.command;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;
    import java.util.stream.Collectors;
    
    import bookshop.api.entity.Book;
    
    import com.bookshop.consumer.batch.service.BookBatchCommandService;
    import com.netflix.hystrix.HystrixCollapser;
    import com.netflix.hystrix.HystrixCollapserKey;
    import com.netflix.hystrix.HystrixCollapserProperties;
    import com.netflix.hystrix.HystrixCommand;
    
    public class BookCommandCollapser extends HystrixCollapser<List<Book>,Book,Integer> {  //三个参数,分别是批量的数据返回类型,单个请求的返回类型,单个请求的参数类型
    	
    	private Integer bookId;
    	private BookBatchCommandService bookcmdservice;
    	
    	public BookCommandCollapser(BookBatchCommandService bookcmdservice, Integer bookId) {
    		
    		super(Setter.withCollapserKey(HystrixCollapserKey.Factory.asKey("BookCommandCollapser"))
                    .andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter().withTimerDelayInMilliseconds(5000))  
                     //为请求合并器设置了时间延迟属性,合并器会在该时间窗内收集获取单个Book的请求并在时间窗结束时进行合并组装成一个批量请求
                    .andScope(Scope.GLOBAL));
    		         //global context  作用于容器内所有调用线程,对一个依赖服务的任何一个command调用都被合并在一起,hystrix就传递一个HystrixRequestContext 
    		         //user request context 作用于容器内某一个调用线程,将某一个线程对某个依赖服务的多个command调用合并在一起
    		         //默认是REQUEST,就是不会跨越多个请求会话的,只在当前用户请求中合并多次请求为批处理请求
    		
    		
    		
    		this.bookId = bookId;
    		this.bookcmdservice = bookcmdservice;
    		
    	}
    
    	/**
    	 * 返回单个请求的参数booId
    	 * */
    	@Override
    	public Integer getRequestArgument() {
    		
    		return bookId;
    	}
    
    	/**
    	 * CollapsedRequest参数中保存了延迟时间窗中收集到的所有获取单个Book的请求。
    	 * 通过获取这些请求的参数来组织批量请求命令 
    	 **/
    	@Override
    	protected HystrixCommand<List<Book>> createCommand(
    		Collection<com.netflix.hystrix.HystrixCollapser.CollapsedRequest<Book, Integer>> requests) {
    		List<Integer> Ids = new ArrayList<>(requests.size());
    		Ids.addAll(requests.stream().map(CollapsedRequest::getArgument).collect(Collectors.toList()));
    		System.out.println(Ids.toString()  +"   " + Ids.size());
    		return new BookBatchCommand(bookcmdservice,Ids);	
    	}
    
    	
    	/**
    	 *通过遍历批量结果batchResponse对象,为CollapsedRequest中每个合并前的单个请求设置返回结果
    	 *以此完成批量结果到单个请求结果的转换。 
    	 **/
    	@Override
    	protected void mapResponseToRequests(
    		List<Book> batchResponse,
    		Collection<com.netflix.hystrix.HystrixCollapser.CollapsedRequest<Book, Integer>> requests) {
    		int count = 0;
    		for(com.netflix.hystrix.HystrixCollapser.CollapsedRequest<Book, Integer> collapsedRequest : requests) {
    			Book book = batchResponse.get(count++);
    			collapsedRequest.setResponse(book);
    			
    		}		
    	}
    }
    

    3.4 Consumer侧Controller提供调用接口

    Controller侧调用上述实现的BookCommandCollapser类,该类必须new一个实例,不能是单例。

    package com.bookshop.consumer.batch.controller;
    
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.Future;
    
    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.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    import bookshop.api.entity.Book;
    
    import com.bookshop.consumer.batch.command.BookCommandCollapser;
    import com.bookshop.consumer.batch.service.BookBatchCommandService;
    import com.bookshop.consumer.batch.service.BookService;
    import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
    
    
    @RestController
    public class BookController {
    
    	@Autowired
    	private BookService bookservice;
    	
    	@Autowired
    	private BookBatchCommandService bookcmdservice;
    	
    	
    	@RequestMapping(value="getBook",method=RequestMethod.GET)
    	public Book batchGetBook(@RequestParam Integer id) {
    		
    		try {
    			return bookservice.getBook(id).get();
    		} catch (InterruptedException | ExecutionException e) {
    			e.printStackTrace();
    			return null;
    		}		
    	}
    	
    	
    	@RequestMapping(value="getBook2",method=RequestMethod.GET)
    	public Book getBook(@RequestParam Integer id) {
    		HystrixRequestContext context = HystrixRequestContext.initializeContext();   //需要初始化Context,否则可能报错...
    		Future<Book> f1= new BookCommandCollapser(bookcmdservice,id).queue();
    		//Future<Book> f2= new BookCommandCollapser(bookcmdservice,2).queue();
    		//Future<Book> f3= new BookCommandCollapser(bookcmdservice,3).queue();   
    		//上述注解的f2,f3是在HystrixCollapser的scope=REQUEST情况下做的测试,即:不会跨越多个请求会话的,只在当前用户请求中合并多次请求为批处理请求
    		try {
    			//f2.get();
    			//f3.get();
    			return f1.get();
    		} catch (InterruptedException | ExecutionException e) {
    			// TODO Auto-generated catch block
    			return null;
    		} finally{
    			context.close();
    		}
    	}
    	
    }
    

    3.5 测试

    运行Provider,Eureku,Consumer,在窗口时间内用浏览器发送两个请求(http://localhost:9099/getBook2?id=1http://localhost:9099/getBook2?id=2),后台窗口会打印出如下消息,说明请求进行了合并。

     

     

     

     

     

    展开全文
  • hystrix:超时熔断,个人感觉理解就像是trycatch一样,当出现异常,需要怎么处理的一种机制。 1.新建项目:ms-hystrix-consumer 1.pom文件: <!-- 注册eureka --> <dependency> <groupId>...

    hystrix:超时熔断,个人感觉理解就像是trycatch一样,当出现异常,需要怎么处理的一种机制。

    1.新建项目:ms-hystrix-consumer

    1.pom文件:

        <!-- 注册eureka -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
            <!-- 打印日志 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
            <!--  web-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!-- feigin的依赖 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-feign</artifactId>
            </dependency>
           <!-- hystrix 的依赖  -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            </dependency>
            <!--hystrix command -->
            <dependency>
                <groupId>com.netflix.hystrix</groupId>
                <artifactId>hystrix-javanica</artifactId>
                <version>1.5.12</version>
            </dependency>

    2.resource :application.yml文件

    #设置默认的服务超时时间为5s
    hystrix:
      command:
        default:
          execution:
            isolation:
              thread:
                timeoutInMilliseconds: 5000
    server:
      port: 8005
    spring:
      application:
        name: ms-hystrix-consumer
    eureka:
      client:
        healthcheck:
          enabled: true
        serviceUrl:
          defaultZone: http://ljf:123@localhost:8761/eureka
      instance:
        prefer-ip-address: true
        instance-id: ${spring.application.name}:${spring.cloud.client.ipAddress}:${spring.application.instance_id:${server.port}}
        metadata-map:
           business: Provide ms-fegin-client
           project-team: java-team
    #将feging中的超时熔断机制给关掉
    feign:
      hystrix:
        enabled: false
    #设置默认的服务超时时间为5s
    hystrix:
      command:
        default:
          execution:
            isolation:
              thread:
                timeoutInMilliseconds: 5000

    3.config:

    package config;
    
    import feign.Logger;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class HystrixUserConfig {
        /**
         * //feign配置日志
         * @return
         */
        @Bean
        public String showSmile() {
            String str="笑只是一种表情,与快乐无关,我是hystrix!!!";
            System.out.println(str);
            return str;
        }
    }
    
    

    4.service:@FeignClient(name="ms-eureka-provider",configuration = HystrixUserConfig.class)

    package com.ljf.weifuwu.springcloud.hystrix.service;
    
    import com.ljf.weifuwu.springcloud.hystrix.model.HystrixUser;
    import config.HystrixUserConfig;
    import org.springframework.cloud.netflix.feign.FeignClient;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    
    @FeignClient(name="ms-eureka-provider",configuration = HystrixUserConfig.class)
    public interface HystrixUserFegin {
        //和ms-eureka-provider模块中的路径要保持一致/eureka-provider/{id}
        //  @GetMapping("/eureka-provider/{id}")
        //    public EurekaUser getSingleUser(@PathVariable Long id)
        @RequestMapping(value = "/eureka-provider/{id}", method = RequestMethod.GET)
        public HystrixUser getSingleUser(@PathVariable("id") Long id);
    }
    

    5.model:

    package com.ljf.weifuwu.springcloud.hystrix.model;
    
    import java.math.BigDecimal;
    
    public class HystrixUser {
        private Long id;
    
        private String username;
    
        private String name;
    
        private Short age;
    
        private BigDecimal balance;
    
        public Long getId() {
            return this.id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getUsername() {
            return this.username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getName() {
            return this.name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Short getAge() {
            return this.age;
        }
    
        public void setAge(Short age) {
            this.age = age;
        }
    
        public BigDecimal getBalance() {
            return this.balance;
        }
    
        public void setBalance(BigDecimal balance) {
            this.balance = balance;
        }
    }
    

    6:controller:

    package com.ljf.weifuwu.springcloud.hystrix.controller;
    
    import com.ljf.weifuwu.springcloud.hystrix.model.HystrixUser;
    import com.ljf.weifuwu.springcloud.hystrix.service.HystrixUserFegin;
    import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
    import feign.Param;
    import feign.RequestLine;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    
    @RestController
    public class HystrixUserController {
        @Autowired
        private HystrixUserFegin huf;
        /**
         * 这个是get请求
         * @param id
         * @return
         */
        @GetMapping("/hystrix-consumer/{id}")
        @HystrixCommand(fallbackMethod = "queryUserByIdFallback")
        public HystrixUser queryInfoById(@PathVariable Long id) {
            System.out.println("hystrix的get请求!!!!!!!!!!1"+id);
            HystrixUser u= this.huf.getSingleUser(id);
            System.out.println("u:"+u.getName());
            return huf.getSingleUser(id);
        }
    
        /**
         * 超时异常处理
         * @param id
         * @return
         */
        public HystrixUser queryUserByIdFallback(@PathVariable Long id){
            System.out.println("超时发生错误的.....使用hystrix进行处理");
            HystrixUser u=new HystrixUser();
            u.setId(00l);
            u.setName("超时错误");
            return u;
        }
    }
    

    7.启动服务:ms-eureka-center(8761)、ms-eureka-provider(9701)、ms-hystrix-consumer(8005)

    8.访问:http://localhost:8005//hystrix-consumer/1

    9.将ms-eureka-provider,服务提供者,关闭之后:再次访问

     

    展开全文
  • Hystrix

    2021-01-14 10:11:44
    为了实现容错和自我保护,下面我们看看Hystrix如何设计和实现的。 Hystrix设计目标: 对来自依赖的延迟和故障进行防护和控制——这些依赖通常都是通过网络访问的 阻止故障的连锁反应 快速失败并迅速恢复 回退并...

    Hystrix

    基本理论

    Hystrix [hɪst’rɪks],中文含义是豪猪,因其背上长满棘刺,从而拥有了自我保护的能力。本文所说的Hystrix是Netflix开源的一款容错框架,同样具有自我保护能力。为了实现容错和自我保护,下面我们看看Hystrix如何设计和实现的。

    Hystrix设计目标:

    对来自依赖的延迟和故障进行防护和控制——这些依赖通常都是通过网络访问的
    阻止故障的连锁反应
    快速失败并迅速恢复
    回退并优雅降级
    提供近实时的监控与告警

    Hystrix遵循的设计原则:

    防止任何单独的依赖耗尽资源(线程)
    过载立即切断并快速失败,防止排队
    尽可能提供回退以保护用户免受故障
    使用隔离技术(例如隔板,泳道和断路器模式)来限制任何一个依赖的影响
    通过近实时的指标,监控和告警,确保故障被及时发现
    通过动态修改配置属性,确保故障及时恢复
    防止整个依赖客户端执行失败,而不仅仅是网络通信

    Hystrix如何实现这些设计目标?

    使用命令模式将所有对外部服务(或依赖关系)的调用包装在HystrixCommand或HystrixObservableCommand对象中,并将该对象放在单独的线程中执行;
    每个依赖都维护着一个线程池(或信号量),线程池被耗尽则拒绝请求(而不是让请求排队)。
    记录请求成功,失败,超时和线程拒绝。
    服务错误百分比超过了阈值,熔断器开关自动打开,一段时间内停止对该服务的所有请求。
    请求失败,被拒绝,超时或熔断时执行降级逻辑。
    近实时地监控指标和配置的修改。

    简单来说,Hystrix 是处理分布式系统的延迟和容错的开源库,保证一个依赖出现问题时不会导致整体服务失败, 避免级联故障,以提高分布式系统弹性。
    断路器本身是一种开关装置, 当某个服务单元发生故障后,通过断路器的故障监控,向调用方返回一个符合预期的可处理的备选响应, 而不是长时间的等待或抛出调用方法无法处理的异常 。

    服务降级

    服务端出现问题时( 程序运行异常 , 超时 ,服务熔断触发服务降级 ,线程池/信号量打满)不让客户端等待,而是立即返回一个友好的提示(俗称:有个兜底的)。

    服务熔断

    当服务端达到了最大访问量时,多余请求过来也没空处理,可能还会造成底层服务宕机,因此直接拒绝访问,呈现出拒绝访问情况(相当于保险丝断了)

    服务限流

    如秒杀类的高并发操作,请求直接全部进来,会造成服务宕机,因此禁止全部过来,而是限定一秒多少个请求有序进行

    降级

    降级,通常指务高峰期,为了保证核心服务正常运行,需要停掉一些不太重要的业务,或者某些服务不可用时,执行备用逻辑从故障服务中快速失败或快速返回,以保障主体业务不受影响。Hystrix提供的降级主要是为了容错,保证当前服务不受依赖服务故障的影响,从而提高服务的健壮性。要支持回退或降级处理,可以重写HystrixCommand的getFallBack方法或HystrixObservableCommand的resumeWithFallback方法。

    Hystrix在以下几种情况下会走降级逻辑:

    执行construct()或run()抛出异常
    熔断器打开导致命令短路
    命令的线程池和队列或信号量的容量超额,命令被拒绝
    命令执行超时
    
    

    降级回退方式
    Fail Fast 快速失败
    快速失败是最普通的命令执行方法,命令没有重写降级逻辑。 如果命令执行发生任何类型的故障,它将直接抛出异常。

    Fail Silent 无声失败
    指在降级方法中通过返回null,空Map,空List或其他类似的响应来完成。

    服务端降级兜底

    设置自身调用超时时间的峰值,峰值内正常运行,超过了由兜底方法处理–服务降级fallback
    新建cloud-provider-hystrix-payment8001

     <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            </dependency>
    

    yml

    server:
      port: 8001
    
    spring:
      application:
        name: cloud-provider-hystrix-payment #微服务名称
    
    注册进注册中心
    eureka:
      client:
        register-with-eureka: true
        fetch-registry: true
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
     
    

    service层:
    PaymentService:
    当请求过来,先由paymentInfo_TimeOut方法处理,当处理时间超过了注解@HystrixCommand 中设置的时间,或者方法内发生了程序错误等等,就会进行服务降级,由paymentInfo_TimeOutHandler方法来处理请求。
    在这里插入图片描述
    注意两个注解:
    @HystrixCommand 指明兜底方法和属性
    @HystrixProperty 定义超时时间单位为毫秒

    Controller层:

      @GetMapping("/payment/hystrix/timeout/{id}")
        public String paymentInfo_TimeOut(@PathVariable("id") Integer id)
        {
            String result = paymentService.paymentInfo_TimeOut(id);
            log.info("*****result: "+result);
            return result;
        }
    

    主启动类:

    @SpringBootApplication
    @EnableEurekaClient
    @EnableCircuitBreaker
    public class PaymentHystrixMain8001
    {
        public static void main(String[] args) {
                SpringApplication.run(PaymentHystrixMain8001.class, args);
        }
    

    注意@EnableCircuitBreaker,用于服务降级/熔断/限流

    客户端降级

    服务端是不可能知道所有客户端调用方的需求,不知道他们需要多少秒返回信息,因此正常需求是:

    在客户端调用服务端,服务端响应不及时或者出错等情况,客户端应该自己处理这种异常情况,即客户端降级,事实上降级一般就是在客户端做的。

    新建 cloud-consumer-feign-hystrix-order80 ,作为客户端微服务去访问cloud-provider-hystrix-payment8001

     <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
            <!--hystrix-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            </dependency>
    
    server:
      port: 80
    
    eureka:
      client:
        register-with-eureka: false
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka/
    
    feign:
      hystrix:
        enabled: true
    

    主启动类:注意注解@EnableHystrix

    @SpringBootApplication
    @EnableFeignClients
    @EnableHystrix
    public class OrderHystrixMain80
    {
        public static void main(String[] args)
        {
            SpringApplication.run(OrderHystrixMain80.class,args);
        }
    }
    

    service层:去找CLOUD-PROVIDER-HYSTRIX-PAYMENT服务,即payment8001

    @Component
    @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT" ,fallback = PaymentFallbackService.class)
    public interface PaymentHystrixService
    {
       @GetMapping("/payment/hystrix/timeout/{id}")
        public String paymentInfo_TimeOut(@PathVariable("id") Integer id);
    }
    

    Controller层:可以看到,和上面的降级类似的,当服务侧比如5s超时,但我客户端1.5s就不等了,或者客户端发生程序错误(比如10/0)则自己调用降级兜底方法。

    在这里插入图片描述
    效果如下:
    order微服务自身降级
    在这里插入图片描述
    思考一下:如果每个方法都需要这样,那么和业务方法耦合太严重了,且每一个微服务方法都需要加兜底太麻烦,于是就引入了全局兜底方法

    Global Fallback

    1、引入注解 @DefaultProperties指定全局兜底方法。

    然后paymentInfo_TimeOut方法不再单独指定自己的兜底方法,而是使用全局兜底方法。
    在这里插入图片描述
    下面解决兜底方法与业务代码耦合的问题
    1、新建PaymentFallbackService 类实现 PaymentHystrixService接口
    2、在PaymentHystrixService接口上利用@FeignClient注解指定fallback的类,即PaymentFallbackService。
    在这里插入图片描述

    @GetMapping("/consumer/payment/hystrix/ok/{id}")
        public String paymentInfo_OK(@PathVariable("id") Integer id)
        {
            String result = paymentHystrixService.paymentInfo_OK(id);
            return result;
        }
    

    可以看到Controller层中的paymentInfo_OK方法无需指定兜底方法,出现异常就去找PaymentFallbackService类中重写的paymentInfo_OK方法兜底。
    当访问paymentInfo_OK出现异常时效果如下:
    在这里插入图片描述
    完成了对兜底方法与业务方法解耦合,但是又引入了新的问题:

    所有接口兜底方法都要自己实现一遍
    是不是感觉回到了第一步,但是与第一步区别就是完成了解耦合

    aop 全局兜底+特定兜底

    用aop方法,对fallback包中的方法统一兜底

    开启aop注解 @EnableAspectJAutoProxy

    添加切面类:

    @Aspect
    @Configuration
    public class FallbackAspect {
        /**
         * 这里我们使用注解的形式
         * 当然,我们也可以通过切点表达式直接指定需要拦截的package,需要拦截的class 以及 method
         * 切点表达式:   execution(...)
         */
       
        @Pointcut("execution( * top.freshgeek.springcloud.order.feign.fallback..*(..))")
        public void logPointCut() {
        }
        /**
         * 环绕通知 @Around   当然也可以使用 @Before (前置通知)  @After (后置通知)
         *
         * @param point
         * @return
         * @throws Throwable
         */
        @Around("logPointCut()")
        public Object around(ProceedingJoinPoint point) throws Throwable {
            Object proceed = point.proceed();
            return proceed == null ? CommonResult.of(9007, "全局兜底降级,请稍后再试") : proceed;
        }
    }
    

    这里预留了空判断,也可以自己实现特定兜底 , 也符合 全局控制+特例特写

    熔断

    现实生活中,可能大家都有注意到家庭电路中通常会安装一个保险盒,当负载过载时,保险盒中的保险丝会自动熔断,以保护电路及家里的各种电器,这就是熔断器的一个常见例子。Hystrix中的熔断器(Circuit Breaker)也是起类似作用,Hystrix在运行过程中会向每个commandKey对应的熔断器报告成功、失败、超时和拒绝的状态,熔断器维护并统计这些数据,并根据这些统计信息来决策熔断开关是否打开。如果打开,熔断后续请求,快速返回。隔一段时间(默认是5s)之后熔断器尝试半开,放入一部分流量请求进来,相当于对依赖服务进行一次健康检查,如果请求成功,熔断器关闭。

    熔断器配置
    Circuit Breaker主要包括如下6个参数:

    1、circuitBreaker.enabled

    是否启用熔断器,默认是TRUE。
    2 、circuitBreaker.forceOpen

    熔断器强制打开,始终保持打开状态,不关注熔断开关的实际状态。默认值FLASE。
    3、circuitBreaker.forceClosed
    熔断器强制关闭,始终保持关闭状态,不关注熔断开关的实际状态。默认值FLASE。

    4、circuitBreaker.errorThresholdPercentage
    错误率,默认值50%,例如一段时间(10s)内有100个请求,其中有54个超时或者异常,那么这段时间内的错误率是54%,大于了默认值50%,这种情况下会触发熔断器打开。

    5、circuitBreaker.requestVolumeThreshold

    默认值20。含义是一段时间内至少有20个请求才进行errorThresholdPercentage计算。比如一段时间了有19个请求,且这些请求全部失败了,错误率是100%,但熔断器不会打开,总请求数不满足20。

    6、circuitBreaker.sleepWindowInMilliseconds

    半开状态试探睡眠时间,默认值5000ms。如:当熔断器开启5000ms之后,会尝试放过去一部分流量进行试探,确定依赖服务是否恢复。

    demo:
    cloud-provider-hystrix-payment8001的service层加入如下代码:
    在这里插入图片描述
    配置参数的意思就是:在时间窗口期内,失败次数达到了10*60%=6次,就发生熔断,熔断开关打开,之后的请求即使正确(id>0)也会交由兜底方法处理,一段时间之后才进入半开状态,请求再次正确才会进入关闭状态

    总结

    熔断类型

    熔断打开 请求不再进行调用当前服务,内部设有时钟一般为 MTTR,当打开时长达时钟则进入半熔断状态

    熔断关闭 熔断关闭不会对服务进行熔断

    熔断半开 根据规则调用当前服务,符合规则恢复正常,关闭熔断

    当开启断路器之后
    设计三个参数:时间窗,请求总阈值,错误百分比阈值 来控制熔断:
    在这里插入图片描述

    展开全文
  • 一、简介   微服务之间的调用模式是在不同进程间通过网络远程调用,内存间调用和远程调用之间的巨大差异之一是远程调用可能会失败,或者在没有响应的情况下... 断路器背后的基本思路很简单。您将一个受保护的函数调
  • Hystrix 是什么 Hystrix 是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等。Hystrix 能够保证在一个依赖出问题的情况下,不会导致整个服务失败,...
  • Hystrix超时实现机制

    2018-03-21 17:40:57
    HystrixCommand在执行的本篇假设大家都具备了如何使用hystrix的能力,如果还没接触过的朋友可参阅Hystrix介绍常规使用姿势 HystrixCommand在执行的过程中如何探测超时,本篇主要对此进行介绍说明。 1.主入口:...
  • 基于Hystrix实现限流

    千次阅读 2019-04-17 22:31:53
    前言 在微服务治理中,我们常常会遇到依赖接口超时或者调用失败的场景,如果没有对这些...下面简单介绍一些Hystrix的一些使用姿势。 hystrix的两种降级方式 信号量 线程池 下面是信号量降级的使用: 具体参数的...
  • 步骤一:服务注册中心的改进(作为Hystrix Dashboard入口,设置密码访问) 1、在服务注册中心添加如下依赖: <!--认证jar包--> <dependency> <groupId>org.springframework.boot</groupId...
  • maven依赖 : <groupId>org.springframework.cloud <artifactId>spring-cloud-starter-...项目启动后 访问 http://127.0.0.1:8764/ 来实现项目接口调用 简单的demo 具备feign 接口调用 以及Hystrix简单熔断的功能
  • hystrix实现服务降级的3种方式

    万次阅读 多人点赞 2019-09-29 22:40:18
    1、hystrix是什么 Hystrix是一款开源的容错插件,具有依赖隔离,系统容错降级等功能,这也是其最重要的两种用途,还有请求合并等功能 2、为什么要进行隔离 在实际工作中,尤其是分布式、微服务越来越普遍的今天,一...
  • 使用Hystrix实现断路器

    2020-07-13 21:42:37
    我们将会看到两大类别的Hystrix实现。在第一个类别中,我们将使用Hystrix断路器包装许可证服务和组织服务中所有对数据库的调用。然后,我们将使用Hystrix包装许可证服务和组织服务之间的内部服务调用。虽然这是两个...
  • Hystrix面试 - 基于 Hystrix 线程池技术实现资源隔离 上一讲提到,如果从 Nginx 开始,缓存都失效了,Nginx 会直接通过缓存服务调用商品服务获取最新商品数据(我们基于电商项目做个讨论),有可能出现调用延时而...
  • springcloud-hystrix服务降级1、hystrix简单介绍2、hystrix服务降级实现1. 在api模块的service文件夹编写FallbackFactory的实现类2. 在api模块的service文件夹@FeignClient注解添加参数3. 在springcloud-consumer-...
  • Hystrix 1.5 滑动窗口实现原理总结

    千次阅读 2019-01-23 16:51:36
    文章目录总览BucketedCounterStream总览...本文转载自:Hystrix 1.5 滑动窗口实现原理总结 总览 Netflix Hystrix 通过类似滑动窗口的数据结构来统计调用的指标数据。Hystrix 1.5 将滑动窗口设计成了数据流(reacti...
  • 只分析使用@HystrixCommand注解的情况。feign结合暂时不考虑,也不考虑异步。 如果要使用hystrix,可以通过@HystrixCommand注解,注释需要熔断降级的方法,hystrix会根据调用情况和配置值执行熔断、降级。 @Hystrix...
  • 加上@HystrixCommand注解,指定服务调用失败的回退方法,服务调用超时也会调用回退方法 controller: @RequestMapping(value = "testHystric", method = RequestMethod.GET) public String testHystric() { ...
  • 大家如果觉得我写的好,可以关注这个项目,之后...Hystrix实现服务容错 目录 一、服务容错简介 1.1 为什么要使用服务容错 1.2 Hystrix简介 二、Hystrix的使用 2.1 简单使用案例 2.2 服务熔断器的使用 2.3 将Hy...
  • Hystrix服务降级fallback实现 花开堪折直需折,莫待无花空折枝 我是一个菜菜鸟 Hystrix服务降级介绍: 当某个服务接口出现异常情况时(超时、执行异常)——该接口不可用,此时需要及时进行异常情况的处理,避免...
  • 本篇配置类及其他代码可参考《Hystrix使用fallback完成消费降级》 我们在Hystrix下新建一个CacheService @Slf4j @Service public class RequestCacheService { @Autowired private MyService service; @Cache...
  • Hystrix面试 - 基于 Hystrix 信号量机制实现资源隔离 Hystrix 里面核心的一项功能,其实就是所谓的资源隔离,要解决的最最核心的问题,就是将多个依赖服务的调用分别隔离到各自的资源池内。避免说对某一个依赖...
  • Hystrix文档-实现原理

    2017-12-19 11:01:10
    下图展示了当你使用 Hystrix 来包装你请求依赖服务时的流程: 接下来将详细介绍如下问题: 构建 HystrixCommand 或者 HystrixObservableCommand 对象 执行命令(即上述 Command 对象包装的逻辑) 结果...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 23,556
精华内容 9,422
关键字:

自己实现简单的hystrix