十三、以线程池的形式实现服务隔离
13.1 系统负载过高存在的问题
在微服务架构中,我们将业务拆分成一个个的服务,服务与服务之间可以相互调用,由于网络原因或者自身的原因,服务并不能保证服务的100%可用,如果单个服务出现问题,调用这个服务就会出现网络延迟,此时若有大量的网络涌入,会形成任务累计,导致服务瘫痪。
在SpringBoot程序中,默认使用内置tomcat作为web服务器。单tomcat支持最大的并发请求是有限的,如果某一接口阻塞,待执行的任务积压越来越多,那么势必会影响其他接口的调用。
13.2 以线程池的形式实现服务隔离
-
引入依赖
引入以线程池方式实现的隔离的相关依赖。
<!-- 以线程池的形式完成资源隔离的相关依赖 --> <dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-metrics-event-stream</artifactId> <version>1.5.12</version> </dependency> <dependency> <groupId>com.netflix.hystrix</groupId> <artifactId>hystrix-javanica</artifactId> <version>1.5.12</version> </dependency>
-
配置线程池
配置 HystrixCommand的实现类,在实现类中可以对线程池进行配置。
package cn.ebuy.order.command; import cn.ebuy.order.pojo.EasybuyProduct; import com.netflix.hystrix.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.client.RestTemplate; public class OrderCommand extends HystrixCommand<EasybuyProduct> { private RestTemplate restTemplate; private Long id; public OrderCommand(RestTemplate restTemplate, Long id) { super(setter()); this.restTemplate = restTemplate; this.id = id; } private static Setter setter() { // 服务分组 HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey("order_product"); // 服务标识 HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey("product"); // 线程池名称 HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey("order_product_pool"); /** * 线程池配置 * withCoreSize : 线程池大小为10 * withKeepAliveTimeMinutes: 线程存活时间15秒 * withQueueSizeRejectionThreshold :队列等待的阈值为100,超过100执行拒绝策略 */ HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter().withCoreSize(500) .withKeepAliveTimeMinutes(15).withQueueSizeRejectionThreshold(100); // 命令属性配置Hystrix 开启超时 HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter() // 采用线程池方式实现服务隔离 .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD) // 禁止 .withExecutionTimeoutEnabled(false); return Setter.withGroupKey(groupKey).andCommandKey(commandKey).andThreadPoolKey(threadPoolKey) .andThreadPoolPropertiesDefaults(threadPoolProperties).andCommandPropertiesDefaults(commandProperties); } /** * 当服务调用时,默认执行run()方法 * @return * @throws Exception */ @Override protected EasybuyProduct run() throws Exception { System.out.println(Thread.currentThread().getName()); return restTemplate.getForObject("http://ebuy-product/product/"+id, EasybuyProduct.class); } /** * 当服务阻塞时,执行fallback方法 * @return */ @Override protected EasybuyProduct getFallback(){ EasybuyProduct easybuyProduct=new EasybuyProduct(); easybuyProduct.setEpDescription("不好意思,出错了"); return easybuyProduct; } }
-
配置调用
修改OrderController,使用自定义的OrderCommand完成调用。
package cn.ebuy.order.controller; import cn.ebuy.order.command.OrderCommand; import cn.ebuy.order.feign.OrderFeignClient; import cn.ebuy.order.pojo.EasybuyProduct; import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.web.bind.annotation.*; import org.springframework.web.client.RestTemplate; import java.util.List; @RestController @RequestMapping("/order") @SuppressWarnings("all") //配置全局熔断,类中默认实现fallback方法 //@DefaultProperties(defaultFallback = "orderFallBack") public class OrderController { @Autowired RestTemplate restTemplate; /** * 测试--以线程池的形式完成资源隔离 * @param id * @return */ @GetMapping("/test/{id}") public EasybuyProduct Order(@PathVariable Long id){ OrderCommand orderCommand = new OrderCommand(restTemplate,id); return orderCommand.execute(); }