本文我們來示範下Hystrix中解決雪崩效應的第三種方式請求合并的實作
1.請求合并的場景
沒有合并的場景中,對于provider的調用會非常的頻繁,容易造成處理不過來的情況

合并請求的場景
2.什麼情況下使用請求合并
在微服務架構中,我們将一個項目拆分成很多個獨立的子產品,這些獨立的子產品通過遠端調用來互相配合工作,但是,在高并發情況下,通信次數的增加會導緻總的通信時間增加,同時,線程池的資源也是有限的,高并發環境會導緻有大量的線程處于等待狀态,進而導緻響應延遲,為了解決這些問題,我們需要來了解 Hystrix 的請求合并。
3.請求合并的缺點
設定請求合并之後,本來一個請求可能 5ms 就搞定了,但是現在必須再等 10ms 看看還有沒有其他的請求一起的,這樣一個請求的耗時就從 5ms 增加到 15ms 了,不過,如果我們要發起的指令本身就是一個高延遲的指令,那麼這個時候就可以使用請求合并了,因為這個時候時間窗的時間消耗就顯得微不足道了,另外高并發也是請求合并的一個非常重要的場景。
4.請求合并案例
4.1.添加依賴
将Hystrix的依賴添加即可
<!--服務熔斷元件-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
4.2.啟動類修改
啟動類中開啟
@EnableCircuitBreaker
注解。
/**
* @author bruceliu
* @create 2019-10-15 14:36
* @description
*/
@SpringBootApplication
@EnableDiscoveryClient // 開啟EurekaClient功能
@EnableFeignClients // 開啟Feign功能
@EnableCircuitBreaker//對hystrixR熔斷機制的支援
public class ConsumerApp {
public static void main(String[] args) {
System.out.println("服務的調用端啟動8082.....");
SpringApplication.run(ConsumerApp.class,args);
}
}
4.3.業務層修改
具體代碼如下,要注意的是getUser方法的傳回類型必須是Future類型,batchMethod 屬性指定的是請求合并後要執行的方法的名稱。
package com.bruceliu.api;
import com.bruceliu.bean.User;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
/**
* @BelongsProject: springcloud0310
* @BelongsPackage: com.bruceliu.api
* @Author: bruceliu
* @QQ:1241488705
* @CreateTime: 2020-03-11 20:00
* @Description: TODO
*/
@Service
public class UserService {
/**
* consumer 的 controller 調用的方法
* 該方法傳回值必須要傳回Future 類型
* 利用 hystrix 合并請求
*/
@HystrixCollapser(
batchMethod = "batchUser", scope = com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL, collapserProperties = {
//請求時間間隔在 20ms 之内的請求會被合并為一個請求,預設為 10ms
@HystrixProperty(name = "timerDelayInMilliseconds", value = "20"),
//設定觸發批處理執行之前,在批進行中允許的最大請求數。
@HystrixProperty(name = "maxRequestsInBatch", value = "200"),
})
public Future<User> getUser(Integer id) {
System.out.println("-----------id-------:" + id);
return null;
}
/**
* 調用 Provider 服務的方法
*
* @param ids
* @return
*/
@HystrixCommand
public List<User> batchUser(List<Integer> ids) {
for (Integer id : ids) {
System.out.println(id);
}
//假設是調用 provider 服務後傳回的 list
List<User> list = new ArrayList<>();
list.add(new User(1, "張三", 18));
list.add(new User(2, "李四", 19));
list.add(new User(3, "王五", 20));
list.add(new User(4, "小明", 21));
list.add(new User(100, "小張", 22));
System.out.println("***********************");
return list;
}
}
4.4.控制器調用
調用service的方法,模拟多次請求的場景,具體如下
@RestController
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/consumer")
public void getUsers() throws Exception{
Future<User> f1 = this.userService.getUser(1);
Future<User> f2 = this.userService.getUser(2);
Future<User> f3 = this.userService.getUser(3);
System.out.println(f1.get().toString());
System.out.println(f2.get().toString());
System.out.println(f3.get().toString());
}
}
4.5.測試
啟動服務後通路,檢視控制台效果,發現雖然請求了多次service,但是batchUser方法隻執行了一次
隻執行了一次,擷取了三個結果!
4.5.控制器調用
參數 | 作用/預設值 | 備注 |
@HystrixCollapser | ||
batchMethod | 合并請求的方法 | |
scope | 請求方式/REQUEST | 請求方式分為REQUEST和GLOBAL。REQUEST範圍隻對一個request請求内的多次服務請求進行合并 GLOBAL是多單應用中的所有線程的請求中的多次服務請求合并 |
timerDelayInMilliseconds | 請求時間間隔在10ms之内的請求會被合并為一個請求/10ms | 建議盡量設定的小一點,如果并發量不大的話,其實也沒有必要使用HystrixCollapser來處理 |