十三、以線程池的形式實作服務隔離
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(); }