1. 程式人生 > >Hystrix斷路器+分散式系統面臨的問題+Hystrix介紹+服務熔斷介紹+服務熔斷案例+ 解耦與降級處理介紹+ 解耦與降級處理案例

Hystrix斷路器+分散式系統面臨的問題+Hystrix介紹+服務熔斷介紹+服務熔斷案例+ 解耦與降級處理介紹+ 解耦與降級處理案例

 測試中使用到的程式碼到在這裡https://download.csdn.net/download/zhou920786312/10853300

 

轉載https://blog.csdn.net/qq_33404395/article/details/80913571

Hystrix斷路器

 

前言

  高可用相關的技術以及架構,對於大型複雜的分散式系統,是非常重要的。而高可用架構中,非常重要的一個環節,就是如何將分散式系統中的各個服務打造成高可用的服務,從而足以應對分散式系統環境中的各種各樣的問題,比如服務間的呼叫超時,或者服務間的呼叫失敗,避免整個分散式系統被某個服務的故障給拖垮。而要解決這些棘手的分散式系統可用性問題,就涉及到了高可用分散式系統中的很多重要的技術,包括資源隔離,限流與過載保護,熔斷,優雅降級,容錯,超時控制,監控運維,等等。而行業中大部分的朋友,對高可用系統架構以及相關的技術並沒有太多的瞭解,這也成為了你設計一個複雜的高可用系統架構,或者面試高階Java職位時的一個重要阻礙。

   在行業中,實現高可用架構的非常流行和重要的框架就是Hystrix,是國外知名的視訊網站Netflix所開源的。Hystrix能夠完美的解決分散式系統架構中,打造高可用服務面臨的一系列技術難題,包括資源隔離,限流與過載保護,熔斷,優雅降級,容錯,超時控制,監控運維等等。

 

分散式系統面臨的問題:

1.扇出:

    多個微服務互相呼叫的時候,如果A呼叫B、C,而B、C又繼續呼叫其他微服務,這就是扇出(像一把扇子一樣慢慢開啟)。

2.服務雪崩:

      刪除過程中,如果某一個環節的服務出現故障或連線超時,就會導致前面的服務佔用越來越多的資源,進而引起系統崩潰,就是“雪崩效應”。

      對於高流量的應用來說,單一的後端依賴會導致伺服器所有的資源都在幾秒鐘內飽和。比失敗更糟糕的是,這些應用程式還可能導致服務之間的延遲增加,備份佇列,執行緒和其他系統資源緊張,導致整個系統發生更多的級聯故障。這些都表示需要【對故障和延遲進行隔離和管理】,以便單個依賴關係的失敗,不能影響整個應用程式或系統。

Hystrix介紹

  •  Hystrix是一個用於處理分散式系統延遲和容錯的開源庫。分散式系統中,依賴避免不了呼叫失敗,比如超時,異常等。Hystrix能保證在出現問題的時候,不會導致整體服務失敗,避免級聯故障,以提高分散式系統的彈性。
  •  Hystrix類似一個“斷路器”,當系統中異常發生時,斷路器給呼叫返回一個符合預期的,可處理的FallBack,這樣就可以避免長時間無響應或丟擲異常,使故障不能再系統中蔓延,造成雪崩。 

 

服務熔斷介紹

  • - 熔斷機制的註解是@HystrixCommand;
  • - 熔斷機制是應對雪崩效應的一種【鏈路保護機制】,一般存在於服務端;
  • - 當扇出鏈路的某個服務出現故障或響應超時,會進行【服務降級】,進而【熔斷該節點的服務呼叫】,快速返回“錯誤”的相應資訊(就是出現服務故障的預選方案),當檢測到該節點微服務正常後,就恢復該節點的呼叫。
  • - Hystrix的熔斷存在閾值,預設是5秒內20次呼叫失敗就會觸發;
  • 一般是某個服務故障或者異常引起,類似顯示世界中的“保險絲”,當某個異常條件被觸發,直接熔斷整個服務,而不是一直等到此服務超時。 

服務熔斷案例

 

 

拷貝一個8001服務單元的程式碼,修改如下

package com.atguigu.springcloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.atguigu.springcloud.entities.Dept;
import com.atguigu.springcloud.service.DeptService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;

@RestController
public class DeptController
{
	@Autowired
	private DeptService service = null;

	@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
	//一旦呼叫服務方法失敗並丟擲了錯誤資訊後,會自動呼叫@HystrixCommand標註好的fallbackMethod呼叫類中的指定方法
	@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 + "沒有對應的資訊,[email protected]");
	}
}

package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient //本服務啟動後會自動註冊進eureka服務中
@EnableDiscoveryClient //服務發現
@EnableCircuitBreaker//對hystrixR熔斷機制的支援
public class DeptProvider8001_Hystrix_App
{
	public static void main(String[] args)
	{
		SpringApplication.run(DeptProvider8001_Hystrix_App.class, args);
	}
}

server:
  port: 8001
  
mybatis:
  config-location: classpath:mybatis/mybatis.cfg.xml  #mybatis所在路徑
  type-aliases-package: com.atguigu.springcloud.entities #entity別名類
  mapper-locations:
  - classpath:mybatis/mapper/**/*.xml #mapper對映檔案
    
spring:
   application:
    name: microservicecloud-dept 
   datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: org.gjt.mm.mysql.Driver
    url: jdbc:mysql://localhost:3306/cloudDB01
    username: root
    password: root
    dbcp2:
      min-idle: 5
      initial-size: 5
      max-total: 5
      max-wait-millis: 200
      
eureka:
  client: #客戶端註冊進eureka服務列表內
    service-url: 
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: microservicecloud-dept8001-hystrix   #自定義hystrix相關的服務名稱資訊
    prefer-ip-address: true     #訪問路徑可以顯示IP地址
      
info:
  app.name: atguigu-microservicecloud
  company.name: www.atguigu.com
  build.artifactId: $project.artifactId$
  build.version: $project.version$
      
      
      
 

    <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-hystrix</artifactId>
        </dependency>

測試結果

 

 解耦與降級處理介紹

  1.何為降級:

  • 當系統整體資源快不夠的時候,忍痛將部分服務暫時關閉,待渡過難關後,再重新開啟。
  • 降級處理是在【客戶端】完成的,與服務端沒有關係。
  • 降級針對的是服務熔斷之後處理。
  • 降級一般是從【整體負荷】考慮,當某個服務熔斷之後,伺服器將不再被呼叫,此時客戶端可以自己準備一個本地的FallBack回撥,  返回 一個預設值。這樣做雖然服務水平下降,但好歹可用,比直接掛掉好。

 

2.為什麼要解耦?

      如果按照上面的熔斷案例來做的話,Controller下的每個方法,都要給其編寫一個FallBack方法,當方法慢慢變多,就會造成程式碼膨脹,一個是增加編寫的工作量,另外一個也會增大維護的難度,程式碼的耦合度也會高,是十分不合理的,所以要將其解耦。
3.解耦思路:

      因為服務端的是通過實現介面訪端的,如果在父介面上實現了FallBack方法,通過這樣一種方式去維護起來就能實現解耦,也順便完成了降級的機制。 

 

解耦與降級處理案例

microservicecloud-api

 

 

package com.atguigu.springcloud.service;

import java.util.List;

import org.springframework.stereotype.Component;

import com.atguigu.springcloud.entities.Dept;

import feign.hystrix.FallbackFactory;

@Component // 這個註解一定要新增
//FallbackFactory對DeptClientService的所有方法設定熔斷處理方案,方案在每個方法上傳
public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService>
{
	@Override
	public DeptClientService create(Throwable throwable)
	{
//		對DeptClientService的所有方法設定熔斷處理方案,方案在每個方法上傳
		return new DeptClientService() {
			@Override
			public Dept get(long id)
			{
				return new Dept().setDname("Dept get方法沒有沒有對應的資訊");
			}

			@Override
			public List<Dept> list()
			{
				return null;
			}
			@Override
			public boolean add(Dept dept)
			{
				return false;
			}
		};
	}
}

 

 

 

 

 

package com.atguigu.springcloud.service;

import java.util.List;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.atguigu.springcloud.entities.Dept;


////客戶端,呼叫該介面就可以實現對MICROSERVICECLOUD-DEPT服務單元的負載均衡
//@FeignClient(value = "MICROSERVICECLOUD-DEPT")

//客戶端,呼叫該介面就可以實現對MICROSERVICECLOUD-DEPT服務單元的負載均衡
//fallbackFactory是對這個DeptClientService介面的熔斷處理方案(DeptClientServiceFallbackFactory)
@FeignClient(value = "MICROSERVICECLOUD-DEPT",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);
}

 

microservicecloud-consumer-dept-feign

 

server:
  port: 80
  

#對整個介面的熔斷處理方案
feign: 
  hystrix: 
    enabled: true



eureka:
  client:
    register-with-eureka: false
    service-url: 
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/  

測試

 

現在關閉8001服務,在訪問的時候,應該客戶端有個預設的預備方案(服務降級)