天天看點

分布式RPC架構Dubbo實作服務治理實用示例:內建Kryo實作高速序列化,內建Hystrix實作熔斷器Dubbo+Kryo實作高速序列化Dubbo+Hystrix實作服務熔斷Dubbo+Hystrix熔斷器儀表盤Hystrix說明

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方法

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隔離模式也生效)