Why
在微服務(wù)架構(gòu)中协屡,由于調(diào)用關(guān)系的復(fù)雜性,如果調(diào)用鏈路中的某個(gè)資源不穩(wěn)定全谤,最終會(huì)導(dǎo)致請(qǐng)求發(fā)生堆積肤晓。可能導(dǎo)致服務(wù)間延遲增加认然,備份隊(duì)列补憾,線程和其他系統(tǒng)資源緊張,導(dǎo)致整個(gè)系統(tǒng)發(fā)生更多的級(jí)聯(lián)故障卷员。
為了維護(hù)服務(wù)的穩(wěn)定盈匾,我們需要在調(diào)用鏈路中某個(gè)資源出現(xiàn)不穩(wěn)定狀態(tài)時(shí)(例如調(diào)用超時(shí)或異常比例升高),對(duì)這個(gè)資源的調(diào)用進(jìn)行限制毕骡,讓請(qǐng)求快速失敗削饵,避免影響到其它的資源而導(dǎo)致級(jí)聯(lián)錯(cuò)誤。當(dāng)資源被降級(jí)后未巫,在接下來(lái)的降級(jí)時(shí)間窗口之內(nèi)窿撬,對(duì)該資源的調(diào)用都自動(dòng)熔斷(默認(rèn)行為是拋出 DegradeException)。
How
- 服務(wù)熔斷
一般發(fā)生于下游服務(wù)叙凡,下游服務(wù)發(fā)生故障時(shí)劈伴,將服務(wù)熔斷不可用
電路中的保險(xiǎn)絲,超過(guò)負(fù)荷握爷,直接熔斷跛璧,斷電,不可用新啼,保護(hù)整體安全 - 服務(wù)降級(jí)
將某一服務(wù)降級(jí)暫時(shí)不可用追城,為了服務(wù)整體的穩(wěn)定,犧牲部分不重要的功能燥撞,保證核心功能的進(jìn)行
媽媽讓小明去買醬油漓柑,給了10塊錢,小明到超市看到自己喜歡的玩具2塊錢,拿上玩具和醬油去柜臺(tái)結(jié)賬發(fā)現(xiàn)一共需要12元辆布,為了完成媽媽的任務(wù)瞬矩,選擇不買玩具。等下次在買玩具
所以從上述分析來(lái)看锋玲,兩者其實(shí)從有些角度看是有一定的類似性的:
目的很一致:都是從可用性可靠性著想景用,為防止系統(tǒng)的整體緩慢甚至崩潰,采用的技術(shù)手段惭蹂;
最終表現(xiàn)類似:對(duì)于兩者來(lái)說(shuō)伞插,最終讓用戶體驗(yàn)到的是某些功能暫時(shí)不可達(dá)或不可用;
自治性要求很高:熔斷模式一般都是服務(wù)基于策略的自動(dòng)觸發(fā)盾碗,降級(jí)雖說(shuō)可人工干預(yù)媚污,但在微服務(wù)架構(gòu)下,完全靠人顯然不可能廷雅,開關(guān)預(yù)置耗美、配置中心都是必要手段;
而兩者的區(qū)別也是明顯的:
觸發(fā)原因不太一樣航缀,服務(wù)熔斷一般是某個(gè)服務(wù)(下游服務(wù))故障引起商架,而服務(wù)降級(jí)一般是從整體負(fù)荷考慮;
What
由于我司使用nacos作為服務(wù)注冊(cè)和發(fā)現(xiàn)芥玉,所以我們使用sentinel進(jìn)行熔斷降級(jí)蛇摸。
首先導(dǎo)入依賴
// Gradle
implementation('com.alibaba.cloud:spring-cloud-starter-alibaba-sentinel') {
exclude module: 'guava'
}
// Maven
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
配置文件中打開sentinel
feign:
sentinel:
enabled: true
使用語(yǔ)言 kotlin
閱讀@FeignClient源碼,我們發(fā)現(xiàn)fallback是由spring創(chuàng)建
/**
* Fallback class for the specified Feign client interface. The fallback class must
* implement the interface annotated by this annotation and be a valid spring bean.
* @return fallback class for the specified Feign client interface
*/
Class<?> fallback() default void.class;
/**
* Define a fallback factory for the specified Feign client interface. The fallback
* factory must produce instances of fallback classes that implement the interface
* annotated by {@link FeignClient}. The fallback factory must be a valid spring bean.
*
* @see feign.hystrix.FallbackFactory for details.
* @return fallback factory for the specified Feign client interface
*/
Class<?> fallbackFactory() default void.class;
1.fallbackFactory
package com.karl.cloud;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import com.karl.DTO.UserInfoDTO;
@FeignClient(value = "karl-service-user", fallbackFactory = UserFallbackFactory::class)
interface UserFeign {
@GetMapping("/karl/user")
fun getUser(): UserInfoDTO
}
@Component
class UserFallbackFactory: FallbackFactory<UserFeign> {
val logger = LoggerFactory.getLogger(UserFallbackFactory::class.java)!!
override fun create(cause: Throwable): DataFeign {
logger.error(cause.message, cause)
return UserFallback()
}
}
class UserFallback: UserFeign {
override fun getUser(): UserInfoDTO{
return UserInfoDTO()
}
}
2.fallback
package com.karl.cloud;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import com.karl.DTO.UserInfoDTO;
@FeignClient(value = "karl-service-user", fallback = UserFallback::class)
interface UserFeign {
@GetMapping("/karl/user")
fun getUser(): UserInfoDTO
}
@Component
class UserFallback: UserFeign {
override fun getUser(): UserInfoDTO{
return UserInfoDTO()
}
}