springcloud微服務總結五 服務熔斷


一:雪崩效應

如下圖所示:A作為服務提供者,B為A的服務消費者,C和D是B的服務消費者。A不可用引起了B的不可用,並將不可用像滾雪球一樣放大到C和D時,導致整個系統癱瘓,雪崩效應就形成了。

 

20180519182935328.png

 

雪崩過程:

1:由於網路或其他原因(硬件故障、程序Bug、用戶大量請求)A服務變得不可用,A服務的不可用導致B服務會出現線程的長阻塞,此時如果有大量的請求涌入(用戶重試加大流量),B服務servlet容器線程資源會被消耗完畢。大量請求的積壓,直接導致B服務變慢,最終癱瘓

2:B服務癱瘓的癱瘓同理會導致C、D服務的癱瘓,最后導致系統癱瘓

 

二:防雪崩利器

怎么防止雪崩效應的發生呢? 

解決問題方案:對依賴做隔離,Hystrix就是處理依賴隔離的框架,同時也是可以幫我們做依賴服務的治理和監控

依賴隔離分為兩種,第一種線程池隔離(Thread-pool Rejection),第二種信號量隔離(semaphre Rejection)

 

b90615c1-f7cb-3cf1-9bf3-de11d5f57697.png

 

 

a):線程隔離

    首先:容器線程(tomcat、jetty)與   遠程服務調用線程隔離,即異步執行服務間遠程調用      

    其次:如果依賴多個微服務,多個依賴間相互隔離

    線上建議線程池不要設置過大,否則大量堵塞線程有可能會拖慢服務器。

線程隔離的優點:

        可以完全模擬異步調用,方便異步編程。

線程隔離的缺點:

        線程開銷

線程隔離的適用場景

       不受信服務(第三方接口服務)

        有限依賴(依賴的服務不能太多)

NOTE: 

Netflix公司內部認為線程隔離開銷足夠小,不會造成重大的成本或性能的影響。Netflix 內部API 每天100億的HystrixCommand依賴請求使用線程隔,每個應用大約40多個線程池,每個線程池大約5-20個線程。

 

b):信號隔離

      信號隔離也可以用於限制並發訪問,防止阻塞擴散, 與線程隔離最大不同在於執行依賴代碼的線程依然是請求線程(該線程需要通過信號申請),

   如果客戶端是可信的且可以快速返回,可以使用信號隔離替換線程隔離,降低開銷.

信號隔離優點

       輕量,無額外開銷

 

信號隔離缺點

        不支持異步調用

信號隔離的適用場景

      

        受信服務(公司內部服務)

        高依賴(網關)

 

 

 

 

三:HYSTRIX

a)hystrix簡介

所謂的熔斷機制和日常生活中見到電路保險絲是非常相似的,當出現了問題之后,保險絲會自動燒斷,以保護我們的電器,程序中我們也可以借用這個思想,使用Hystrix實現程序的熔斷。

719930-20170903171704624-1917697781.png

 

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:測試

關閉服務提供者,測試結果如下:

image.png

說明:

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就成了主邏輯方法

五:熔斷器狀態機

其實上面演示的不是熔斷,熔斷器根本沒開啟,上面演示的只是服務降級。真正的熔斷器開啟是要滿足一定條件【閾值】,才會開啟熔斷器。

image.png

 

 快照時間窗:斷路器確定是否打開需要統計一些請求和錯誤數據,而統計的時間范圍就是快照時間窗,默認為最近的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)

這樣就可以了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM