面試官:為什么需要 Hystrix_第1頁
面試官:為什么需要 Hystrix_第2頁
面試官:為什么需要 Hystrix_第3頁
面試官:為什么需要 Hystrix_第4頁
面試官:為什么需要 Hystrix_第5頁
已閱讀5頁,還剩28頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

面試官:為什么需要Hystrix?為什么需要hystrixHystrix官網(wǎng)地址Github:/Netflix/Hystrix/Hystrix同樣是netfix公司在分布式系統(tǒng)中的貢獻(xiàn)。同樣的也進(jìn)入的不維護(hù)階段。不維護(hù)不代表被淘汰。只能說明推陳出新技術(shù)在不斷迭代。曾今的輝煌曾經(jīng)的設(shè)計還是值得我們?nèi)W(xué)習(xí)的。在分布式環(huán)境中,服務(wù)調(diào)度是特色也是頭疼的一塊。在服務(wù)治理章節(jié)我們介紹了服務(wù)治理的功能。前一課我們也介紹了ribbon、feign進(jìn)行服務(wù)調(diào)用?,F(xiàn)在自然的到了服務(wù)監(jiān)控管理了。hystrix就是對服務(wù)進(jìn)行隔離保護(hù)。以實(shí)現(xiàn)服務(wù)不會出現(xiàn)連帶故障。導(dǎo)致整個系統(tǒng)不可用hystrix對服務(wù)進(jìn)行隔離保護(hù)如上圖所示,當(dāng)多個客戶端進(jìn)行服務(wù)調(diào)用Aservice時,而在分布式系統(tǒng)中Aservice存在三臺服務(wù),其中Aservice某些邏輯需要Bservice處理。Bservice在分布式系統(tǒng)中部署了兩臺服務(wù)。這個時候因?yàn)榫W(wǎng)絡(luò)問題導(dǎo)致Aservice中有一臺和Bservice的通信異常。如果Bservice是做日志處理的。在整個系統(tǒng)看來日志丟了和系統(tǒng)宕機(jī)比起來應(yīng)該無所謂了。但是這個時候因?yàn)榫W(wǎng)絡(luò)通信問題導(dǎo)致Aservice整個服務(wù)不可用了。有點(diǎn)得不嘗試。系統(tǒng)雪崩在看上圖。A-->B-->C-->D。此時D服務(wù)宕機(jī)了。C因?yàn)镈宕機(jī)出現(xiàn)處理異常。但是C的線程卻還在為B響應(yīng)。這樣隨著并發(fā)請求進(jìn)來時,C服務(wù)線程池出現(xiàn)爆滿導(dǎo)致CPU上漲。在這個時候C服務(wù)的其他業(yè)務(wù)也會受到CPU上漲的影響導(dǎo)致響應(yīng)變慢。特色功能Hystrix是一個低延遲和容錯的第三方組件庫。旨在隔離遠(yuǎn)程系統(tǒng)、服務(wù)和第三方庫的訪問點(diǎn)。官網(wǎng)上已經(jīng)停止維護(hù)并推薦使用resilience4j:/resilience4j/resilience4j。

但是國內(nèi)的話我們有springcloudalibaba。Hystrix通過隔離服務(wù)之間的訪問來實(shí)現(xiàn)分布式系統(tǒng)中延遲及容錯機(jī)制來解決服務(wù)雪崩場景并且基于hystrix可以提供備選方案(fallback)。對網(wǎng)絡(luò)延遲及故障進(jìn)行容錯阻斷分布式系統(tǒng)雪崩快速失敗并平緩恢復(fù)服務(wù)降級實(shí)時監(jiān)控、警報上面試官網(wǎng)給出的一個統(tǒng)計。在30臺服務(wù)中每臺出現(xiàn)異常的概覽是0.01%。一億個請求就會有300000失敗。這樣換算下每個月至少有2小時停機(jī)。這對于互聯(lián)網(wǎng)系統(tǒng)來說是致命的。服務(wù)雪崩的場景上圖是官網(wǎng)給出的兩種情況。和我們上章節(jié)的類似。都是介紹服務(wù)雪崩的場景。項(xiàng)目準(zhǔn)備在openfeign專題中我們就探討了基于feign實(shí)現(xiàn)的服務(wù)熔斷當(dāng)時說了內(nèi)部就是基于hystrix。當(dāng)時我們也看了pom內(nèi)部的結(jié)構(gòu)在eureka中內(nèi)置ribbon的同時也內(nèi)置了hystrix模塊。引入hystrix雖然包里面包含了hystrix。我們還是引入對應(yīng)的start開啟相關(guān)配置吧。這里其實(shí)就是在openfeign專題中的列子。在那個專題我們提供了PaymentServiceFallbackImpl、PaymentServiceFallbackFactoryImpl兩個類作為備選方案。不過當(dāng)時我們只需指出openfeign支持設(shè)置兩種方式的備選方案。今天我們

org.springframework.cloud

spring-cloud-starter-netflix-hystrix

演示下傳統(tǒng)企業(yè)沒有備選方案的情況會發(fā)生什么災(zāi)難。openfeign使用接口調(diào)用接口測試首先我們對payment#createByOrder接口進(jìn)行測試。查看下響應(yīng)情況接口響應(yīng)情況在測試payment#getTimeout/id方法。postman接口調(diào)用jmeter壓測tomcat最大線程數(shù)測試spring中默認(rèn)的tomcat的最大線程數(shù)是200.為了保護(hù)我們辛苦的筆記本。這里我們將線程數(shù)設(shè)置小點(diǎn)。這樣我們更容易復(fù)現(xiàn)線程被打滿的情況。線程滿了就會影響到payment#createByOrder接口?,F(xiàn)在我們用jmeter來壓測payment#getTimeOut/id這個接口。一位需要4S等待會照成資源消耗殆盡問題。這個時候我們的payment#createByOrder也會被阻塞。上面我們壓測的是payment的原生接口。如果壓測的是order模塊。如果沒有在openfeign中配置fallback。那么order服務(wù)就會因?yàn)閜ayment#getTimeOut/id接口并發(fā)導(dǎo)致線程滿了從而導(dǎo)致order模塊響應(yīng)緩慢。這就是雪崩效應(yīng)。下面我們從兩個方面來解決雪崩的發(fā)生。業(yè)務(wù)隔離上面的場景發(fā)生是因?yàn)閜ayment#createByOrder和payment#getTimeOut/id同屬于payment服務(wù)。一個payment服務(wù)實(shí)際上就是一個Tomcat服務(wù)。同一個tomcat服務(wù)是有一個線程池的。每次請求落到該tomcat服務(wù)里就會去線程池中申請線程。獲取到線程了才能由線程來處理請求的業(yè)務(wù)。就是因?yàn)閠omcat內(nèi)共享線程池。所以當(dāng)payment#getTimeOut/id并發(fā)上來后就會搶空線程池。導(dǎo)致別的借口甚至是毫不相關(guān)的接口都沒有資源可以申請。只能干巴巴的等待資源的釋放。這就好比上班高峰期乘坐電梯因?yàn)槟骋粋€公司集中上班導(dǎo)致一段時間電梯全部被使用了。這時候國家領(lǐng)導(dǎo)過來也沒辦法上電梯。我們也知道這種情況很好解決。每個園區(qū)都會有專用電梯供特殊使用。我們解決上述問題也是同樣的思路。進(jìn)行隔離。不同的接口有不同的線程池。這樣就不會造成雪崩。線程隔離線程隔離還記得我們上面為了演示并發(fā)將order模塊的最大線程數(shù)設(shè)置為10.這里我們通過測試工具調(diào)用下order/getpayment/1這個接口看看日志打印情況接口日志我們接口調(diào)用的地方將當(dāng)前線程打印出來。我們可以看到一只都是那10個線程在來回的使用。這也是上面為什么會造成雪崩現(xiàn)象。搜索公眾號頂級架構(gòu)師后臺回復(fù)“offer”,獲取一份驚喜禮包。 @HystrixCommand(

groupKey="order-service-getPaymentInfo",

commandKey="getPaymentInfo",

threadPoolKey="orderServicePaymentInfo",

commandProperties={

@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1000")

},

threadPoolProperties={

@HystrixProperty(name="coreSize",value="6"),

@HystrixProperty(name="maxQueueSize",value="100"),

@HystrixProperty(name="keepAliveTimeMinutes",value="2"),

@HystrixProperty(name="queueSizeRejectionThreshold",value="100")

},

fallbackMethod="getPaymentInfoFallback"

)

@RequestMapping(value="/getpayment/{id}",method=RequestMethod.GET)

publicResultInfogetPaymentInfo(@PathVariable("id")Longid){

(Thread.currentThread().getName());

returnrestTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,ResultInfo.class);

}

publicResultInfogetPaymentInfoFallback(@PathVariable("id")Longid){

("已經(jīng)進(jìn)入備選方案了,下面交由自由線程執(zhí)行"+Thread.currentThread().getName());

returnnewResultInfo();

}

@HystrixCommand(

groupKey="order-service-getpaymentTimeout",

commandKey="getpaymentTimeout",

threadPoolKey="orderServicegetpaymentTimeout",

commandProperties={

@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="10000")

},

threadPoolProperties={

@HystrixProperty(name="coreSize",value="3"),

@HystrixProperty(name="maxQueueSize",value="100"),

@HystrixProperty(name="keepAliveTimeMinutes",value="2"),

@HystrixProperty(name="queueSizeRejectionThreshold",value="100")

}

)

@RequestMapping(value="/getpaymentTimeout/{id}",method=RequestMethod.GET)

publicResultInfogetpaymentTimeout(@PathVariable("id")Longid){

(Thread.currentThread().getName());

returnorderPaymentService.getTimeOut(id);

}這里演示效果不好展示,我就直接展示數(shù)據(jù)吧。如果我們將hystrix加載payment原生服務(wù)就不會出現(xiàn)上面第三條情況。為什么我會放在order上就是想讓大家看看雪崩的場景。在并發(fā)50的時候因?yàn)閜ayment設(shè)置的最大線程也是10,他本身也是有吞吐量的。在order#getpyament/id接口雖然在order模塊因?yàn)閔ystrix線程隔離有自己的線程運(yùn)行,但是因?yàn)樵?wù)不給力導(dǎo)致自己調(diào)用超時從而影響運(yùn)行的效果。這樣演示也是為了后續(xù)引出fallback解決雪崩的一次場景模擬吧。我們可以在payment服務(wù)中通過hystrix設(shè)置fallback。保證payment服務(wù)低延遲從而保證order模塊不會因?yàn)閜ayment自己緩慢導(dǎo)致order#getpayment這種正常接口異常。還有一點(diǎn)雖然通過hystrix進(jìn)行線程隔離了。但是我們在運(yùn)行其他接口時響應(yīng)時間也會稍長點(diǎn)。因?yàn)镃PU在進(jìn)行線程切換的時候是有開銷的。這一點(diǎn)也是痛點(diǎn)。我們并不能隨心所欲的進(jìn)行線程隔離的。這就引出我們的信號量隔離了。信號量隔離關(guān)于信號量隔離這里也就不演示了。演示的意義不是很大@HystrixCommand(

commandProperties={

@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1000"),

@HystrixProperty(name=HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY,value="SEMAPHORE"),

@HystrixProperty(name=HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS,value="6")

},

fallbackMethod="getPaymentInfoFallback"

)我們?nèi)缟吓渲帽硎拘盘柫孔畲鬄?。表示并發(fā)6之后就會進(jìn)行等待。等待超時時間未1s。除了線程隔離、信號量隔離等隔離手段我們可以通過請求合并、接口數(shù)據(jù)緩存等手段加強(qiáng)穩(wěn)定性。服務(wù)降級觸發(fā)條件程序發(fā)生除HystrixBadRequestException異常。服務(wù)調(diào)用超時服務(wù)熔斷線程池、信號量不夠timeout在上面我們的timeout接口。不管是線程隔離還是信號量隔離在條件滿足的時候就會直接拒絕后續(xù)請求。這樣太粗暴了。上面我們也提到了fallback。還記的上面我們order50個并發(fā)的timeout的時候會導(dǎo)致getpayment接口異常,當(dāng)時定位了是因?yàn)樵鷓ayment服務(wù)壓力撐不住導(dǎo)致的。如果我們在payment上加入fallback就能保證在資源不足的時候也能快速響應(yīng)。這樣至少能保證order#getpayment方法的可用性。配置fallback但是這種配置屬于實(shí)驗(yàn)性配置。在真實(shí)生產(chǎn)中我們不可能在每個方法上配置fallback的。這樣愚蠢至極。hystrix除了在方法上特殊定制的fallback以外,還有一個全局的fallback。只需要在類上通過@DefaultProperties(defaultFallback="globalFallback")來實(shí)現(xiàn)全局的備選方案。一個方法滿足觸發(fā)降級的條件時如果該請求對應(yīng)的HystrixCommand注解中沒有配置fallback則使用所在類的全局fallback。如果全局也沒有則拋出異常。不足雖然DefaultProperties

可以避免每個接口都配置fallback。但是這種的全局好像還不是全局的fallback。我們還是需要每個類上配置fallback。筆者查閱了資料好像也沒有但是在openfeign專題里我們說了openfeign結(jié)合hystrix實(shí)現(xiàn)的服務(wù)降級功能。還記的里面提到了一個FallbackFactory這個類嗎。這個類可以理解成spring的BeanFactory。這個類是用來產(chǎn)生我們所需要的FallBack的。我們在這個工廠里可以生成一個通用類型的fallback的代理對象。代理對象可以根據(jù)代理方法的方法簽名進(jìn)行入?yún)⒑统鰠ⅰ_@樣我們可以在所有的openfeign地方配置這個工廠類。這樣的話就避免的生成很多個fallback。美中不足的還是需要每個地方都指定一下。關(guān)于FallBackFactory感興趣的可以下載源碼查看或者進(jìn)主頁查看openfeign專題。服務(wù)熔斷@HystrixCommand(

commandProperties={

@HystrixProperty(name="circuitBreaker.enabled",value="true"),//是否開啟斷路器

@HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value="10"),//請求次數(shù)

@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value="10000"),//時間范圍

@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value="60"),//失敗率達(dá)到多少后跳閘

},

fallbackMethod="getInfoFallback"

)

@RequestMapping(value="/get",method=RequestMethod.GET)

publicResultInfoget(@RequestParamLongid){

if(id<0){

inti=1/0;

}

(Thread.currentThread().getName());

returnorderPaymentService.get(id);

}

publicResultInfogetInfoFallback(@RequestParamLongid){

returnnewResultInfo();

}首先我們通過circuitBreaker.enabled=true開啟熔斷器circuitBreaker.requestVolumeThreshold設(shè)置統(tǒng)計請求次數(shù)circuitBreaker.sleepWindowInMilliseconds

設(shè)置時間滑動單位,在觸發(fā)熔斷后多久進(jìn)行嘗試開放,及俗稱的半開狀態(tài)circuitBreaker.errorThresholdPercentage

設(shè)置觸發(fā)熔斷開關(guān)的臨界條件上面的配置如果最近的10次請求錯誤率達(dá)到60%,則觸發(fā)熔斷降級,在10S內(nèi)都處于熔斷狀態(tài)服務(wù)進(jìn)行降級。10S后半開嘗試獲取服務(wù)最新狀態(tài)下面我們通過jmeter進(jìn)行接口http://localhost/order/get?id=-1進(jìn)行20次測試。雖然這20次無一例額外都會報錯。但是我們會發(fā)現(xiàn)一開始報錯是因?yàn)槲覀兇a里的錯誤。后面的錯誤就是hystrix熔斷的錯誤了。一開始試byzero錯誤、后面就是short-circuitedandfallbackfailed熔斷錯誤了jmeter壓測正常我們在hystrix中會配置fallback,關(guān)于fallback兩種方式我們上面降級章節(jié)已經(jīng)實(shí)現(xiàn)了。這里是為了方便看到錯誤的不同特意放開了。HystrixCommand中配置的參數(shù)在HystrixCommand中配置的參數(shù)基本都是在HystrixPropertiesManager對象中。我們可以看到關(guān)于熔斷器的配置有6個參數(shù)?;揪褪俏覀兩厦娴乃膫€配置服務(wù)限流服務(wù)降級我們上面提到的兩種隔離就是實(shí)現(xiàn)限流的策略。請求合并除了熔斷、降級、限流意外hystrix還為我們提供了請求合并。顧名思義就是將多個請求合并成一個請求已達(dá)到降低并發(fā)的問題。比如說我們order有個接個是查詢當(dāng)個訂單信息order/getId?id=1

突然有一萬個請求過來。為了緩解壓力我們集中一下請求每100個請求調(diào)用一次order/getIds?ids=xxxxx

。這樣我們最終到payment模塊則是10000/100=100個請求。下面我們通過代碼配置實(shí)現(xiàn)下請求合并。HystrixCollapser@Target({ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

@Documented

public@interfaceHystrixCollapser{

StringcollapserKey()default"";

StringbatchMethod();

Scopescope()defaultScope.REQUEST;

HystrixProperty[]collapserProperties()default{};

}HystrixPropertiesManager在Hystrix中所有的properties配置都會在HystrixPropertiesManager.java中。我們在里面可以找到Collapser只有兩個相關(guān)的配置。分別表示最大請求數(shù)和統(tǒng)計時間單元。搜索公眾號后端架構(gòu)師后臺回復(fù)“架構(gòu)整潔”,獲取一份驚喜禮包。 @HystrixCollapser(

scope=flix.hystrix.HystrixCollapser.Scope.GLOBAL,

batchMethod="getIds",

collapserProperties={

@HystrixProperty(name=HystrixPropertiesManager.MAX_REQUESTS_IN_BATCH,value="3"),

@HystrixProperty(name=HystrixPropertiesManager.TIMER_DELAY_IN_MILLISECONDS,value="10")

}

)

@RequestMapping(value="/getId",method=RequestMethod.GET)

publicResultInfogetId(@RequestParamLongid){

if(id<0){

inti=1/0;

}

(Thread.currentThread().getName());

returnnull;

}

@HystrixCommand

publicListgetIds(Listids){

System.out.println(ids.size()+"@@@@@@@@@");

returnorderPaymentService.getIds(ids);

}上面我們配置了getId會走getIds請求,最多是10S三個請求會合并在一起。然后getIds有payment服務(wù)在分別去查詢最終返回多個ResultInfo。通過jemeter進(jìn)行g(shù)etId接口壓測我們通過jemeter進(jìn)行g(shù)etId接口壓測,日志中ids的長度最大是3。驗(yàn)證了我們上面getId接口的配置。這樣就能保證在出現(xiàn)高并發(fā)的時候會進(jìn)行接口合并降低TPS。上面我們是通過請求方法注解進(jìn)行接口合并處理。實(shí)際上內(nèi)部hystrix是通過HystrixCommand工作流程Hystrix官網(wǎng)給出的流程圖官網(wǎng)給出的流程圖示,并配備流程說明一共是9部。下面我們就翻譯下。①、創(chuàng)建HystrixCommand或者HystrixObservableCommand對象HystrixCommand:用在依賴單個服務(wù)上HystrixObservableCommand:用在依賴多個服務(wù)上②、命令執(zhí)行,hystrrixCommand執(zhí)行execute、queue;hystrixObservableCommand執(zhí)行observe、toObservable③、查看緩存是否開啟及是否命中緩存,命中則返回緩存響應(yīng)④、是否熔斷,如果已經(jīng)熔斷則fallback降級;如果熔斷器是關(guān)閉的則放行⑤、線程池、信號量是否有資源供使用。如果沒有足夠資源則fallback。有則放行⑥、執(zhí)行run或者construct方法。這兩個是hystrix原生的方法,java實(shí)現(xiàn)hystrix會實(shí)現(xiàn)兩個方法的邏輯,springcloud已經(jīng)幫我們封裝了。這里就不看這兩個方法了。如果執(zhí)行錯誤或者超時則fallback。在此期間會將日志采集到監(jiān)控中心。⑦、計算熔斷器數(shù)據(jù),判斷是否需要嘗試放行;這里統(tǒng)計的數(shù)據(jù)會在hystrix.stream的dashboard中查看到。方便我們定位接口健康狀態(tài)⑧、在流程圖中我們也能看到④、⑤、⑥都會指向fallback。也是我們俗稱的服務(wù)降級??梢姺?wù)降級是hystrix熱門業(yè)務(wù)啊。⑨、返回響應(yīng)HystrixDashboardhystrix除了服務(wù)熔斷、降級、限流以外,還有一個重要的特性是實(shí)時監(jiān)控。并形成報表統(tǒng)計接口請求信息。關(guān)于hystrix的安裝也很簡單,只需要在項(xiàng)目中配置actutor和hystrix-dashboard兩個模塊就行了

org.springframework.cloud

spring-cloud-starter-netflix-hystrix-dashboard

org.springframework.boot

spring-boot-starter-actuator

啟動類上添加EnableHystrixDashboard

就引入了dashboard了。我們不需要進(jìn)行任何開發(fā)。這個和eureka一樣主需要簡單的引包就可以了。hystrixdashboard就這樣dashboard搭建完成了。dashboard主要是用來監(jiān)控hystrix的請求處理的。所以我們還需要在hystrix請求出將端點(diǎn)暴露出來。在使用了hystrix命令的模塊加入如下配置即可,我就在order模塊加入@Component

publicclassHystrixConfig{

@Bean

publicServletRegistrationBeangetServlet(){

HystrixMetricsStreamServletstreamServlet=newHystrixMetricsStreamServlet();

ServletRegistrationBeanregistrationBean=newServletRegistrationBean(streamServlet);

registrationBean.setLoadOnStartup(1);

//注意這里配置的/hystrix.stream最終訪問地址就是localhost:port/hystrix.stream;如果在配置文件中配置在新版本中是需要

//加上actuator即localhost:port/actuator

registrationBean.addUrlMappings("/hystrix.stream");

registrationBean.setName("HystrixMetricsStreamServlet");

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論