一:雪崩效應
如下圖所示:A作為服務提供者,B為A的服務消費者,C和D是B的服務消費者。A不可用引起了B的不可用,並將不可用像滾雪球一樣放大到C和D時,導致整個系統癱瘓,雪崩效應就形成了。
雪崩過程:
1:由於網路或其他原因(硬件故障、程序Bug、用戶大量請求)A服務變得不可用,A服務的不可用導致B服務會出現線程的長阻塞,此時如果有大量的請求涌入(用戶重試加大流量),B服務servlet容器線程資源會被消耗完畢。大量請求的積壓,直接導致B服務變慢,最終癱瘓
2:B服務癱瘓的癱瘓同理會導致C、D服務的癱瘓,最后導致系統癱瘓
二:防雪崩利器
怎么防止雪崩效應的發生呢?
解決問題方案:對依賴做隔離,Hystrix就是處理依賴隔離的框架,同時也是可以幫我們做依賴服務的治理和監控
依賴隔離分為兩種,第一種線程池隔離(Thread-pool Rejection),第二種信號量隔離(semaphre Rejection)
a):線程隔離
首先:容器線程(tomcat、jetty)與 遠程服務調用線程隔離,即異步執行服務間遠程調用
其次:如果依賴多個微服務,多個依賴間相互隔離
線上建議線程池不要設置過大,否則大量堵塞線程有可能會拖慢服務器。
線程隔離的優點:
可以完全模擬異步調用,方便異步編程。
線程隔離的缺點:
線程開銷
線程隔離的適用場景
不受信服務(第三方接口服務)
有限依賴(依賴的服務不能太多)
NOTE:
Netflix公司內部認為線程隔離開銷足夠小,不會造成重大的成本或性能的影響。Netflix 內部API 每天100億的HystrixCommand依賴請求使用線程隔,每個應用大約40多個線程池,每個線程池大約5-20個線程。
b):信號隔離
信號隔離也可以用於限制並發訪問,防止阻塞擴散, 與線程隔離最大不同在於執行依賴代碼的線程依然是請求線程(該線程需要通過信號申請),
如果客戶端是可信的且可以快速返回,可以使用信號隔離替換線程隔離,降低開銷.
信號隔離優點
輕量,無額外開銷
信號隔離缺點
不支持異步調用
信號隔離的適用場景
受信服務(公司內部服務)
高依賴(網關)
三:HYSTRIX
a)hystrix簡介
所謂的熔斷機制和日常生活中見到電路保險絲是非常相似的,當出現了問題之后,保險絲會自動燒斷,以保護我們的電器,程序中我們也可以借用這個思想,使用Hystrix實現程序的熔斷。
hystrix對應的中文名字是“豪豬”,豪豬周身長滿了刺,能保護自己不受天敵的傷害,代表了一種防御機制,這與hystrix本身的功能不謀而合,因此Netflix團隊將該框架命名為Hystrix,並使用了對應的卡通形象做作為logo。
b)Hystrix快速體驗
Hystrix熔斷限流主要埋在客戶端,所以只需要在服務消費者方集成Hystrix。集成了Hystrix的客戶端,我們一般稱為Hystrix客戶端
1:pom依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId> spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
2:啟動類加@EnableCircuitBreaker
3:fallback邏輯
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.wendao.provider.consumer.pojo.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController public class ConsumerController { @Autowired private RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "fallback") @RequestMapping("/findOne") public User findOne(){ User user = restTemplate.getForObject("http://SPRING-CLOUD-SERVICE-PROVIDER/user/1", User.class); return user; } //fallback邏輯 private User fallback(){ //TODO .... return new User("fallback",12); } }
4:測試
關閉服務提供者,測試結果如下:
說明:
1:請求服務提供者失敗,怎么樣算失敗呢?
答:請求超時(默認1秒)算請求失敗,不一定是服務提供者沒啟動,即使服務提供者啟動,但是響應慢,超過了超時時間,一樣請求失敗。
可以通過下面方式設置超時時間
@HystrixCommand(fallbackMethod = "fallback",commandProperties = {
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="5000")
})
|
2:服務提供者請求失敗,會調用fallback邏輯,立即給客戶端響應,這種情況叫服務降級
@RestController public class ConsumerController { @Autowired private RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "fallback",commandProperties = { @HystrixProperty(name = "circuitBreaker.enabled",value="true"), @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value="10"), @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value="10000"), @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value="50"), }) @RequestMapping("/findOne") public User findOne(){ //如果熔斷器開啟是不會進入這個方法的,直接調用fallback邏輯 System.out.println("come in"); User user = restTemplate.getForObject("http://SPRING-CLOUD-SERVICE-PROVIDER/user/1", User.class); return user; } //fallback邏輯 private User fallback(){ //TODO .... return new User("fallback",12); } }
剛開始你會發現打印come in ,說明主邏輯方法還是執行了,還是發送了請求,只不過請求失敗,執行了fallback邏輯,這個時候只是服務降級。
一旦調用失敗次數過大就會導致熔斷器開啟,熔斷器如果open,那么就不可能讓你繼續執行主邏輯方法了,這時候fallback就成了主邏輯方法
其實上面演示的不是熔斷,熔斷器根本沒開啟,上面演示的只是服務降級。真正的熔斷器開啟是要滿足一定條件【閾值】,才會開啟熔斷器。
快照時間窗:斷路器確定是否打開需要統計一些請求和錯誤數據,而統計的時間范圍就是快照時間窗,默認為最近的10秒。
請求總數下限:在快照時間窗內,必須滿足請求總數下限才有資格根據熔斷。默認為20,意味着在10秒內,如果該hystrix命令的調用此時不足20次,即時所有的請求都超時或其他原因失敗,斷路器都不會打開。
circuitBreaker.requestVolumeThreshold
|
錯誤百分比下限:當請求總數在快照時間窗內超過了下限,比如發生了30次調用,如果在這30次調用中,有16次發生了超時異常,也就是超過50%的錯誤百分比,在默認設定50%下限情況下,這時候就會將斷路器打開。
circuitBreaker.errorThresholdPercentage
|
當熔斷器在10秒內發現請求總數超過20,並且錯誤百分比超過50%,這個時候熔斷器打開。打開之后,再有請求調用的時候,將不會調用主邏輯,而是直接調用降級邏輯,通過斷路器,實現了自動地發現錯誤並將降級邏輯切換為主邏輯,減少響應延遲的效果。
在斷路器打開之后,處理邏輯並沒有結束,我們的降級邏輯已經被成了主邏輯,那么原來的主邏輯要如何恢復呢?對於這一問題,hystrix也為我們實現了自動恢復功能。當斷路器打開,對主邏輯進行熔斷之后,hystrix會啟動一個休眠時間窗,在這個時間窗內,降級邏輯是臨時的成為主邏輯,當休眠時間窗到期,斷路器將進入半開狀態,釋放一次請求到原來的主邏輯上,如果此次請求正常返回,那么斷路器將繼續閉合,主邏輯恢復,如果這次請求依然有問題,斷路器繼續進入打開狀態,休眠時間窗重新計時。
六 feign對hystrix的支持
feign只能服務降級,無法進行服務熔斷,這個是我個人了解道德
使用方法:
在aplication。properties文件中添加配置:
feign.hystrix.enabled=true
創建熔斷類這個類是實現調用服務的那個接口的實現類:
@Component//不能忘記加上該注解 public class UserBizImpl implements IUserbiz { @Override public Map update(User user) { return new HashMap(); } }
再修改feign客戶端:
@FeignClient(value="spring-cloud-service-provider",fallback = UserBizImpl.class)
這樣就可以了