一、服務(wù)熔斷
官方文檔:https://cloud.spring.io/spring-cloud-static/spring-cloud-netflix/1.3.5.RELEASE/single/spring-cloud-netflix.html#_circuit_breaker_hystrix_clients
我們知道,微服務(wù)之間是可以進(jìn)行相互調(diào)用的,那么如果出現(xiàn)了下面的情況會(huì)導(dǎo)致什么問(wèn)題?
由于位于最底端的服務(wù)提供者E發(fā)生故障,那么此時(shí)會(huì)直接導(dǎo)致服務(wù)ABCD全線崩潰,就像雪崩了一樣。?
這種問(wèn)題實(shí)際上是不可避免的,由于多種因素,比如網(wǎng)絡(luò)卡頓、系統(tǒng)故障、硬件問(wèn)題等,都存在一定可能,會(huì)導(dǎo)致這種極端的情況發(fā)生。因此,我們需要尋找一個(gè)應(yīng)對(duì)這種極端情況的解決方案。
為了解決分布式系統(tǒng)的雪崩問(wèn)題,SpringCloud提供了Hystrix熔斷器組件,他就像我們家中的保險(xiǎn)絲一樣,當(dāng)電流過(guò)載就會(huì)直接熔斷,防止危險(xiǎn)進(jìn)一步發(fā)生,從而保證家庭用電安全。可以想象一下,如果整條鏈路上的服務(wù)已經(jīng)全線崩潰,這時(shí)還在不斷地有大量的請(qǐng)求到達(dá),需要各個(gè)服務(wù)進(jìn)行處理,肯定是會(huì)使得情況越來(lái)越糟糕的。
我們來(lái)詳細(xì)看看它的工作機(jī)制。
1.服務(wù)降級(jí)
服務(wù)降級(jí),注意一定要區(qū)分開(kāi)服務(wù)降級(jí)和服務(wù)熔斷的區(qū)別,服務(wù)降級(jí)并不會(huì)直接返回錯(cuò)誤,而是可以提供一個(gè)補(bǔ)救措施,正常響應(yīng)給請(qǐng)求者。這樣相當(dāng)于服務(wù)依然可用,但是服務(wù)能力肯定是下降了的。
我們就基于借閱管理服務(wù)來(lái)進(jìn)行講解,我們不開(kāi)啟用戶服務(wù)和圖書(shū)服務(wù),表示用戶服務(wù)和圖書(shū)服務(wù)已經(jīng)掛掉了。
這里我們導(dǎo)入Hystrix的依賴(此項(xiàng)目已經(jīng)停止維護(hù),SpringCloud依賴中已經(jīng)不自帶了,所以說(shuō)需要自己?jiǎn)为?dú)導(dǎo)入):
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
接著我們需要在啟動(dòng)類添加注解開(kāi)啟:
@SpringBootApplication
@EnableFeignClients
@EnableHystrix //啟用Hystrix
public class BorrowApplication {
public static void main(String[] args) {
SpringApplication.run(BorrowApplication.class, args);
}
}
那么現(xiàn)在,由于用戶服務(wù)和圖書(shū)服務(wù)不可用,所以查詢借閱信息的請(qǐng)求肯定是沒(méi)辦法正常響應(yīng)的,這時(shí)我們可以提供一個(gè)備選方案,也就是說(shuō)當(dāng)服務(wù)出現(xiàn)異常時(shí),返回我們的備選方案:
BorrowController
@RestController
@RequestMapping("/borrow")
public class BorrowController {
@Resource
private BorrowService borrowService;
//使用@HystrixCommand來(lái)指定備選方案
@HystrixCommand(fallbackMethod = "onError")
@GetMapping("/getBorrowById/{uid}")
public UserBorrowDto getBorrowById(@PathVariable("uid") Integer uid){
return borrowService.getUserBorrowDtoByUid(uid);
}
//備選方案,這里直接返回空列表了
//注意參數(shù)和返回值要和上面的一致
public UserBorrowDto onError(Integer uid){
return new UserBorrowDto(null, Collections.emptyList());
}
}
可以看到,雖然我們的服務(wù)無(wú)法正常運(yùn)行了,但是依然可以給瀏覽器正常返回響應(yīng)數(shù)據(jù):?
?
?服務(wù)降級(jí)是一種比較溫柔的解決方案,雖然服務(wù)本身的不可用,但是能夠保證正常響應(yīng)數(shù)據(jù)。
2.服務(wù)熔斷
熔斷機(jī)制是應(yīng)對(duì)雪崩效應(yīng)的一種微服務(wù)鏈路保護(hù)機(jī)制,當(dāng)檢測(cè)出鏈路的某個(gè)微服務(wù)不可用或者響應(yīng)時(shí)間太長(zhǎng)時(shí),會(huì)進(jìn)行服務(wù)的降級(jí),進(jìn)而熔斷該節(jié)點(diǎn)微服務(wù)的調(diào)用,快速返回”錯(cuò)誤”的響應(yīng)信息。當(dāng)檢測(cè)到該節(jié)點(diǎn)微服務(wù)響應(yīng)正常后恢復(fù)調(diào)用鏈路。
實(shí)際上,熔斷就是在降級(jí)的基礎(chǔ)上進(jìn)一步升級(jí)形成的,也就是說(shuō),在一段時(shí)間內(nèi)多次調(diào)用失敗,那么就直接升級(jí)為熔斷。
加入兩條語(yǔ)句打印
//使用@HystrixCommand來(lái)指定備選方案
@HystrixCommand(fallbackMethod = "onError")
@GetMapping("/getBorrowById/{uid}")
public UserBorrowDto getBorrowById(@PathVariable("uid") Integer uid){
System.out.println("正常執(zhí)行方法");
return borrowService.getUserBorrowDtoByUid(uid);
}
//備選方案,這里直接返回空列表了
//注意參數(shù)和返回值要和上面的一致
public UserBorrowDto onError(Integer uid){
System.out.println("服務(wù)器錯(cuò)誤,進(jìn)入備選方法");
return new UserBorrowDto(null, Collections.emptyList());
}
}
一開(kāi)始的時(shí)候,會(huì)正常地去調(diào)用Controller對(duì)應(yīng)的方法findUserBorrows
,發(fā)現(xiàn)失敗然后進(jìn)入備選方法,但是我們發(fā)現(xiàn)在持續(xù)請(qǐng)求一段時(shí)間之后,沒(méi)有再調(diào)用這個(gè)方法,而是直接調(diào)用備選方案,這便是升級(jí)到了熔斷狀態(tài)。
我們可以繼續(xù)不斷點(diǎn)擊,繼續(xù)不斷地發(fā)起請(qǐng)求:
可以看到,過(guò)了一段時(shí)間之后,會(huì)嘗試正常執(zhí)行一次findUserBorrows,但是依然是失敗狀態(tài),所以繼續(xù)保持熔斷狀態(tài)。
所以得到結(jié)論,它能夠?qū)σ欢螘r(shí)間內(nèi)出現(xiàn)的錯(cuò)誤進(jìn)行偵測(cè),當(dāng)偵測(cè)到出錯(cuò)次數(shù)過(guò)多時(shí),熔斷器會(huì)打開(kāi),所有的請(qǐng)求會(huì)直接響應(yīng)失敗,一段時(shí)間后,只執(zhí)行一定數(shù)量的請(qǐng)求,如果還是出現(xiàn)錯(cuò)誤,那么則繼續(xù)保持打開(kāi)狀態(tài),否則說(shuō)明服務(wù)恢復(fù)正常運(yùn)行,關(guān)閉熔斷器。
我們可以測(cè)試一下,開(kāi)啟另外兩個(gè)服務(wù)之后,繼續(xù)點(diǎn)擊:
?
可以看到,當(dāng)另外兩個(gè)服務(wù)正常運(yùn)行之后,當(dāng)再次嘗試調(diào)用findUserBorrows
之后會(huì)成功,于是熔斷機(jī)制就關(guān)閉了,服務(wù)恢復(fù)運(yùn)行。
總結(jié)?
?二、OpenFign實(shí)現(xiàn)降級(jí)
Hystrix也可以配合Feign進(jìn)行降級(jí),我們可以對(duì)應(yīng)接口中定義的遠(yuǎn)程調(diào)用單獨(dú)進(jìn)行降級(jí)操作。
比如我們還是以用戶服務(wù)掛掉為例,那么這個(gè)時(shí)候肯定是會(huì)遠(yuǎn)程調(diào)用失敗的,也就是說(shuō)我們的Controller中的方法在執(zhí)行過(guò)程中會(huì)直接拋出異常,進(jìn)而被Hystrix監(jiān)控到并進(jìn)行服務(wù)降級(jí)。
而實(shí)際上導(dǎo)致方法執(zhí)行異常的根源就是遠(yuǎn)程調(diào)用失敗,所以我們換個(gè)思路,既然用戶服務(wù)調(diào)用失敗,那么我就給這個(gè)遠(yuǎn)程調(diào)用添加一個(gè)替代方案,如果此遠(yuǎn)程調(diào)用失敗,那么就直接上替代方案。那么怎么實(shí)現(xiàn)替代方案呢?我們知道Feign都是以接口的形式來(lái)聲明遠(yuǎn)程調(diào)用,那么既然遠(yuǎn)程調(diào)用已經(jīng)失效,我們就自行對(duì)其進(jìn)行實(shí)現(xiàn),創(chuàng)建一個(gè)實(shí)現(xiàn)類,對(duì)原有的接口方法進(jìn)行替代方案實(shí)現(xiàn):
?
package com.example.service.client;
import com.example.entity.User;
import org.springframework.stereotype.Component;
@Component
public class UserFallbackClient implements UserClient {
@Override
public User getUserById(Integer uid) {
User user = new User();
user.setName("我是補(bǔ)救措施");
return user;
}
}
實(shí)現(xiàn)完成后,我們只需要在原有的接口中指定失敗替代實(shí)現(xiàn)即可:
//聲明為userservice服務(wù)的HTTP請(qǐng)求客戶端
@FeignClient(value = "userservice",fallback = UserFallbackClient.class)
public interface UserClient {
//路徑保證和其他微服務(wù)提供的一致即可
@GetMapping("/user/getUserById/{uid}")
User getUserById(@PathVariable("uid") Integer uid);
}
現(xiàn)在去掉BorrowController
的@HystrixCommand
注解和備選方法:
@RestController
@RequestMapping("/borrow")
public class BorrowController {
@Resource
private BorrowService borrowService;
@GetMapping("/getBorrowById/{uid}")
public UserBorrowDto getBorrowById(@PathVariable("uid") Integer uid){
return borrowService.getUserBorrowDtoByUid(uid);
}
}
最后我們?cè)谂渲梦募虚_(kāi)啟熔斷支持:
feign:
circuit breaker:
enabled: true
?
可以看到,現(xiàn)在已經(jīng)采用我們的替代方案作為結(jié)果。
三、監(jiān)控頁(yè)面部署?
除了對(duì)服務(wù)的降級(jí)和熔斷處理,我們也可以對(duì)其進(jìn)行實(shí)時(shí)監(jiān)控,只需要安裝監(jiān)控頁(yè)面即可,這里我們創(chuàng)建一個(gè)新的項(xiàng)目,導(dǎo)入依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
接著添加配置文件:
server:
port: 8900
hystrix:
dashboard:
# 將localhost添加到白名單,默認(rèn)是不允許的
proxy-stream-allow-list: "localhost"
接著創(chuàng)建主類,注意需要添加@EnableHystrixDashboard
注解開(kāi)啟管理頁(yè)面:
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashBoardApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixDashBoardApplication.class, args);
}
}
啟動(dòng)Hystrix管理頁(yè)面服務(wù),然后我們需要在要進(jìn)行監(jiān)控的服務(wù)中添加Actuator依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Actuator是SpringBoot程序的監(jiān)控系統(tǒng),可以實(shí)現(xiàn)健康檢查,記錄信息等。在使用之前需要引入spring-boot-starter-actuator,并做簡(jiǎn)單的配置即可。
然后在配置文件中配置Actuator添加暴露:
management:
endpoints:
web:
exposure:
include: '*'
接著我們打開(kāi)剛剛啟動(dòng)的管理頁(yè)面,地址為:http://localhost:8900/hystrix/
?在中間填寫(xiě)要監(jiān)控的服務(wù):比如借閱服務(wù):http://localhost:8301/actuator/hystrix.stream,注意后面要添加/actuator/hystrix.stream
,然后點(diǎn)擊Monitor Stream即可進(jìn)入監(jiān)控頁(yè)面:
可以看到5次訪問(wèn)都是正常的,所以顯示為綠色,接著我們來(lái)嘗試將圖書(shū)服務(wù)關(guān)閉,這樣就會(huì)導(dǎo)致服務(wù)降級(jí)甚至熔斷,然后再多次訪問(wèn)此服務(wù)看看監(jiān)控會(huì)如何變化:?
?
可以看到,錯(cuò)誤率直接飆升到100%,并且一段時(shí)間內(nèi)持續(xù)出現(xiàn)錯(cuò)誤,中心的圓圈也變成了紅色,在出現(xiàn)大量錯(cuò)誤的情況下保持持續(xù)訪問(wèn),可以看到此時(shí)已經(jīng)將服務(wù)熔斷,Circuit
更改為Open狀態(tài),并且圖中的圓圈也變得更大,表示壓力在持續(xù)上升。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-580567.html
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-580567.html
到了這里,關(guān)于SpringCloud(四)Hystrix服務(wù)降級(jí)、熔斷、監(jiān)控頁(yè)面的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!