一、前言
現(xiàn)在分布式系統(tǒng)的規(guī)模不斷增加漠魏,對可用性的要求也越來越高倔矾。在各種高可用設計模式中,熔斷柱锹、隔離哪自、降級是經(jīng)常被使用的。而相關的技術禁熏,如 Hystrix壤巷,便成為最近的熱點。
從16年初開始瞧毙,我所在的團隊便開始應用 Hystrix胧华。為了進一步推動系統(tǒng)可用性升級寄症,普及 Hystrix 在團隊內(nèi)的使用,我便有了寫一系列 Hystrix 相關的文章的想法矩动。
雖然 Hystrix 有著很詳細的官方文檔有巧,但出于語言和更多細節(jié)介紹、實踐建議的考慮悲没,還是需要一些文章作為補充篮迎。
二、什么是 Hystrix
雖然 Hystrix 已算不上什么新技術示姿,但還是要簡單介紹一下柑潦。
Hystrix 是一個在調(diào)用端上,實現(xiàn)斷路器模式峻凫,以及隔艙模式渗鬼,通過避免級聯(lián)故障,提高系統(tǒng)容錯能力荧琼,從而實現(xiàn)高可用設計的一個 Java 類庫譬胎。
上面這段介紹是我的一個簡要總結。更具體的介紹可以參照官網(wǎng)命锄。
三堰乔、Hystrix 的基本使用
Hystrix 的主要目的是保護跨進程調(diào)用,避免因為超時等問題脐恩,導致的級聯(lián)故障镐侯。Hystrix 的實現(xiàn)方法是封裝跨進程調(diào)用。具體的使用方式有多種:從編程方式看可分為編程方式和注解方式兩種驶冒;從調(diào)用方式看可分為同步調(diào)用方式苟翻、異步調(diào)用方式和反應式調(diào)用方式三種。
我們先來看最常見的同步編程方式:
代碼示例
@Component
public class AuthService {
@Autowired
private UserService userService;
public boolean validateUser(String userId) {
User user = new GetUserCommand(userId).execute(); // 6
if (user == null) {
return false;
} else {
return user.isValid();
}
}
class GetUserCommand extends HystrixCommand<User> { // 1
private Long userId;
public GetUserCommand(Long userId) { // 2
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("UserService")) // 3
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
.withCoreSize(20) // 3
)
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionTimeoutInMilliseconds(100) // 3
)
);
this.userId = userId;
}
@Override
public User run() throws Exception {
return userService.getUserById(userId); // 4
}
@Override
public User getFallback() {
return new InvalidUser(); // 5
}
}
}
代碼解釋
- Hystrix 常見的使用方法是在一個業(yè)務處理類(在本例中是
AuthService
)新建一個內(nèi)部類(本例中是GetUserCommand
)骗污。這個內(nèi)部類需要擴展HystrixCommand
崇猫。之所以使用內(nèi)部類是因為 Hystrix 通常用來封裝一次遠程調(diào)用,一般是直接調(diào)用一個業(yè)務方法需忿。這個業(yè)務方法通常位于一個業(yè)務處理類或這個業(yè)務處理類所依賴的類中诅炉。所以使用內(nèi)部類的方式可以簡化這種調(diào)用。擴展HystrixCommand
還需聲明一個泛型類型屋厘,這個泛型類型表示這個HystrixCommand
的返回值涕烧。 - 定義一個
HystrixCommand
還需定義一個構造函數(shù)。這個構造函數(shù)十分重要汗洒,因為在使用這個HystrixCommand
時议纯,需要通過構造函數(shù)傳遞參數(shù)。 - 在構造函數(shù)中仲翎,需要調(diào)用父構造函數(shù)對當前的
HystrixCommand
進行配置痹扇。主要的配置主要有三個:GroupKey、ThreadPoolSize 和 Timeout溯香。具體的配置方式有多種鲫构,較常用的一種方式是通過一個名為Setter
的 Builder 類進行配置。- GroupKey 通過
Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("UserService"))
語句進行配置玫坛; - ThreadPoolSize 通過
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(20))
語句進行配置结笨; - Timeout 通過
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(100)
語句進行配置;
- GroupKey 通過
- 通過實現(xiàn)
run()
方法湿镀,在其中實現(xiàn)業(yè)務邏輯炕吸。通常是調(diào)用外部類的方法或外部類依賴的方法。 - 通過實現(xiàn)
getFallback()
方法勉痴,實現(xiàn)失敗邏輯赫模,可以在其中實現(xiàn)降級等功能。 - 編寫完
GetUserCommand
之后蒸矛,使用的時候每次都需要 new 一個新對象瀑罗,再調(diào)用execute()
方法。注意雏掠,不要調(diào)用run()
方法斩祭,否則熔斷、隔離等功能是不生效的乡话。
四摧玫、Hystrix 的基本配置
上面的部分介紹了 HystrixCommand
的基本使用方法,但只是簡單介紹了幾個配置绑青。所以诬像,下面將對 HystrixCommand
的相關配置的作用做一個較為詳細的介紹。
配置模式
Hystrix 的配置有三個維度:全局默認配置闸婴、Instance 默認配置颅停、Instance 動態(tài)配置。除了少部分配置項外掠拳,大部分配置都支持動態(tài)修改癞揉。接下來介紹一下一些主要參數(shù)的 Instance 默認配置方式。這種配置方式也是使用 Hystrix 最先接觸到的配置方式溺欧。
Command Group
GroupKey 是 HystrixCommand
不可缺少的配置喊熟,其它配置均為可選。所以姐刁,使用 Hystrix 可以使用下面的代碼:
public class CommandHelloWorld extends HystrixCommand<String> {
private final String name;
public CommandHelloWorld(String name) {
super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
this.name = name;
}
@Override
protected String run() {
return "Hello " + name + "!";
}
}
HystrixCommandGroupKey
是一個接口芥牌,所以除了可以使用 HystrixCommandGroupKey.Factory.asKey("ExampleGroup")
的方式定義以外,也可以直接實現(xiàn)這個接口聂使。比如使用如下的方式:
public enum Groups implements HystrixCommandGroupKey {
GROUP_1
}
class EnumGroupCommand extends HystrixCommand<String> {
EnumGroupCommand() {
super(Groups.GROUP_1);
}
@Override
protected String run() throws Exception {
LOGGER.info("Thread of Command: {}", Thread.currentThread().getName());
return null;
}
}
如上面代碼這樣壁拉,使用自定義的枚舉類谬俄,實現(xiàn) HystrixCommandGroupKey
接口,可以統(tǒng)一 Hystrix Command Group 的定義弃理,簡化配置溃论。
HystrixCommandGroupKey
的作用主要有兩個:
- 一是起到分組監(jiān)控、報警的作用痘昌。后面的文章會對監(jiān)控等方面進行介紹钥勋;
- 二是在不配置
HystrixThreadPoolKey
的情況下,起到分組線程池的作用辆苔。即默認使用HystrixCommandGroupKey
去命名線程池算灸。使用同一個HystrixCommandGroupKey
且沒有自定義HystrixThreadPoolKey
的HystrixCommand
將使用同一個線程池。
Command Thread-Pool
雖然 HystrixCommandGroupKey
可以起到隔離線程池的作用驻啤,但是無法起到對線程池進行精細配置的作用菲驴。所以這里就需要線程池進行配置:
Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("MyService"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("MyThreadPool"))
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
.withCoreSize(10)
.withKeepAliveTimeMinutes(1)
.withMaxQueueSize(-1)
)
)
andThreadPoolPropertiesDefaults
配置中的數(shù)值表示的是默認值。接下來逐項介紹:
-
andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("MyThreadPool"))
這是配置 ThreadPoolKey骑冗。如果需要在同一個 GroupKey 下面配置不同的 ThreadPool 就需要這個配置谢翎。 -
withCoreSize(10)
用來配置線程池大小。Hystrix 對線程池的配置有一些限制沐旨,這里只能配置線程數(shù)的 Core Size森逮,不能配置 Max Size。不配置的話使用的默認值是 10磁携。 -
withKeepAliveTimeMinutes(1)
用來配置核心線程數(shù)空閑時 keep alive 的時長褒侧,默認為 1 mins。這項配置一般不需要修改谊迄。 -
withMaxQueueSize(-1)
用來配置線程池任務隊列的大小闷供,默認值為 -1。當使用 -1 時统诺,SynchronousQueue
將被使用歪脏,即意味著其實這個隊列只是一個交換器,任務將被直接交給工作線程處理粮呢。如果工作線程不足婿失,那任務將被拒絕;如果使用任何正整數(shù)啄寡,LinkedBlockingQueue
將被使用豪硅。
Command Properties
這部分是和命令執(zhí)行直接相關的配置,包括隔離策略挺物、超時時間懒浮、Fallback 相關配置。接下來介紹幾個主要的配置:
隔離策略
默認的隔離策略是實現(xiàn)線程池隔離识藤,另外一種隔離策略是 Semaphore砚著。Instance 默認配置可使用如下方法設置:
HystrixCommandProperties.Setter().withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)
這項配置通常不用配置
超時時間
默認時間是1s次伶,單位是毫秒。Instance 默認配置可以使用如下方法設置:
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(100))
這項配置比較重要稽穆,后文還會詳細介紹如何調(diào)配這個參數(shù)冠王。
Fallback 并發(fā)度
在 Instance 默認配置中是通過如下代碼設置的:
super(Setter.withGroupKey(BASIC_USAGE_GROUP)
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withFallbackIsolationSemaphoreMaxConcurrentRequests(10)
)
);
默認值為 10。因為 getFallback()
方法是和 run()
方法使用同一個線程池執(zhí)行的秧骑,并且不受線程超時時間限制,并發(fā)過高會影響主邏輯的執(zhí)行扣囊,所有需要控制并發(fā)量乎折。如果 getFallback()
執(zhí)行速度很快仿便,那不用修改此值扁耐。如果 getFallback()
中執(zhí)行一個較為耗時的操作,那就需要考慮修改此值(或再通過另一個 HystrixCommand
調(diào)用挣柬,后續(xù)文章會詳細解釋)惕虑。
五坟冲、小結
本文介紹了 Hystrix 的基本使用方式,看完此文后溃蔫,讀者應該能通過使用 Hystrix 使得自己的應用具備初步的熔斷降級功能健提。下一篇文章將介紹 Hystrix 監(jiān)控相關的內(nèi)容。
六伟叛、參考
文章
- Netflix Hystrix — 應對復雜分布式系統(tǒng)中的延時和故障容錯:http://www.infoq.com/cn/news/2013/01/netflix-hystrix-fault-tolerance
- Introduction to Hystrix: http://www.baeldung.com/introduction-to-hystrix