分散式RPC框架Dubbo實現服務治理:整合Kryo實現高速序列化,整合Hystrix實現熔斷器

攻城獅Chova發表於2021-05-19

Dubbo+Kryo實現高速序列化

  • Dubbo RPC是Dubbo體系中最核心的一種高效能,高吞吐量的遠端呼叫方式,是一種多路複用的TCP長連線呼叫:
    • 長連線: 避免每次呼叫新建TCP連線,提高呼叫的響應速度
    • 多路複用: 單個TCP連線可交替傳輸多個請求和響應的訊息,降低了連線的等待時間,從而減少了同樣併發數的情況下網路連線數,提高了系統的雲吞吐量
  • Dubbo RPC主要用於兩個Dubbo之間的遠端呼叫,適合高併發,小資料的網際網路場景.序列化對於遠端呼叫的響應速度,吞吐量,網路頻寬消耗等同樣也起著至關重要的作用,是提升分散式系統效能的最關鍵因素之一
  • Dubbo中支援的序列化方式:
    • dubbo序列化: 阿里的高效java序列化實現
    • hessian2序列化: hessian是一種高效跨語言的二進位制序列化方式.這裡不是原生的hessian2序列化,而是阿里修改過的hessian lite,是Dubbo RPC預設啟動的序列化方式
    • json序列化: 目前有兩種實現-
      • 採用阿里的fastjson
      • 採用dubbo中實現的簡單json庫
      • json這種文字序列化效能不如dubbo序列化,hessian2序列化這兩種二進位制序列化
    • java序列化: 主要採用JDK自帶的Java序列化實現,效能差
  • 序列化方式:
    • 針對Java語言的序列化方式:Kryo,FST
    • 跨語言的序列化方式:Protostuff,ProtoBuf,Thrift,Avro,MsgPack
序列化:
1.序列化(serialization)在電腦科學的資料處理中,是指將資料結構或物件狀態轉換成可取用格式(例如存成檔案,存於緩衝,或經由網路中傳送),
以留待後續在相同或另一臺計算機環境中,能恢復原先狀態的過程。依照序列化格式重新獲取位元組的結果時,
可以利用它來產生與原始物件相同語義的副本。
2.簡單的來講就是將某種資料結構或者物件轉換成一種資料格式,資料格式可以通過網路傳送或者存入資料庫中,
同時可以根據資料格式還原出原來的資料結構(反序列化)。在 Java 中,物件只有在 JVM 執行時才會存在,如果想要把物件儲存到本地或者傳送到遠端的伺服器,
則必須通過序列化將物件轉換成相應的位元組然後進行儲存或者傳送,之後再將位元組組裝成物件。
3.在以下場景中都會遇到序列化:
		3.1將物件狀態儲存到檔案或者資料庫中
		3.2通過 socket 在網路中傳送物件
		3.3通過RMI(遠端方法呼叫)傳輸物件
  • 在面向生產的環境中,使用Dubbo+Kryo實現序列化:
    • 引入Kryo依賴kryo-serializers
    <dependency>
    	<groupId>de.javakaffee</groupId>
    	<artifactId>kryo-serializers</artifactId>
    	<version>0.42</version>
    </dependency>	
    
    • 配置檔案中增加配置
    dubbo.protocol. serialization=kryo
    
    • 註冊被序列化類
      • 要讓Kryo發揮高效能,需要將需要被序列化的實體類註冊到Dubbo系統中,實現如下回撥介面:
      public class SerializationOptimizerImpl implements SerializationOptimizerImpl{
        public Collection<class> getSerializableClasses(){
        		List<Class> classes=new LinkedList<class>();
        		classes.add(provider.class);
        		classes.add(consumer.class);
        		return classes;
        }
      }
      
      • 配置檔案中增加配置
      dubbo.protocol.optimizer=com.oxford.SerializationOptimizerImpl
      
      • 註冊這些類後,序列化的效能大大提升,特別是針對小數量的巢狀物件
1.為什麼需要手動註冊,不在配置檔案中註冊?
	因為要註冊的類往往數量較多,導致配置檔案冗長
	在沒有好的IDE支援下,配置檔案的編寫和重構都比Java類複雜得多
	這些註冊的類一般是不需要在專案編譯打包後還需要動態修改的
2.為什麼不用@annotation標註然後系統發現並註冊?
	因為annotation只能用來標註你可以修改的類,很多序列化的類是無法修改的(第三方庫,JDK系統和其它專案的類)
3.除了annotation,可以用其它方式來自動註冊被序列化的類,如掃描路徑,自動發現實現
Serializable介面(甚至包括Externalizable)的類並註冊,類路徑上找到Serializable類可能非常多,
可以用package字首來一定程度限定掃描範圍

在自動序號產生器制中,要保證服務提供端和消費端以同樣的順序(或者ID)來註冊類,避免錯位.因為可
被發現然後註冊的類的數量可能都是不一樣的
  • 注意:(無參建構函式Serializable介面)
  • 如果被序列化的類,不包含無參建構函式,則會導致Kryo序列化效能降低.因為底層將會使用Java的序列化來透明取代Kryo序列化.儘可能為每一個被序列化的類新增無參建構函式(Java類如果不自定義建構函式,預設就有無參建構函式)
  • Kryo和FST都不需要被序列化類實現Serializable介面,但還是需要每個序列化類都去實現Serializable介面,保持和Java序列化以及dubbo序列化相容性

Dubbo+Hystrix實現服務熔斷

  • 熔斷器:
    • 在微服務架構中,根據業務拆分成一個個的服務,服務服務之間通過RPC相互呼叫
    • 為了保證高可用,單個服務採用叢集部署,由於網路或者自身的原因,服務不能保證100%可用
    • 如果單個服務出現問題,呼叫這個服務就會出現出現執行緒阻塞,此時若大量的請求湧入,servlet容器的執行緒就會被消耗完畢,導致服務癱瘓,服務與服務之間的依賴性會導致故障傳播,進而導致整個微服務癱瘓,這就是"服務雪崩效應"
    • 為了解決服務雪崩效應,提出熔斷器的模型
  • 熔斷器模型:
    • 底層的服務出現故障,會導致連鎖故障
    • 當對特定服務呼叫的不可用到達一個閾值(Hystrix預設5秒20次),熔斷器就會被開啟
    • 熔斷器開啟後,為了避免連鎖故障,通過fallback方法直接返回一個固定值

Dubbo Provider中使用熔斷器

  • 在Provider(服務提供者)中增加依賴spring-cloud-starter-netflix-hystrix
  • 在主類中標註@EnableHystrix註解
  • 在介面實現類的服務呼叫方法上標註@HystrixCommand註解,呼叫Hystrix代理
可以在@HystrixCommand中的@HystrixProperty中配置閾值

Dubbo Consumer中使用熔斷器

  • 在Consumer(服務消費者)中增加依賴spring-cloud-starter-netflix-hystrix
  • 在主類上標註@EnableHystrix註解
  • 在呼叫類controller中的呼叫方法上標註 @HystrixCommand(fallback="熔斷返回頁面的方法名")

Dubbo+Hystrix熔斷器儀表盤

在Provider和Consumer中都需要配置Hystrix儀表盤,配置方式一致

Dubbo+Hystrix配置熔斷器儀表盤

  • 增加Hystrix儀表盤依賴spring-cloud-starter-netflix-hystrix-dashboard
  • 在主類上標註@EnableHystrixDashboard註解開啟Hystrix儀表盤功能
  • 建立hystrix.stream(監控路徑)的Servlet配置
@Configuration
public class HystrixDashBoardConfiguration{
	@Bean
	public ServletRegistrationBean getServlet(){
		HystrixMetricsStreamServlet streamServlet=new HystrixMetricsStreamServlet();
		ServletRegistrationBean registrationBean=new ServletRegistrationBean(streamServlet);
		registrationBean.setLoadOnStartup(1);
		registrationBean.addUrlMappings("/hystrix.stream");
		registrationBea.setName("HystrixMetricsStreamServlet");
		return registrationBean;
	}
}

Hystrix說明

觸發fallback方法

引數 描述
FAILURE 執行丟擲異常
TIMEOUT 執行開始,但沒有在指定的時間內完成
SHORT_CIRCUITED 斷路器開啟,不嘗試執行
THREAD_POOL_REJECTED 執行緒池拒絕,不嘗試執行
SEMAPHORE_REJECTED 訊號量拒絕,不嘗試執行

fallback方法丟擲異常

引數 描述
FALLBACK_FAILURE Fallback執行丟擲出錯
FALLBACK_REJECTED Fallback訊號量拒絕,不嘗試執行
FallBack_MISSING 沒有Fallback例項

Hystrix常用配置資訊

超時時間(預設1000ms)
  • hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 在Consumer中配置,Provider的所有方法的超時時間都是該值,優先順序低於下面的指定配置
  • hystrix.command.HystrixCommandKey.execution.isolation.thread.timeoutInMilliseconds: 在Consumer中配置,Provider的指定方法(HystrixCommandKey方法名)的超時時間都是該值
執行緒池核心執行緒數
  • hystrix.threadpool.default.coreSize: 預設為10,Consumer中配置
  • Queue:
    • hystrix.threadpool.default.maxQueueSize: 最大排隊長度,預設-1,使用 SynchronousQueue, 其他值使用LinkedBlockingQueue. 如果要從-1換成其他值重啟,即該值不能動態調整,需要使用下邊這個配置
    • hystrix.threadpool.default.queueSizeRejectionThreshold: 排隊執行緒數量閾值,預設為5,達到時拒絕,如果配置了該選項,佇列的大小是該佇列(注意: 如果maxQueueSize=-1的話,則該選項不起作用)
斷路器
  • hystrix.command.default.circuitBreaker.requestVolume.Threshold: 當在配置時間視窗內達到此數量的失敗後,進行短路,預設20個
  • hystrix.command.default.circuitBreaker.sleepWindowinMilliseconds: 短路一定的時間開始嘗試是否恢復,預設5s
  • hystrix.command.default.circuitBreaker.errorThresholdPercentage: 出錯百分比閾值,當達到此閾值後,開始短路,預設50%
fallback
  • hystrix.command.default.fallback.isloation.semaphore.maxConcurrentRequests: 呼叫執行緒(Consumer)允許請求HystrixCommand.GetFallback()最大數量,預設為10.(注意: 該項配置對於THREAD隔離模式也生效)

相關文章