溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何使用Hystrix提高系統(tǒng)可用性

發(fā)布時(shí)間:2021-11-10 17:59:49 來(lái)源:億速云 閱讀:130 作者:柒染 欄目:大數(shù)據(jù)

本篇文章給大家分享的是有關(guān)如何使用Hystrix提高系統(tǒng)可用性,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。

今天稍微復(fù)雜點(diǎn)的互聯(lián)網(wǎng)應(yīng)用,服務(wù)端基本都是分布式的,大量的服務(wù)支撐起整個(gè)系統(tǒng),服務(wù)之間也難免有大量的依賴關(guān)系,依賴都是通過(guò)網(wǎng)絡(luò)連接起來(lái)。

然而任何一個(gè)服務(wù)的可用性都不是 100% 的,網(wǎng)絡(luò)亦是脆弱的。當(dāng)我依賴的某個(gè)服務(wù)不可用的時(shí)候,我自身是否會(huì)被拖死?當(dāng)網(wǎng)絡(luò)不穩(wěn)定的時(shí)候,我自身是否會(huì)被拖死?這些在單機(jī)環(huán)境下不太需要考慮的問(wèn)題,在分布式環(huán)境下就不得不考慮了。假設(shè)我有5個(gè)依賴的服務(wù),他們的可用性都是99.95%,即一年不可用時(shí)間約為4個(gè)多小時(shí),那么是否意味著我的可用性最多就是 99.95% 的5次方,99.75%(近乎一天),再加上網(wǎng)絡(luò)不穩(wěn)定因素、依賴服務(wù)可能更多,可用性會(huì)更低??紤]到所依賴的服務(wù)必定會(huì)在某些時(shí)間不可用,考慮到網(wǎng)絡(luò)必定會(huì)不穩(wěn)定,我們應(yīng)該怎么設(shè)計(jì)自身服務(wù)?即,怎么為出錯(cuò)設(shè)計(jì)?

Michael T. Nygard 在在精彩的《Release It!》一書中總結(jié)了很多提高系統(tǒng)可用性的模式,其中我認(rèn)為非常重要的兩條是:

  1. 使用超時(shí)

  2. 使用斷路器

第一條,通過(guò)網(wǎng)絡(luò)調(diào)用外部依賴服務(wù)的時(shí)候,都必須應(yīng)該設(shè)置超時(shí)。在健康的情況下,一般局域往的一次遠(yuǎn)程調(diào)用在幾十毫秒內(nèi)就返回了,但是當(dāng)網(wǎng)絡(luò)擁堵的時(shí)候,或者所依賴服務(wù)不可用的時(shí)候,這個(gè)時(shí)間可能是好多秒,或者壓根就僵死了。通常情況下,一次遠(yuǎn)程調(diào)用對(duì)應(yīng)了一個(gè)線程或者進(jìn)程,如果響應(yīng)太慢,或者僵死了,那一個(gè)進(jìn)程/線程,就被拖死,短時(shí)間內(nèi)得不到釋放,而進(jìn)程/線程都對(duì)應(yīng)了系統(tǒng)資源,這就等于說(shuō)我自身服務(wù)資源會(huì)被耗盡,導(dǎo)致自身服務(wù)不可用。假設(shè)我的服務(wù)依賴于很多服務(wù),其中一個(gè)非核心的依賴如果不可用,而且沒(méi)有超時(shí)機(jī)制,那么這個(gè)非核心依賴就能拖死我的服務(wù),盡管理論上即使沒(méi)有它我在大部分情況還能健康運(yùn)轉(zhuǎn)的。

斷路器其實(shí)我們大家都不陌生(你會(huì)換保險(xiǎn)絲么?),如果你家沒(méi)有斷路器,當(dāng)電流過(guò)載,或者短路的時(shí)候,電路不斷開,電線就會(huì)升溫,造成火災(zāi),燒掉房子。有了斷路器之后,電流過(guò)載的時(shí)候,保險(xiǎn)絲就會(huì)首先燒掉,斷開電路,不至于引起更大的災(zāi)難(只不過(guò)這個(gè)時(shí)候你得換保險(xiǎn)絲)。

如何使用Hystrix提高系統(tǒng)可用性

當(dāng)我們的服務(wù)訪問(wèn)某項(xiàng)依賴有大量超時(shí)的時(shí)候,再讓新的請(qǐng)求去訪問(wèn)已經(jīng)沒(méi)有太大意義,那只會(huì)無(wú)謂的消耗現(xiàn)有資源。即使你已經(jīng)設(shè)置超時(shí)1秒了,那明知依賴不可用的情況下再讓更多的請(qǐng)求,比如100個(gè),去訪問(wèn)這個(gè)依賴,也會(huì)導(dǎo)致100個(gè)線程1秒的資源浪費(fèi)。這個(gè)時(shí)候,斷路器就能幫助我們避免這種資源浪費(fèi),在自身服務(wù)和依賴之間放一個(gè)斷路器,實(shí)時(shí)統(tǒng)計(jì)訪問(wèn)的狀態(tài),當(dāng)訪問(wèn)超時(shí)或者失敗達(dá)到某個(gè)閾值的時(shí)候(如50%請(qǐng)求超時(shí),或者連續(xù)20次請(qǐng)失?。痛蜷_斷路器,那么后續(xù)的請(qǐng)求就直接返回失敗,不至于浪費(fèi)資源。斷路器再根據(jù)一個(gè)時(shí)間間隔(如5分鐘)嘗試關(guān)閉斷路器(或者更換保險(xiǎn)絲),看依賴是否恢復(fù)服務(wù)了。

超時(shí)機(jī)制和斷路器能夠很好的保護(hù)我們的服務(wù),不受依賴服務(wù)不可用的影響太大,具體可以參看文章《 使用熔斷器設(shè)計(jì)模式保護(hù)軟件》。然而具體實(shí)現(xiàn)這兩個(gè)模式還是有一定的復(fù)雜度的,所幸 Netflix 開源的 Hystrix框架 幫我們大大簡(jiǎn)化了超時(shí)機(jī)制和斷路器的實(shí)現(xiàn),Hystrix:供分布式系統(tǒng)使用,提供延遲和容錯(cuò)功能,隔離遠(yuǎn)程系統(tǒng)、訪問(wèn)和第三方程序庫(kù)的訪問(wèn)點(diǎn),防止級(jí)聯(lián)失敗,保證復(fù)雜的分布系統(tǒng)在面臨不可避免的失敗時(shí),仍能有其彈性。在Codeplex上有一個(gè).NET的移植版本https://hystrixnet.codeplex.com/ 。

使用Hystrix,需要通過(guò)Command封裝對(duì)遠(yuǎn)程依賴的調(diào)用:

public class GetCurrentTimeCommand : HystrixCommand<long>

{

private static long currentTimeCache;

public GetCurrentTimeCommand()

: base(HystrixCommandSetter.WithGroupKey("TimeGroup")

.AndCommandKey("GetCurrentTime")

.AndCommandPropertiesDefaults(new HystrixCommandPropertiesSetter().WithExecutionIsolationThreadTimeout(TimeSpan.FromSeconds(1.0)).WithExecutionIsolationThreadInterruptOnTimeout(true)))

{

}

protected override long Run()

{

using (WebClient wc = new WebClient())

{

string content = wc.DownloadString("http://tycho.usno.navy.mil/cgi-bin/time.pl");

XDocument document = XDocument.Parse(content);

currentTimeCache = long.Parse(document.Element("usno").Element("t").Value);

return currentTimeCache;

}

}

protected override long GetFallback()

{

return currentTimeCache;

}

}

然后在需要的時(shí)候調(diào)用這個(gè)Command:

GetCurrentTimeCommand command = new GetCurrentTimeCommand();

long currentTime = command.Execute();

上述是同步調(diào)用,當(dāng)然如果業(yè)務(wù)邏輯允許且更追求性能,或許可以選擇異步調(diào)用:

該例中,不論 WebClient. DownloadString () 自身有沒(méi)有超時(shí)機(jī)制(可能你會(huì)發(fā)現(xiàn)很多遠(yuǎn)程調(diào)用接口自身并沒(méi)有給你提供超時(shí)機(jī)制),用 HystrixCommand 封裝過(guò)后,超時(shí)是強(qiáng)制的,默認(rèn)超時(shí)時(shí)間是1秒,當(dāng)然你可以根據(jù)需要自己在構(gòu)造函數(shù)中調(diào)節(jié) Command 的超時(shí)時(shí)間,例如說(shuō)2秒:

HystrixCommandSetter.WithGroupKey("TimeGroup")

.AndCommandKey("GetCurrentTime")

.AndCommandPropertiesDefaults(new HystrixCommandPropertiesSetter().WithExecutionIsolationThreadTimeout(TimeSpan.FromSeconds(2.0)).WithExecutionIsolationThreadInterruptOnTimeout(true))

當(dāng)Hystrix執(zhí)行命令超時(shí)后,Hystrix 執(zhí)行命令超時(shí)或者失敗之后,是會(huì)嘗試去調(diào)用一個(gè) fallback 的,這個(gè) fallback 即一個(gè)備用方案,要為 HystrixCommand 提供 fallback,只要重寫 protected virtual R GetFallback()方法即可。

一般情況下,Hystrix 會(huì)為 Command 分配專門的線程池,池中的線程數(shù)量是固定的,這也是一個(gè)保護(hù)機(jī)制,假設(shè)你依賴很多個(gè)服務(wù),你不希望對(duì)其中一個(gè)服務(wù)的調(diào)用消耗過(guò)多的線程以致于其他服務(wù)都沒(méi)線程調(diào)用了。默認(rèn)這個(gè)線程池的大小是10,即并發(fā)執(zhí)行的命令最多只能有是個(gè)了,超過(guò)這個(gè)數(shù)量的調(diào)用就得排隊(duì),如果隊(duì)伍太長(zhǎng)了(默認(rèn)超過(guò)5),Hystrix就立刻走 fallback 或者拋異常。

根據(jù)你的具體需要,你可能會(huì)想要調(diào)整某個(gè)Command的線程池大小,例如你對(duì)某個(gè)依賴的調(diào)用平均響應(yīng)時(shí)間為200ms,而峰值的QPS是200,那么這個(gè)并發(fā)至少就是 0.2 x 200 = 40 (Little's Law),考慮到一定的寬松度,這個(gè)線程池的大小設(shè)置為60可能比較合適:

public GetCurrentTimeCommand()

: base(HystrixCommandSetter.WithGroupKey("TimeGroup")

.AndCommandKey("GetCurrentTime")

.AndCommandPropertiesDefaults(new HystrixCommandPropertiesSetter().WithExecutionIsolationThreadTimeout(TimeSpan.FromSeconds(1.0)).WithExecutionIsolationThreadInterruptOnTimeout(true))

.AndThreadPoolPropertiesDefaults(new HystrixThreadPoolPropertiesSetter().WithCoreSize(60) // size of thread pool

.WithKeepAliveTime(TimeSpan.FromMinutes(1.0)) // minutes to keep a thread alive (though in practice this doesn't get used as by default we set a fixed size)

.WithMaxQueueSize(100) // size of queue (but we never allow it to grow this big ... this can't be dynamically changed so we use 'queueSizeRejectionThreshold' to artificially limit and reject)

.WithQueueSizeRejectionThreshold(10) // number of items in queue at which point we reject (this can be dyamically changed)

.WithMetricsRollingStatisticalWindow(10000) // milliseconds for rolling number

.WithMetricsRollingStatisticalWindowBuckets(10)))

{

}

說(shuō)了這么多,還沒(méi)提到Hystrix的斷路器,其實(shí)對(duì)于使用者來(lái)說(shuō),斷路器機(jī)制默認(rèn)是啟用的,但是編程接口默認(rèn)幾乎不需要關(guān)心這個(gè),機(jī)制和前面講的也差不多,Hystrix會(huì)統(tǒng)計(jì)命令調(diào)用,看其中失敗的比例,默認(rèn)當(dāng)超過(guò)50%失敗后,開啟斷路器,那之后一段時(shí)間的命令調(diào)用直接返回失?。ɑ蛘咦遞allback),5秒之后,Hystrix再嘗試關(guān)閉斷路器,看看請(qǐng)求是否能正常響應(yīng)。下面的幾行Hystrix源碼展示了它如何統(tǒng)計(jì)失敗率的:

public HealthCounts GetHealthCounts()

{

// we put an interval between snapshots so high-volume commands don't

// spend too much unnecessary time calculating metrics in very small time periods

long lastTime = this.lastHealthCountsSnapshot;

long currentTime = ActualTime.CurrentTimeInMillis;

if (currentTime - lastTime >= this.properties.MetricsHealthSnapshotInterval.Get().TotalMilliseconds || this.healthCountsSnapshot == null)

{

if (Interlocked.CompareExchange(ref this.lastHealthCountsSnapshot, currentTime, lastTime) == lastTime)

{

// our thread won setting the snapshot time so we will proceed with generating a new snapshot

// losing threads will continue using the old snapshot

long success = counter.GetRollingSum(HystrixRollingNumberEvent.Success);

long failure = counter.GetRollingSum(HystrixRollingNumberEvent.Failure); // fallbacks occur on this

long timeout = counter.GetRollingSum(HystrixRollingNumberEvent.Timeout); // fallbacks occur on this

long threadPoolRejected = counter.GetRollingSum(HystrixRollingNumberEvent.ThreadPoolRejected); // fallbacks occur on this

long semaphoreRejected = counter.GetRollingSum(HystrixRollingNumberEvent.SemaphoreRejected); // fallbacks occur on this

long shortCircuited = counter.GetRollingSum(HystrixRollingNumberEvent.ShortCircuited); // fallbacks occur on this

long totalCount = failure + success + timeout + threadPoolRejected + shortCircuited + semaphoreRejected;

long errorCount = failure + timeout + threadPoolRejected + shortCircuited + semaphoreRejected;

healthCountsSnapshot = new HealthCounts(totalCount, errorCount); }

}

return healthCountsSnapshot;

}

其中 failure 表示命令本身發(fā)生錯(cuò)誤、success 自然不必說(shuō),timeout 是超時(shí)、threadPoolRejected 表示當(dāng)線程池滿后拒絕的命令調(diào)用、shortCircuited 表示斷路器打開后拒絕的命令調(diào)用,semaphoreRejected 使用信號(hào)量機(jī)制(而不是線程池)拒絕的命令調(diào)用。

原文地址:http://www.cnblogs.com/shanyou/p/4752226.html


關(guān)注我們的方法:
1.點(diǎn)擊文章標(biāo)題下的“dotNET跨平臺(tái)”藍(lán)字,或者在微信搜索“opendotnet”,加關(guān)注
2.老朋友點(diǎn)擊點(diǎn)擊右上角“……”標(biāo)志分享到朋友圈

如何使用Hystrix提高系統(tǒng)可用性

本文分享自微信公眾號(hào) - dotNET跨平臺(tái)(opendotnet)。
如有侵權(quán),請(qǐng)聯(lián)系 support@oschina.cn 刪除。
本文參與“OSC源創(chuàng)計(jì)劃”,歡迎正在閱讀的你也加入,一起分享。

以上就是如何使用Hystrix提高系統(tǒng)可用性,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI