SpringCloud:Hystrix(服務熔斷、服務降級)
1、分散式系統面臨的問題
(1)服務雪崩
多個微服務之間呼叫的時候,假設微服務A呼叫微服務B和C,微服務B和C又呼叫其它的微服務,這就是所謂的“扇出”。如果扇出的鏈路上某個微服務的呼叫響應時間過長或者不可用,對微服務A的呼叫就會佔用越來越多的系統資源,進而引起系統崩潰,引起所謂的“雪崩效應”。
對於高流量的應用來說,單一的後端依賴可能會導致所有伺服器上的所有資源都在幾秒鐘內飽和。比失敗更糟糕的是,這些應用程式還可能導致服務之間的延遲增加,備份佇列,執行緒和其他系統資源緊張,導致整個系統發生更多的級聯故障。這些都表示需要對故障和延遲進行隔離和管理,以便單個依賴關係的失敗,不能取消整個應用程式或系統。
(2)解決方案
- 熔斷模式
這種模式主要是參考電路熔斷,如果一條線路電壓過高,保險絲會熔斷,防止火災。放到我們的系統中,如果某個目標服務呼叫慢或者有大量超時,此時,熔斷該服務的呼叫,對於後續呼叫請求,不在繼續呼叫目標服務,直接返回,快速釋放資源。如果目標服務情況好轉則恢復呼叫。
- 隔離模式
這種模式就像對系統請求按型別劃分成一個個小島的一樣,當某個小島被火燒光了,不會影響到其他的小島。例如:可以對不同型別的請求使用執行緒池來資源隔離,每種型別的請求互不影響,如果一種型別的請求執行緒資源耗盡,則對後續的該型別請求直接返回,不再呼叫後續資源。這種模式使用場景非常多,例如將一個服務拆開,對於重要的服務使用單獨伺服器來部署,再或者公司最近推廣的多中心。
- 限流模式
上述的熔斷模式和隔離模式都屬於出錯後的容錯處理機制,而限流模式則可以稱為預防模式。限流模式主要是提前對各個型別的請求設定最高的QPS閾值,若高於設定的閾值則對該請求直接返回,不再呼叫後續資源。這種模式不能解決服務依賴的問題,只能解決系統整體資源分配問題,因為沒有被限流的請求依然有可能造成雪崩效應。
2、服務熔斷
(1)概念
當扇出鏈路的某個微服務不可用或者響應時間太長時,會進行服務的降級,進而熔斷該節點微服務的呼叫,快速返回"錯誤"的響應資訊。當檢測到該節點微服務呼叫響應正常後恢復呼叫鏈路。在SpringCloud框架裡熔斷機制通過Hystrix實現。Hystrix會監控微服務間呼叫的狀況,當失敗的呼叫到一定閾值,預設是5秒內20次呼叫失敗就會啟動熔斷機制。
(2)實現
- 模仿8001埠新建Hystrix模組(服務的提供者)
新增依賴:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency>
配置檔案中修改服務的名稱:
instance: instance-id: my8001-hystrix prefer-ip-address: true
定義Controller:
一旦呼叫GET方法失敗並丟擲了錯誤資訊後,會自動呼叫@HystrixCommand標註好的fallbackMethod呼叫類中的指定方法。但是,此種方式會存在一個問題就是每一個方法都需要一個處理
@RestController public class DeptController { @Autowired private DeptService service = null; @RequestMapping(value="/dept/get/{id}",method= RequestMethod.GET) @HystrixCommand(fallbackMethod = "processHystrix_Get") public Dept get(@PathVariable("id") Long id) { Dept dept = this.service.get(id); if(null == dept) { throw new RuntimeException("該ID:"+id+"沒有沒有對應的資訊"); } return dept; } public Dept processHystrix_Get(@PathVariable("id") Long id) { return new Dept().setDeptno(id) .setDname("該ID:"+id+"沒有沒有對應的資訊,null--@HystrixCommand") .setDb_source("no this database in MySQL"); } }
在啟動類中新增對hystrixR熔斷機制的支援
@EnableCircuitBreaker
- 測試
3、服務降級
(1)概念
整體資源不足,將某些服務先關掉,待渡過難關,再重新開啟,服務降級是在客戶端完成的。
(2)實現
- API模組(公共模組)
新建一個實現了FallbackFactory介面的類DeptClientServiceFallbackFactory,該介面是專門處理異常的,與上面的服務熔斷處理異常的方式相比,此種方式實現了邏輯與異常處理業務的分離
@Component public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService> { @Override public DeptClientService create(Throwable throwable) { return new DeptClientService() { @Override public Dept get(long id) { return new Dept().setDeptno(id) .setDname("該ID:" + id + "沒有沒有對應的資訊,Consumer客戶端提供的降級資訊,此刻服務Provider已經關閉") .setDb_source("no this database in MySQL"); } @Override public List<Dept> list() { return null; } @Override public boolean add(Dept dept) { return false; } }; } }
在API模組中的業務介面的註解中新增屬性:
@FeignClient(value = "PROVIDER",fallbackFactory=DeptClientServiceFallbackFactory.class) public interface DeptClientService { @RequestMapping(value = "/dept/get/{id}",method = RequestMethod.GET) public Dept get(@PathVariable("id") long id); @RequestMapping(value = "/dept/list",method = RequestMethod.GET) public List<Dept> list(); @RequestMapping(value = "/dept/add",method = RequestMethod.POST) public boolean add(Dept dept); }
- Feign模組(消費者模組)
feign: hystrix: enabled: true
(3)測試
在只啟動一個服務的提供者(8001)的情況下,能夠正常訪問,當講該服務關閉的時候能夠給出提示資訊。也就是說在服務端不可用的時候客戶端能夠得到提示,而不是掛起。