Hystrix解读
目錄
`Hystrix` 簡介
`Hystrix` 服務熔斷產生的背景
引起雪崩效應常見場景
初探 `Hystrix`
`Hystrix` 設計目標,作用
`Hystrix` 如何實現這些設計目標
`Hystrix` 入門
項目概覽
`Hystrix` 的使用(不整合 `Feign`)
`Hystrix-study-user` 服務的主啟動類
`Hystrix-study-user` 服務的 `Feign` 的客戶端接口
`Hystrix-study-user` 服務的服務降級類
`Hystrix-study-user` 服務的 `Service` 實現類
`Hystrix-study-user` 服務的配置文件
服務熔斷測試
`@HystrixCommand` 注解的簡單使用
`Hystrix-study-user` 服務的 `Service` 實現類添加方法
`Hystrix-study-activity` 服務的 `Controller` 類
服務降級測試
修改 `Hystrix-study-activity` 服務的 `Controller` 類再測試
`@HystrixCommand` 注解的常見使用
`Hystrix` 與 `Ribbon` 的超時時間
`Hystrix` 的斷路器工作原理
斷路器開啟的條件
斷路器關閉的條件
服務降級與服務熔斷區別
服務熔斷
服務降級
區別
相同點
不同點
Hystrix 簡介
Hystrix 是 Netlifx 開源的一款容錯框架,防雪崩利器,具備服務降級,服務熔斷,依賴隔離,監控 Hystrix Dashboard 等功能
官網:https://github.com/Netflix/Hystrix/wiki/How-To-Use
Hystrix 服務熔斷產生的背景
分布式系統環境下,服務間類似依賴非常常見,一個業務調用通常依賴多個基礎服務。如下圖,對于同步調用,當庫存服務不可用時,商品服務請求線程被阻塞,當有大批量請求調用庫存服務時,最終可能導致整個商品服務資源耗盡,無法繼續對外提供服務。并且這種不可用可能沿請求調用鏈向上傳遞,這種現象被稱為雪崩效應
引起雪崩效應常見場景
硬件故障:如服務器宕機,機房斷電,光纖被挖斷等
流量激增:如異常流量,重試加大流量等
緩存擊穿:一般發生在應用重啟,所有緩存失效時,以及短時間內大量緩存失效時。大量的緩存不命中,使請求直擊后端服務,造成服務提供者超負荷運行,引起服務不可用
程序 BUG:如程序邏輯導致內存泄漏,JVM 長時間 FullGC 等
同步等待:服務間采用同步調用模式,同步等待造成的資源耗盡
初探 Hystrix
Hystrix 設計目標,作用
服務的降級
服務的熔斷
服務的限流
提供近實時的監控與告警
Hystrix 如何實現這些設計目標
使用命令模式將所有對外部服務(或依賴關系)的調用包裝在 HystrixCommand 或HystrixObservableCommand 對象中,并將該對象放在單獨的線程中執行
每個依賴都維護著一個線程池(或信號量),線程池被耗盡則拒絕請求(而不是讓請求排隊)
記錄請求成功,失敗,超時和線程拒絕
服務錯誤百分比超過了閾值,熔斷器開關自動打開,一段時間內停止對該服務的所有請求
請求失敗,被拒絕,超時或熔斷時執行降級邏輯
近實時地監控指標和配置的修改
Hystrix 入門
項目概覽
Hystrix 的使用(不整合 Feign)
在使用 Feign 組件作為接口調用遠程服務時,是不需要添加 Hystrix 的依賴的。因為 Feign 默認已經集成了 Hystrix 和 Ribbon。如果單獨使用 Hystrix 組件時,可以導入以下依賴
<dependency>
? ? <groupId>org.springframework.cloud</groupId>
? ? <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
1
2
3
4
Hystrix-study-user 服務的主啟動類
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableCircuitBreaker // 開啟斷路器
@EnableHystrixDashboard // 開啟 Hystrix 的監控儀表盤
public class UserApplication {
?? ?private static final Logger log = LoggerFactory.getLogger(UserApplication.class);
?? ?public static void main(String[] args) {
?? ??? ?SpringApplication.run(UserApplication.class, args);
?? ??? ?log.info("===============springcloud user啟動了=================");
?? ?}
?? ?// 解決 hystrix-dashBoard 儀表盤不能訪問
?? ?@SuppressWarnings({ "rawtypes", "unchecked" })
?? ?@Bean
?? ?public ServletRegistrationBean getServlet() {
?? ??? ?HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
?? ??? ?ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
?? ??? ?registrationBean.setLoadOnStartup(1);
?? ??? ?registrationBean.addUrlMappings("/hystrix.stream");
?? ??? ?registrationBean.setName("HystrixMetricsStreamServlet");
?? ??? ?return registrationBean;
?? ?}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Hystrix-study-user 服務的 Feign 的客戶端接口
@FeignClient(name = "STUDY-ACTIVITY", fallback = UserFeignFallback.class)
public interface UserFeign {
?? ?@RequestMapping(path = { "/activity/getCoupon" }, method = RequestMethod.POST)
?? ?String getCoupon(@RequestBody Integer id);
?? ?@RequestMapping(path = { "/activity/getCouponTimeOut" }, method = RequestMethod.POST)
?? ?String getCouponTimeOut(@RequestBody Integer id);
?? ?@RequestMapping(path = { "/demo/timeOut" }, method = RequestMethod.POST)
?? ?String timeOut(@RequestParam Integer mills);
?? ?@RequestMapping(path = { "/timeOut" }, method = RequestMethod.POST)
?? ?String tripTest(@RequestParam Integer mills);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Hystrix-study-user 服務的服務降級類
@Component
public class UserFeignFallback implements UserFeign {
?? ?@Override
?? ?public String getCoupon(Integer id) {
?? ??? ?return null;
?? ?}
?? ?@Override
?? ?public String getCouponTimeOut(Integer id) {
?? ??? ?return "------超過2000毫秒時,直接進入服務降級處理------";
?? ?}
?? ?@Override
?? ?public String timeOut(Integer mills) {
?? ??? ?return "---------------您的請求【超時】或【失敗】,已進入服務降級模式了----------------";
?? ?}
?? ?@Override
?? ?public String tripTest(Integer mills) {
?? ??? ? return "-------------請求未通過-----------";
?? ?}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Hystrix-study-user 服務的 Service 實現類
@Service
public class UserServiceImpl implements UserService {
?? ?private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
?? ?@Autowired
?? ?private UserFeign userFeign;
?? ?// 使用注解 @HystrixCommand 指定服務熔斷的回退方法
?? ?@HystrixCommand(fallbackMethod = "firstLoginError")
?? ?@Override
?? ?public String firstLogin(Integer id) {
?? ??? ?// 采用 Feign 客戶端來調用服務 Hystrix-study-activity
?? ??? ?String result = userFeign.getCoupon(id);
?? ??? ?log.info("===================result的值為:" + result + "======================");
?? ??? ?return result;
?? ?}
?? ?// 當服務 Hystrix-study-activity 不可用時,這時讓其回調回退方法
?? ?public String firstLoginError(Integer id) {
?? ??? ?return "---------您請求的服務暫時不可用,請稍后再試--------------";
?? ?}
}?? ?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Hystrix-study-user 服務的配置文件
server.port=8080
spring.application.name=study-user
eureka.client.service-url.defaultZone=http://eureka7001.com:8761/eureka/
#事實上,springcloud默認已為Feign整合了Hystrix,要想為Feign打開Hystrix支持,只需要設置feign.hystrix.enabled=true即可。
feign.hystrix.enabled=true
#補充:在springcloud Dalston之前的版本中,Feign默認開啟Hystrix支持,無需設置feign.hystrix.enabled=true.
#從springcloud Dalston版本開始,Feign的Hystrix支持默認關閉,需要手動設置開啟
#配置Hystrix的超時時間
#default全局有效,service id指定應用有效
hystrix.command.default.execution.timeout.enabled=true #默認為true
#默認值為 1000毫秒(對于每一個標有注解 @FeignClient 的接口的所有抽象方法生效)
#hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=9000
#顯示服務器詳細的健康信息
management.endpoint.health.show-details=always
#暴露全部的監控信息(解決hystrix-dashBoard儀表盤不能訪問)
management.endpoint.web.exposure.include="*"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
服務熔斷測試
分別啟動 Hystrix-study-activity,Hystrix-study-eureka,Hystrix-study-user 三個服務,使用 Postman 測試如下
此時再關閉 Hystrix-study-activity 服務
說明執行了 @HystrixCommand(fallbackMethod = "firstLoginError") 服務熔斷的回退方法
@HystrixCommand 注解的簡單使用
依然使用上面的入門項目,只不過不需要引入 Hystrix 的依賴了,直接使用 Feign 客戶端進行調用。在使用 Feign 組件作為接口調用遠程服務時,是不需要添加 Hystrix 的依賴的。因為 Feign 默認已經集成了 Hystrix 和 Ribbon。如果單獨使用 Hystrix 組件時,可以導入以下依賴
Hystrix-study-user 服務的 Service 實現類添加方法
execution.isolation.thread.timeoutInMilliseconds:該屬性用來配置方法執行的超時時間。我們在之前對于降級處理時間的配置,都是在全局配置文件 application.yml 中配置的,commandProperties 可以讓我們在一些具有獨特要求的方法上,單獨進行一些配置操作
// 設置Hystrix的服務降級超時時間,超過2000毫秒時,直接進入服務降級處理?? ?
@HystrixCommand(commandProperties = {
?? ??? ?@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000") })
@Override
public String firstLoginTimeOut(Integer id) {
?? ?String result = userFeign.getCouponTimeOut(id);
?? ?log.info("===================result的值為:" + result + "======================");
?? ?return result;
}
1
2
3
4
5
6
7
8
9
Hystrix-study-activity 服務的 Controller 類
@Controller
@RequestMapping(path = { "/activity" })
public class ActivityController {
?? ?private static final Logger log = LoggerFactory.getLogger(ActivityController.class);
?? ?@RequestMapping(path = { "/getCouponTimeOut" }, method = RequestMethod.POST)
?? ?@ResponseBody
?? ?public String getCouponTimeOut(@RequestBody Integer id) {
?? ??? ?try {
?? ??? ??? ?Random random = new Random();
?? ??? ??? ?TimeUnit.SECONDS.sleep(random.nextInt(10) % (7) + 4);
?? ??? ?} catch (InterruptedException e) {
?? ??? ??? ?e.printStackTrace();
?? ??? ?}
?? ??? ?log.info("=============該用戶首次登陸(注冊),領取優惠券失敗============");
?? ??? ?return "error";
?? ?}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
服務降級測試
分別啟動 Hystrix-study-activity,Hystrix-study-eureka,Hystrix-study-user 三個服務,使用 Postman 測試如下
說明執行了 UserFeignFallback 服務降級處理類的相應方法
修改 Hystrix-study-activity 服務的 Controller 類再測試
@Controller
@RequestMapping(path = { "/activity" })
public class ActivityController {
?? ?private static final Logger log = LoggerFactory.getLogger(ActivityController.class);
?? ?@RequestMapping(path = { "/getCouponTimeOut" }, method = RequestMethod.POST)
?? ?@ResponseBody
?? ?public String getCouponTimeOut(@RequestBody Integer id) {
?? ??? ?log.info("=============該用戶首次登陸(注冊),領取優惠券成功============");
?? ??? ?return "SUCCESS";
?? ?}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
再測試結果
@HystrixCommand 注解的常見使用
@Service
public class UserServiceImpl implements UserService {
? ? private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
? ? @Autowired
? ? private UserFeign userFeign;
? ?
? ? @HystrixCommand(threadPoolKey = "time", threadPoolProperties = {
? ? ? ? ? ? @HystrixProperty(name = "coreSize", value = "2"),
? ? ? ? ? ? @HystrixProperty(name = "maxQueueSize", value = "20")}, commandProperties = {
? ? ? ? ? ? @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "9000")})
? ? @Override
? ? public String timeOut(Integer mills) {
? ? ? ? log.info("-----------mills:的值為:" + mills + "--------------");
? ? ? ? return userFeign.timeOut(mills);
? ? }
? ? @HystrixCommand(threadPoolKey = "time_1", threadPoolProperties = {
? ? ?? ??? ?@HystrixProperty(name = "coreSize", value = "2"),
? ? ? ? ? ? @HystrixProperty(name = "maxQueueSize", value = "20")}, commandProperties = {
? ? ? ? ? ? @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "9000")})
? ? @Override
? ? public String timeOut_1(Integer mills) {
? ? ? ? log.info("-----------mills:的值為:" + mills + "--------------");
? ? ? ? return userFeign.timeOut(mills);
? ? }
? /**
? ? * Hystrix的斷路器測試
? ? *?
? ? * 模擬測試:3秒鐘內,請求次數達到2次,并且失敗率在50%以上,斷路器做跳閘動作。跳閘后的活動窗口設置為3秒
? ? *
? ? * 服務的健康狀態檢查:http://ip:port/actuator/health
? ? * ?? ?Hystrix的健康狀態為:status: "UP"
? ? * ?? ?Hystrix的斷路器跳閘后狀態為:status: "CIRCUIT_OPEN"
? ? * ?? ?此時要刪除服務的降級處理類 UserFeignFallback,才能查看健康狀態
? ? ?*/
? ? @HystrixCommand(commandProperties = {
? ? ? ? ? ? @HystrixProperty(name = "metrics.rollingPercentile.timeInMilliseconds", value = "3000"),
? ? ? ? ? ? @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "2"),
? ? ? ? ? ? @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
? ? ? ? ? ? @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "3000")})
? ? @Override
? ? public String tripTest(Integer mills) {
? ? ? ? return userFeign.tripTest(mills);
? ? }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
鑒于篇幅,文章不再贅述,詳情可以查看:https://www.cnblogs.com/zhenbianshu/p/9630167.html
Hystrix 與 Ribbon 的超時時間
如果 hystrix.command.default.execution.timeout.enabled = true(默認),則會有兩個執行方法超時的配置:一個就是 ribbon 的 ReadTimeout,一個就是熔斷器 hystrix 的timeoutInMilliseconds,此時誰的值小誰生效
如果 hystrix.command.default.execution.timeout.enabled = false,則熔斷器不進行超時熔斷,而是根據 ribbon 的 ReadTimeout 拋出的異常而熔斷,也就是取決于 ribbon
ribbon 的 ConnectTimeout 配置的是請求服務的超時時間,除非服務找不到,或者網絡原因,這個時間才會生效
ribbon 還有 MaxAutoRetries 對當前實例的重試次數,MaxAutoRetriesNextServer 對切換實例的重試次數,如果 ribbon 的 ReadTimeout 超時,或者 ConnectTimeout 連接超時,會進行重試操作
由于 ribbon 的重試機制,通常熔斷的超時時間需要配置的比 ReadTimeout 長,ReadTimeout 比 ConnectTimeout 長,否則還未重試就熔斷了
為了確保重試機制的正常運作,理論上(以實際情況為準)建議 hystrix 的超時時間為:(1 + MaxAutoRetries + MaxAutoRetriesNextServer) * ReadTimeout
Hystrix 的斷路器工作原理
斷路器開啟的條件
當請求達到閥值時候:默認 10 秒內 20 次請求,當請求失敗率達到默認 50% 的時,此時斷路器將會開啟,所有的請求都不會執行
斷路器關閉的條件
當斷路器開啟 5 秒(默認)時,這時斷路器是半開狀態, 會允許其中一個請求執行
如果執行成功,則斷路器會關閉;如果失敗,則繼續開啟。循環重復這兩個流程
服務降級與服務熔斷區別
服務熔斷
熔斷機制是應對雪崩效應的一種微服務鏈路保護機制,一般來說,每個服務都需要熔斷機制的
如高壓電路中,如果某個地方的電壓過高,熔斷器就會熔斷,對電路進行保護。在微服務架構中,熔斷機制也是起著類似的作用
當扇出鏈路的某個微服務不可用,或響應超時,或宕機,或異常時,進而熔斷該節點微服務的調用,快速返回錯誤的響應信息。當檢測到該節點微服務調用響應正常后,恢復調用鏈路
使用注解 @HystrixCommand(fallbackMethod = " ") 來指定服務熔斷的回退方法
@Service
public class UserServiceImpl implements UserService {
?? ?private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
?? ?@Autowired
?? ?private UserFeign userFeign;
?? ?// 使用注解 @HystrixCommand 指定服務熔斷的回退方法
?? ?@HystrixCommand(fallbackMethod = "firstLoginError")
?? ?@Override
?? ?public String firstLogin(Integer id) {
?? ??? ?// 采用 Feign 客戶端來調用服務 Hystrix-study-activity
?? ??? ?String result = userFeign.getCoupon(id);
?? ??? ?log.info("===================result的值為:" + result + "======================");
?? ??? ?return result;
?? ?}
?? ?// 當服務 Hystrix-study-activity 不可用時,這時讓其回調回退方法
?? ?public String firstLoginError(Integer id) {
?? ??? ?return "---------您請求的服務暫時不可用,請稍后再試--------------";
?? ?}
}?? ?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
服務降級
降級是指自己的待遇下降了,從 RPC 調用環節來講,就是說整體資源快不夠了,忍痛將某些服務單元先關掉,關閉后還要返回一些可處理的備選方法,待渡過難關,再開啟回來
降級一般需要對業務有層級之分(比如降級一般是從最外圍服務開始)
@FeignClient(name = "STUDY-ACTIVITY", fallback = UserFeignFallback.class)
public interface UserFeign {
?? ?@RequestMapping(path = { "/activity/getCouponTimeOut" }, method = RequestMethod.POST)
?? ?String getCouponTimeOut(@RequestBody Integer id);
?? ?@RequestMapping(path = { "/demo/timeOut" }, method = RequestMethod.POST)
?? ?String timeOut(@RequestParam Integer mills);
}
1
2
3
4
5
6
7
8
9
@Component
public class UserFeignFallback implements UserFeign {
?? ?@Override
?? ?public String getCouponTimeOut(Integer id) {
?? ??? ?return "------超過2000毫秒時,直接進入服務降級處理------";
?? ?}
?? ?@Override
?? ?public String timeOut(Integer mills) {
?? ??? ?return "---------------您的請求【超時】或【失敗】,已進入服務降級模式了----------------";
?? ?}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
區別
相同點
目的很一致,都是從服務的可用性可靠性著想,為防止系統的整體緩慢甚至崩潰,采用的技術手段
最終表現類似,對于兩者來說,最終讓用戶體驗到的是某些功能暫時不可達或不可用
不同點
觸發原因不太一樣:服務熔斷一般是某個服務(下游服務)故障或異常引起,而服務降級一般是從系統整體負荷考慮的
管理層次不太一樣:熔斷其實是一個框架級的處理,每個服務都需要(無層級之分),而降級一般需要對業務有層級之分(比如降級一般是從最外圍服務開始)
————————————————
版權聲明:本文為CSDN博主「柳若煙」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_38192427/article/details/114176876
總結
- 上一篇: 揣姓是哪个民族的(揣姓)
- 下一篇: Seata 是什么?