怎麼透過 Hystrix 執行緒池技術實現資源隔離?
資源隔離,就是說,你如果要把對某一個依賴服務的所有呼叫請求,全部隔離在同一份資源池內,不會去用其它資源了,這就叫資源隔離。哪怕對這個依賴服務,比如說商品服務,現在同時發起的呼叫量已經到了 1000,但是執行緒池內就 10 個執行緒,最多就只會用這 10 個執行緒去執行,不會說,對商品服務的請求,因為介面呼叫延時,將 tomcat 內部所有的執行緒資源全部耗盡。
Hystrix 進行資源隔離,其實是提供了一個抽象,叫做 command。這也是 Hystrix 最最基本的資源隔離技術。
一、利用 HystrixCommand 獲取單條資料
我們透過將呼叫商品服務的操作封裝在
HystrixCommand
中,限定一個 key,比如下面的
GetProductInfoCommandGroup
,在這裡我們可以簡單認為這是一個執行緒池,每次呼叫商品服務,就只會用該執行緒池中的資源,不會再去用其它執行緒資源了。
public class GetProductInfoCommand extends HystrixCommand<ProductInfo> {
private Long productId;
public GetProductInfoCommand(Long productId) {
super(HystrixCommandGroupKey.Factory.asKey("GetProductInfoCommandGroup"));
this.productId = productId;
}
@Override
protected ProductInfo run() {
String url = "
// 呼叫商品服務介面
String response = HttpClientUtils.sendGetRequest(url);
return JSONObject.parseObject(response, ProductInfo.class);
}
}
我們在快取服務介面中,根據 productId 建立 command 並執行,獲取到商品資料。
@RequestMapping("/getProductInfo")
@ResponseBody
public String getProductInfo(Long productId) {
HystrixCommand<ProductInfo> getProductInfoCommand = new GetProductInfoCommand(productId);
// 透過 command 執行,獲取最新商品資料
ProductInfo productInfo = getProductInfoCommand.execute();
System.out.println(productInfo); return "success";
}
上面執行的是
execute()
方法,其實是同步的。也可以對 command 呼叫
queue()
方法,它僅僅是將 command 放入執行緒池的一個等待佇列,就立即返回,拿到一個 Future 物件,後面可以繼續做其它一些事情,然後過一段時間對 Future 呼叫
get()
方法獲取資料。這是非同步的。
二、利用 HystrixObservableCommand 批次獲取資料
只要是獲取商品資料,全部都繫結到同一個執行緒池裡面去,我們透過
HystrixObservableCommand
的一個執行緒去執行,而在這個執行緒裡面,批次把多個 productId 的 productInfo 拉回來。
public class GetProductInfosCommand extends HystrixObservableCommand<ProductInfo> {
private String[] productIds;
public GetProductInfosCommand(String[] productIds) {
// 還是繫結在同一個執行緒池
super(HystrixCommandGroupKey.Factory.asKey("GetProductInfoGroup"));
this.productIds = productIds;
}
@Override
protected Observable<ProductInfo> construct() {
return Observable.unsafeCreate((Observable.OnSubscribe<ProductInfo>) subscriber -> {
for (String productId : productIds) {
// 批次獲取商品資料
String url = "
String response = HttpClientUtils.sendGetRequest(url);
ProductInfo productInfo = JSONObject.parseObject(response, ProductInfo.class);
subscriber.onNext(productInfo);
}subscriber.onCompleted();
}).subscribeOn(Schedulers.io());
}
}
在快取服務介面中,根據傳來的 id 列表,比如是以 ,分隔的 id 串,透過上面的
HystrixObservableCommand
,執行 Hystrix 的一些 API 方法,獲取到所有商品資料。
public String getProductInfos(String productIds) {
String[] productIdArray = productIds.split(",");
HystrixObservableCommand<ProductInfo> getProductInfosCommand = new GetProductInfosCommand(productIdArray);
Observable<ProductInfo> observable = getProductInfosCommand.observe();
observable.subscribe(new Observer<ProductInfo>() {
@Override
public void onCompleted() {
System.out.println("獲取完了所有的商品資料");
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
}
/**
* 獲取完一條資料,就回撥一次這個方法
* @param productInfo
*/
@Override
public void onNext(ProductInfo productInfo) {
System.out.println(productInfo);
}
}); return "success";
}
我們回過頭來,看看 Hystrix 執行緒池技術是如何實現資源隔離的。
從 Nginx 開始,快取都失效了,那麼 Nginx 透過快取服務去呼叫商品服務。快取服務預設的執行緒大小是 10 個,最多就只有 10 個執行緒去呼叫商品服務的介面。即使商品服務介面故障了,最多就只有 10 個執行緒會 hang 死在呼叫商品服務介面的路上,快取服務的 tomcat 內其它的執行緒還是可以用來呼叫其它的服務,幹其它的事情。
喜歡這篇文章的朋友們可以關注個人簡介中的公眾號