Java程式設計良心推薦——分散式架構原理解析

慕容千語發表於2018-09-29
Java程式設計良心推薦——分散式架構原理解析

應用架構演進

這裡的架構演進應該是從服務化的角度來說,應該說隨著業務發展,應用規模擴大,系統的一些公共服務就會抽取出來,獨立開發,部署,維護,用來解決併發,擴充套件,維護的問題。

傳統垂直架構

有的地方也叫單體應用,以mvc模式開發:

  1. 所有應用程式碼統一打包,程式碼所有介面本地api呼叫,很少存在遠端服務呼叫;
  2. 單機或主備,應用做叢集部署;
  3. DB主從等。

這種並沒有什麼不好,發展初期大多是這樣,體量沒那麼大,也不需要考慮高併發大流量可擴充套件性什麼的,簡單粗暴,解決業務需求就好,活下去才能活的更好。

但是必須明白這種簡單架構存在的一些問題:

1. 業務不斷髮展,功能逐漸增多,應用的開發維護成本變高,部署效率降低,隨便改個程式碼,編譯一次十幾分鍾就浪費了。悲劇,我們有個系統才開發3年,就碰到這種情況,一次打包編譯部署,13分鐘結束。

2. 不同的人負責不同的部分,一些通用程式碼、公共程式碼就各寫各的,不能複用,如果只是util還好,但是一些外部服務的都有重複,那就happy了(不過這種情況的出現,不一定是架構問題,更多可能是管理);

3. 不斷地上新需求,不斷地改程式碼,有時測試不到位,指定哪裡埋了bug,上生產後系統就down了,牽一髮而動全身;

4. 可維護性,可靠性,擴充套件性變差。

既然有這些問題,就要解決啊,業務就會提要求,你要解決啊,要不然影響我業務發展,影響我ipo上市啊,苦逼的碼農開始幹活了。

不提應用的拆分主從那些手段,但從拆分後應用互動看,原來的本地api互動變成的遠端api的呼叫,這裡就出現了rpc,當然也有走esb,webservice。其實拆分後挺麻煩的,光一個分散式事務就能折騰死人。

RPC架構

Remote Procedure Call,遠端方法呼叫,遮蔽底層實現細節,像呼叫本地方法一樣呼叫遠端服務。

上個作者的圖:

Java程式設計良心推薦——分散式架構原理解析

這個圖對於大多數rpc框架通用,實現的幾個技術點:

1. 服務提供者釋出服務:服務介面定義,資料結構,服務提供者資訊等;

2. 客戶端遠端呼叫:通常是使用jdk的程式碼代理攔截;

3. 底層通訊:現在應該更多是使用netty吧,當然也有走支援http的;

4. 序列化:關注序列化反序列效能,xml,json,hessiaon,pb,protostuff,kryo等;

作者給了個socket實現簡單demo,來實現遠端呼叫,說明上面幾個技術點。

常用的rpc框架

1. Thrift;

2. Hadoop的Avro-RPC;

3. Hessian;

4. gRPC;

單論rpc的話,沒太多可說的,可是如果加上服務治理,那複雜度就幾何倍數增長了。服務治理裡面東西太多了,動態註冊,動態發現,服務管控,呼叫鏈分析等等問題這些問題,單憑rpc框架解決不了,所以現在常用的說的服務化框架,通常指的是rpc+服務治理2個點。

SOA服務化架構

感覺soa架構應該是在rpc之前出現,用來解決異構系統的互動,通常的實現是通過ESB,WSDL來處理。其粒度通常來說是比較粗的。也存在服務治理方面的問題。

微服務

MSA也是一種服務化架構風格,正流行ing,服務劃分

1. 原子服務,粒度細;

2. 獨立部署,主要是容器;

分享篇文章:雲棲肥俠的文章 微服務(Microservice)那點事 。

MSA與SOA的對比:

  1. 服務拆分粒度:soa首要解決的是異構系統的服務化,微服務專注服務的拆分,原子服務;
  2. 服務依賴:soa主要處理已有系統,重用已有的資產,存在大量服務間依賴,微服務強調服務自治,原子性,避免依賴耦合的產生;
  3. 服務規模:soa服務粒度大,大多數將多個服務合併打包,因此服務例項數有限,微服務強調自治,服務獨立部署,導致規模膨脹,對服務治理有挑戰;
  4. 架構差異:微服務通常是去中心化的,soa通常是基於ESB的;
  5. 服務治理:微服務的動態治理,實時管控,而soa通常是靜態配置治理;
  6. 交付:微服務的小團隊作戰。

感覺在有了docker後,微服務這個概念突然火了起來,總結就是微服務+容器+DevOps。

Java程式設計良心推薦——分散式架構原理解析

分散式服務框架入門

背景

應用從集中式走向分散式

隨著業務的發展導致功能的增多,傳統的架構模式開發,測試,部署整個流程變長,效率變低,後臺服務的壓力變大,只能通過硬體擴容來暫時緩解壓力,但解決不了根本性問題:

  1. 應用規模變大,開發維護成本變高,部署效率降低;
  2. 程式碼複用:原來是本地api呼叫,導致一些公用功能可能是按需開發,不統一,隨意等問題;
  3. 交付面臨困難:主要是業務變得複雜,新增修改測試變得困難,拉長整個流程。

通用法寶:拆分,大系統拆小系統,獨立擴充套件和伸縮。

  1. 縱向:分業務模組;
  2. 橫向:提煉核心功能,公共業務;

需要服務治理

大拆小,核心服務提煉後,服務的數量變多,而且需要一些執行態的管控,這時候就需要服務治理:

  1. 服務生命週期管理;
  2. 服務容量規劃;
  3. 執行期治理;
  4. 服務安全。

服務框架介紹

Dubbo

阿里開源的Dubbo應該是業界分散式服務框架最出名的了吧,看過公司的rpc框架,Dubbo的擴充套件性比我們的好的多了,我們的框架每次升級,改動都很多,改天要看下Dubbo的原始碼瞭解瞭解擴充套件性。

Java程式設計良心推薦——分散式架構原理解析

Java程式設計良心推薦——分散式架構原理解析

HSF

淘寶的體量決定了他對極致效能的追求,HSF跨機房特性挺牛。

Java程式設計良心推薦——分散式架構原理解析

Java程式設計良心推薦——分散式架構原理解析

Coral Service

這個沒聽說過,孤陋寡聞了。

Java程式設計良心推薦——分散式架構原理解析

框架設計

架構原理

萬變不離其中,這張圖可以概括rpc的一些通用原理:

Java程式設計良心推薦——分散式架構原理解析

細化了下:

Java程式設計良心推薦——分散式架構原理解析

  1. rpc層:底層的通訊框架,通訊協議,序列化和反序列化;
  2. 服務釋出訂閱;
  3. 服務治理;

功能

Java程式設計良心推薦——分散式架構原理解析

Java程式設計良心推薦——分散式架構原理解析

Java程式設計良心推薦——分散式架構原理解析

效能

Java程式設計良心推薦——分散式架構原理解析

可靠性

Java程式設計良心推薦——分散式架構原理解析

分散式的,面試會問,用池子的話講就是,知識點啊。

服務治理

Java程式設計良心推薦——分散式架構原理解析

Java程式設計良心推薦——分散式架構原理解析

通訊框架

技術點

  1. 長連線:主要是鏈路的建立過程到最後的關閉,耗時耗資源;每次呼叫都要建立的話,呼叫時延的問題,很可能鏈路建立的耗時比程式碼真正執行時長還多;
  2. BIO還是NIO:主要是執行緒模型的選擇,推薦篇文章 IO - 同步,非同步,阻塞,非阻塞 (亡羊補牢篇);
  3. 自研還是使用開源NIO框架:一般來說還是使用開源吧,技術成熟,社群支援,現在netty和mina使用較多了吧。
Java程式設計良心推薦——分散式架構原理解析

在功能設計方面,作者基於netty給了demo服務端和客戶端的程式碼,個人理解:

1. 通用性api;

2. 擴充套件性,封裝底層,提供上層介面,隔離協議和底層通訊;

可靠性設計

談分散式系統必談可靠性。

鏈路有效性

通過心跳來確認雙方c、s存活,保證鏈路可用,心跳檢測機制分為3個層面:

1. tcp層面,即tcp的keep-alive,作用於整個tcp協議棧;

2. 協議層的心跳檢測,主要存在於長連線協議中,例如smpp協議;

3. 應用層的心跳,業務雙方的定時傳送心跳訊息;

第2個沒聽說過,常用的是1,3。一般使用netty的話用的是netty的讀寫空閒來實現心跳。

斷連

不管因為網路掛了還是服務端當機,還是心跳超時什麼的,導致鏈路不可用關閉,這時候就需要鏈路重連,需要注意的一點就是短連後,不要立即重連,留時間給系統釋放資源,可以scheduler處理。

訊息快取重發

底層訊息不會立即傳送(也會導致半包粘包),斷鏈後,導致訊息丟失,看有無業務需求,有就支援斷鏈後訊息重發。

資源釋放

主要是斷鏈後,一定要保證資源銷燬和釋放,當然也包括一些執行緒池,記憶體等的釋放。

效能設計

效能差的三宗罪

對於底層通訊框架來說,主要是下面幾個:

1. 通訊模型的選擇,主要是阻塞非阻塞那些東西;

2. 序列化反序列化(後面有章單講序列化);

3. 執行緒模型,主要是服務端選擇什麼樣的執行緒模型來處理訊息。

通訊效能三原則

既然有上面的3個問題,那就針對這些做優化了:

  1. 傳輸:BIONIOAIO的選擇;
  2. 選擇自定義協議棧,便於優化;
  3. 服務端執行緒模型,單執行緒處理還是執行緒池,執行緒池是一個,還是分優先順序,Reactor還是其他什麼的。

高效能之道這節作者講了netty的優勢。

序列化與反序列化

也就是通常所說的編碼、解碼。通常的通訊框架會提供編解碼的介面,也會內建一些常用的序列化反序列化工具支援。

與通訊框架和協議的關係,感覺可以理解為:通訊框架是通道,其上跑的碼流資料是利用各種序列化編碼後的各種協議。

功能設計

各種序列化框架需要考慮的主要有:

  • 序列化框架本身的功能的豐富,支援的資料型別;
  • 多語言的支援;
  • 相容性,往大了說:
  1. 服務介面的前後相容;
  2. 協議的相容;
  3. 支援的資料型別的相容。
  • 效能,目的是最少的資源,最快的速度,最大的壓縮:
  1. 序列化後碼流大小;
  2. 序列化的速度;
  3. 序列化的資源佔用。

在擴充套件性這節,作者講了netty的對序列化的一些內建支援,但實際開發中,一般不太會使用這些東西,都會提供序列化反序列介面,自行擴充套件定義,所以擴充套件性特重要。

常用的序列化,xml,json,hessian,kryo,pb,ps,看需求需要支援那種,具體可以搜尋各序列化的效能和壓縮後大小。

協議棧

這一章最主要的是講了自定義協議棧的設計,已經互動的過程,其他講的可靠性設計什麼的跟之前通訊框架一章有重複。

通訊模型

Java程式設計良心推薦——分散式架構原理解析

服務提供者和消費者之間採用單鏈路,長連線通訊,鏈路建立流程:

1. 客戶端傳送握手請求,攜帶節點ID等認證資訊;

2. 服務端校驗:節點ID有效性,重複登入,ip地址黑白名單等,通過後,返回握手應答資訊;

3. 鏈路建立後,客戶端傳送業務訊息;

4. 客戶端服務端心跳維持鏈路;

5. 服務端退出時,關閉連線,客戶端感知連線關閉,關閉客戶端連線。

協議訊息定義

Java程式設計良心推薦——分散式架構原理解析

Java程式設計良心推薦——分散式架構原理解析

通過attachment相容了擴充套件性。作者還講了將訊息頭的通用序列化和訊息體的自定義序列化,看需求吧,我們公司的框架沒做這部分支援,做了簡化,將訊息頭和訊息體統一封裝,然後再加一個序列化方式組成一條訊息傳送。

安全性設計

  1. 內部的,不一定需要認證,也有基於系統,域名,ip的黑白名單,安全認證的;
  2. 外部開發平臺的話,基於祕鑰認證;

服務路由

服務路由指的是服務提供者叢集部署,消費端如何從服務列表中選擇合適的服務提供者提供服務進行呼叫。

透明化路由

  1. 基於zk的服務註冊中心的釋出訂閱;
  2. 消費者本地快取服務提供者列表,註冊中心當機後,不影響已有的使用,只是影響新服務的註冊和老服務的下線。

負載均衡

  • 隨機
  • 輪循
  • 服務呼叫時延
  • 一致性Hash
  1. 有個一致性hash演算法,挺有意思的,redis的客戶端shard用的
Java程式設計良心推薦——分散式架構原理解析


  • 黏滯連線
  1. 這個應該不太常用,服務提供者多數無狀態,一旦有狀態,不利於擴充套件

這些都是點對點的連線,負載均衡大多會在客戶端執行,有種場景會取決於服務端負載,就是服務端服務配置的是域名。

本地路由優先策略

  • injvm:jvm也提供了消費端的服務,可以改成優先本jvm,對於消費端來說,不需關注提供者;
  • innative:injvm比較少,多得是可能是這種,一個物理機部署多個虛擬機器,或者一個容器部署多個服務提供者,消費者不需遠端呼叫,本機,本地或本機房優先。

路由規則

除了上面提供的各種路由負載均衡,還容許自定義路由規則:

- 條件路由:主要是通過條件表示式來實現;

- 指令碼路由:通過指令碼解析實現。

其實應該還有一種客戶端通過程式碼自定義路由選擇。這些主要是為了擴充套件性。

路由策略定製

自定義路由場景:

1. 灰度;

2. 引流;

路由策略:

1. 框架提供介面擴充套件;

2. 配置平臺提供路由指令碼配置;

配置化路由

  1. 本地配置:包括服務提供者和消費者,全域性配置3種;
  2. 註冊中心:路由策略統一註冊到服務註冊中心,集中化管理;
  3. 動態下發:配置後動態下發各服務消費端。

叢集容錯

指的是服務呼叫失敗後,根據容錯策略進行自動容錯處理。

叢集容錯場景

  • 通訊鏈路故障:
  1. 通訊過程中,對方當機導致鏈路中斷;
  2. 解碼失敗等原因Rest掉連結;
  3. 消費者read-write socketchannel發生IOException導致鏈路中斷;
  4. 網路閃斷故障;
  5. 交換機異常導致鏈路中斷;
  6. 長時間Full GC導致;
  • 服務端超時:
  1. 服務端沒有及時從網路讀取客戶端請求訊息,導致訊息阻塞;
  2. 服務端業務處理超時;
  3. 服務端長時間Full GC;
  • 服務端呼叫失敗:
  1. 服務端解碼失敗;
  2. 服務端流控;
  3. 服務端佇列積壓;
  4. 訪問許可權校驗失敗;
  5. 違反SLA策略;
  6. 其他系統異常;

業務執行異常不屬於服務端異常。

容錯策略

Java程式設計良心推薦——分散式架構原理解析

這圖不錯,關係很清晰。

  • 失敗自動切換(Failover):
  1. 呼叫失敗後切換鏈路呼叫;
  2. 服務提供者的防重;
  3. 重試次數和超時時間的設定。
  • 失敗通知(FailBack):失敗後直接返回,由消費端自行處理;
  • 失敗快取(Failcache):主要是失敗後,快取重試重發,注意:
  1. 快取時間、快取數量;
  2. 快取淘汰演算法;
  3. 定時重試的週期T、重試次數;
  • 快速失敗(Failfast):失敗不處理,記錄日誌分析,可用於大促期間,對非核心業務的容錯。

容錯策略擴充套件

  1. 容錯介面的開放;
  2. 遮蔽底層細節,使用者自定義;
  3. 支援擴充套件。

其實還有一點,感覺也挺重要,就是支援容錯後本地mcok。呼叫失敗後的鏈路切換和快速失敗肯定要支援,快取重發可以不用。

本篇篇幅過長,相信能堅持看到最後的都是對知識求知如渴的人,將來必定不凡。順便點點關注點點讚唄。

歡迎工作一到五年的Java工程師朋友們加入Java架構開發:878249276

群內提供免費的Java架構學習資料(裡面有高可用、高併發、高效能及分散式、Jvm效能調優、Spring原始碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!


相關文章