H__D  

服务隔离介绍

  当大多数人在使用Tomcat时,多个HTTP服务会共享一个线程池,假设其中一个HTTP服务访问的数据库响应非常慢,这将造成服务响应时间延迟增加,大多数线程阻塞等待数据响应返回,导致整个Tomcat线程池都被该服务占用,甚至拖垮整个Tomcat。因此,如果我们能把不同HTTP服务隔离到不同的线程池,则某个HTTP服务的线程池满了也不会对其他服务造成灾难性故障。这就需要线程隔离或者信号量隔离来实现了。

  使用线程隔离或信号隔离的目的是为不同的服务分配一定的资源,当自己的资源用完,直接返回失败而不是占用别人的资源。

  Hystrix实现服务隔离两种方案

  Hystrix的资源隔离策略有两种,分别为:线程池和信号量。

线程池方式

  优点:

  1、 使用线程池隔离可以完全隔离第三方应用,请求线程可以快速放回。

  2、 请求线程可以继续接受新的请求,如果出现问题线程池隔离是独立的不会影响其他应用。

  3、 当失败的应用再次变得可用时,线程池将清理并可立即恢复,而不需要一个长时间的恢复。

  4、 独立的线程池提高了并发性

  缺点:

  线程池隔离的主要缺点是它们增加计算开销(CPU)。每个命令的执行涉及到排队、调度和上 下文切换都是在一个单独的线程上运行的。

  线程池方式案例

  1、使用上一章项目工程,在服务端项目的业务类Service中编写如下方法:

 1 // 服务限流
 2 @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_Thread",
 3         // 属性设置参考:HystrixCommandProperties
 4         commandProperties = {
 5                 // 隔离策略,有THREAD和SEMAPHORE
 6                 @HystrixProperty(name="execution.isolation.strategy", value="THREAD")
 7         },
 8         threadPoolProperties = {
 9                 // 线程池核心线程数
10                 @HystrixProperty(name = "coreSize", value = "3"),
11                 // 队列最大长度
12                 @HystrixProperty(name = "maxQueueSize", value = "5"),
13                 // 排队线程数量阈值,默认为5,达到时拒绝,如果配置了该选项,队列的大小是该队列
14                 @HystrixProperty(name = "queueSizeRejectionThreshold", value = "7")
15         })
16 public String paymentCircuitBreakerThread(@PathVariable("id") Integer id){
17     int second = 500;
18     try {
19         // 休眠500毫秒
20         TimeUnit.MILLISECONDS.sleep(second);
21     } catch (InterruptedException e) {
22 //            e.printStackTrace();
23     }
24     // 异常
25 //        int n = 10/0;
26     String result = "线程池:" + Thread.currentThread().getName()
27             + ",paymentCircuitBreakerThreadPool,ID == " + id
28             + ",耗时" + second + "毫秒";
29     return result;
30 }
31 
32 public String paymentCircuitBreaker_Thread(@PathVariable("id") Integer id){
33     return " paymentCircuitBreaker_Thread 服务限流,ID == " + id;
34 }

  2、在controller中调用该方法

1 // 线程
2 @GetMapping(value = "/payment/hystrix/thread/{id}")
3 public String paymentCircuitBreakerThreadPool(@PathVariable("id") Integer id) {
4     String result = paymentService.paymentCircuitBreakerThread(id);
5     log.info("result===" + result);
6     return result;
7 }

  3、重启项目,使用JMeter进行并发测试,测试url地址:http://localhost:8008/payment/hystrix/thread/1

    测试发现,有一部分请求调用了fallback方法,一部分正常响应

    

信号量方式  

  使用一个原子计数器(或信号量)来记录当前有多少个线程在运行,当请求进来时先判断计数 器的数值,若超过设置的最大线程个数则拒绝该请求,若不超过则通行,这时候计数器+1,请求返 回成功后计数器-1。

  与线程池隔离最大不同在于执行依赖代码的线程依然是请求线程

  提示:信号量的大小可以动态调整, 线程池大小不可以

  信号量方式案例

  1、使用上一章项目工程,在服务端项目的业务类Service中编写如下方法:

 1 // 服务限流
 2 @HystrixCommand(fallbackMethod = "paymentCircuitBreaker_Semaphore",
 3         // 属性设置参考:HystrixCommandProperties
 4         commandProperties = {
 5                 // 隔离策略,有THREAD和SEMAPHORE
 6                 // THREAD - 它在单独的线程上执行,并发请求受线程池中的线程数量的限制(默认)
 7                 // SEMAPHORE - 它在调用线程上执行,并发请求受到信号量计数的限制
 8                 @HystrixProperty(name="execution.isolation.strategy", value="SEMAPHORE"),
 9                 // 设置在使用时允许到HystrixCommand.run()方法的最大请求数。默认值:10 ,SEMAPHORE模式有效
10                 @HystrixProperty(name="execution.isolation.semaphore.maxConcurrentRequests", value="1")
11 
12         })
13 public String paymentCircuitBreakerSemaphore(@PathVariable("id") Integer id){
14     int second = 500;
15     try {
16         // 休眠500毫秒
17         TimeUnit.MILLISECONDS.sleep(second);
18     } catch (InterruptedException e) {
19 //            e.printStackTrace();
20     }
21     // 异常
22 //        int n = 10/0;
23     String result = "线程池:" + Thread.currentThread().getName()
24             + ",paymentCircuitBreaker_Semaphore,ID == " + id
25             + ",耗时" + second + "毫秒";
26     return result;
27 }
28 
29 public String paymentCircuitBreaker_Semaphore(@PathVariable("id") Integer id){
30     return " paymentCircuitBreaker_Semaphore 服务限流,ID == " + id;
31 }

  2、在controller中调用该方法

1 // 信号量
2 @GetMapping(value = "/payment/hystrix/semaphore/{id}")
3 public String paymentCircuitBreakerLimit(@PathVariable("id") Integer id) {
4     String result = paymentService.paymentCircuitBreakerSemaphore(id);
5     log.info("result===" + result);
6     return result;
7 }

  3、重启项目,使用JMeter进行并发测试,测试url地址:http://localhost:8008/payment/hystrix/semaphore/1

    测试发现,有一部分请求调用了fallback方法,一部分正常响应

    

 

posted on 2020-04-16 23:33  H__D  阅读(1237)  评论(0编辑  收藏  举报