1、前言
前面第一篇闡述了采用基於.NET CORE微服務架構,應用surging服務端與客戶端之間進行通信的簡單示例以及對於surging服務化框架簡單介紹。在這篇文章中,我們將剝析surging的架構思想。
2、通信機制
2.1 簡介
在單體應用中,模塊之間的調用通信通過引用加載方法或者函數來實現,但是單體應用最終都會因為團隊壯大,項目模塊的擴展和部署等出現難以維護的問題。隨着業務需求的快速發展變化,敏捷性、靈活性和可擴展性需求不斷增長,迫切需要一種更加快速高效的軟件交付方式。微服務可以彌補單體應用不足,是一種更加快速高效軟件架構風格。單體應用被分解成多個更小的服務,每個服務有自己的獨立模塊,單獨部署,然后共同組成一個應用程序。把范圍限定到單個獨立業務模塊功能。分布式部署在各台服務器上。一般來說,每個微服務都是一個進程。而各服務之間的交互必須通過進程間通信(IPC)來實現
2.2 交互模式
交互模式有以下幾種方式:
• 請求/響應:客戶端向服務器端發起請求,同步等待響應,等待過程可能造成線程阻塞。
• 通知(也就是常說的單向請求):客戶端請求發送到服務端,服務端不返回請求響應。
• 請求/異步響應:客戶端發送請求到服務端,服務端異步響應請求。客戶端不會阻塞,而且被設計成默認響應不會立刻到達。
• 發布/ 訂閱模式:客戶端發布通知消息,被零個或者多個訂閱者服務消費。
• 發布/異步響應模式:客戶端發布請求消息,然后異步或者回調服務發回響應。
服務之間的通信可以使用同步的請求/響應和請求/異步響應模式,在surging框架采用的基於RPC的netty 請求/異步響應和基於rabbitmq 的消息通信模式。首先來看異步消息通信模式
2.1.1 異步消息通信模式
Surging采用基於Rabbitmq發布訂閱的異步交換消息的IPC進程通信,客戶端通過pub發布請求,然后服務端進行Consume,之間的通信是異步,客戶端不會因為等待而阻塞。
消息由頭部(元數據)和消息體構成,生產者發送消息到channel,消費者則通過channel接受數據,channel 則分為點對點和發布訂閱,點對點Channel 會把消息准確發送到消費者,之間采用的是一對一的交互模式。而發布/訂閱則把消息PUB到所有從channel 訂閱消息的消費者中,之間采用的一對多的交互模式
2.1.2 基於請求/異步響應通信模式
Surging采用基於netty的 (IPC)進程通信,是基於請求/異步響應的IPC機制,客戶端向服務端發送請求,服務端處理請求,異步響應,客戶端不會因為等待服務返回而阻塞其它請求。
在請求/異步響應模式中,服務器端異步響應是在多處理器系統上可以並行處理或者單處理上交錯執行,這使得當某個線程阻塞請求的同時其它線程得以繼續執行。但訪問共享資源時,需要保證其線程安全,可以通過鎖,先進先出集合或者其它機制來處理線程安全的問題。
3、部署和調用
1.單體應用架構
當網站流量很小時,只需要將所有功能部署在一起,以減少部署節點和成本
單體架構業務流程往往在同一個進程內部完成處理,不需要進行分布式協作,它的工作原理如下:
圖 1-1 單體架構本地方法調用
2.垂直應用架構
當訪問量逐漸增大,單體架構壓力越來越大,將架構拆成互不相干的若干應用以提升效率,此時采用MVC、webAPI進行調用
3.分布式微服務架構
當垂直應用越來越多,應用之間交互不可避免,可以將各個獨立的業務模塊,部署成獨立的微服務,逐漸形成穩定的服務中心。
而Surging 微服務采用分布式集群部署方式,服務的消費者和提供者通常運行在不同的進程中,進程之間通信采用RPC方式調用,它的工作原理如下:
圖1-2 Surging分布式RPC調用
Surging微服務采用基於netty進行通信,數據之間的傳遞通過序列化和反序列JSON,相比於本地方法調用,會產生如下問題:
1.數據序列化問題:微服務進程的通信都需要經過序列化和反序列化,因數據結構不一致、數據類型的不支持、編碼錯誤都會造成數據轉化的失敗,從而導致調用失敗
2.網絡問題:常見的包括網絡超時、網絡閃斷、網絡阻塞等, 都會導致微服務遠程調用失敗。
每個微服務都獨立打包部署,讓服務之間進行進程隔離,對於大型的互聯網項目,會有成百上千的微服務,通常不會百分百獨立部署,對於同一業務的微服務會打包部署在一起,對於時延非常敏感,會合設在同一進程之內,采用本地方法調用。
不同的微服務合設在同一進程中,會產生以下問題:
- 處理較慢的微服務會阻塞其它微服務
- 某個微服務故障,可能導致整個進程不可用
3、總體架構
Surging框架代碼邏輯一共划分了8層,各個層的設計要點:
- 業務模塊服務接口層(IModuleServices):該層是與實際業務邏輯相關的,根據服務提供方和服務消費方,設計業務模塊接口。
- 業務模塊服務層(ModuleServices):該層是通過Domain和Repository實現實際業務邏輯
- 基礎通信平台(CPlatform):提供基礎數據通信對應的接口和基礎實現,如:基礎日志,遠程調用服務,Event bus,負載均衡算法,數據序列化等
- DotNetty服務層(DotNetty):實現基於DotNetty服務的信息的發送和接收
- RabbitMQ服務層(EventBusRabbitMQ):封裝基於Rabbitmq的發布訂閱的事件總線
- 代理服務層(ProxyGenerator):封裝代理服務的生成及創建調用。
- 服務注冊層(Zookeeper):封裝服務地址的注冊與發現,以Zookeeper為服務注冊中心,實現ServiceRouteManagerBase抽象,通過心跳檢測的方式更新路由
- 系統服務層(system):對於系統底層接口的封裝
4、分布式的可靠性
Surging 微服務的運行質量,除了自身的可靠性因素之外,還受到其它因素的影響,包括網絡,數據庫訪問,其它關聯的微服務的運行質量,可靠性設計,需要考慮上述綜合因素,總結如下:
4.1 異步I/O 操作
4.1.1 網絡I/O
1.同步阻塞I/o 通信:
即典型的請求/響應模式。 該模型最大的問題就是缺乏彈性伸縮能力,當客戶端並發訪問量增加后,服務端的線程個數和客戶端並發訪問數呈1:1的正比關系,線程數量快速膨脹后,系統的性能將急劇下降,隨着訪問量的繼續增大,系統最終崩潰。
- 異步非阻塞I/O 通信:
Surging 是基於Netty進行異步非阻塞I/O 通信,即典型的請求/異步響應模式。此模式的優點如下:
- 更好的吞吐量,低延遲,更省資源
- 不再因過快、過慢或超負載訪問導致系統崩潰
4.1.2 磁盤I/O
微服務對磁盤I/O的操作主要分為同步文件操作和異步文件操作,
在Surging項目中,需要從注冊中心獲取路由信息緩存到本地,通過創建代理,負載均衡算法選擇Router,路由信息的緩存到采用的是心跳檢測的方式進行更新。
4.1.3 數據庫操作
一般來說文件 I/O、網絡訪問乃至於進程間同步通信,以及本節所討論的 數據庫訪問等都較為耗時,ado.net,Entity Framework以及其它ORM框架都提供了異步執行方法。
4.2 故障隔離
由於大部分微服務采用同步接口調用,而且多個領域相關的微服務會部署在同一個進程中,很容易發生“雪崩效應”,即某個微服務提供者故障,導致調用該微服務的消費者、或者與故障微服務合設在同一個進程中的其它微服務發生級聯故障,最終導致系統崩潰。為了避免“雪崩效應”的發生,需要支持多種維度的依賴和故障隔離,
4.1.1 通信鏈路隔離
由於網絡通信本身通常不是系統的瓶頸,因此大部分服務框架會采用多線程+單個通信鏈路的方式進行通信,原理如下所示:
4.1.2 調度資源隔離
4.1.2.1微服務之間隔離
當多個微服務合設運行在同一個進程內部時,可以利用線程實現不同微服務之間的隔離。
4.3 進程級隔離
對於核心的微服務,例如商品用戶注冊、計費、訂單等,可以采用獨立部署的方式,實現高可用性。
4.3.1 容器隔離
微服務將整個項目解耦成各個獨立的業務模塊,部署成獨立的微服務,利用Docker 容器部署微服務可以升級和擴容,並且有以下優點:
高效:使用Docker部署微服務,微服務的啟動 和銷毀速度非常快,在高壓力時,可以實現秒級彈性伸縮。
高性能:Docker 容器的性能接近邏輯,比VM高20%
隔離性:可以實現高密度的部署微服務,而且是基於細粒度的資源隔離機制,實現微服務隔離,保證微服務的可靠性
可移植性:通過將運行環境和應用程序打包到一起,來解決部署的環境依賴問題,真正做到跨平台的分發和使用。可謂是一次編寫,到處運行。
4.3.2 VM隔離
除了Docker容器隔離,也可以使用VM對微服務進行故障隔離,相比於Docker容器,使用VM進行微服務隔離存在如下優勢:
1.微服務的資源隔離性更好,CPU、內存、網絡等可以實現完全的資源隔離。
2.對於已經完成硬件虛擬化的遺留系統,可以直接使用已有的VM,而不需要在VM中重新部署Docker容器。
4.4 集群容錯
略
5、Cache和EventBus中間件
5.1 Cache 中間件設計
設計目標:
- 將緩存服務器的部署配置與應用隔離,
- 實現分布式,提高數據的均勻分布,並且能實現故障隔離
- 根據KEY前綴的不同分配到MemoryCache 或者redis 上
- 統計緩存的使用情況,便於分析和提高緩存合理資源的分配。
設計如下:
緩存中間件內部使用一致性哈希算法實現分布式。設置的虛擬節點能均勻分布。
緩存中間件暫時只實現Redis,MemoryCache做為緩存服務。后期應該會實現CacheBase
緩存中間件后期會提供配置服務,方便管理緩存服務配置,以及顯示一些狀態信息
5.2 EventBus中間件設計
設計目標:
- 基於發布/訂閱的模式異步傳遞消息。
- 集成第三方消息中間件,如:MSMQ,Rabbitmq
- 實現基於發布/訂閱的異步通知
設計如下:
1.publisher: 是發布者把消息事件Event通過Event Bus 發布到Topic
2.Event bus::是事件總線,對於publisher 和 Subscriber 之間進行解耦,找到已經注冊的事件訂閱者,消息事件Event發送到topic
3.Topic: 是消息路由,對於訂閱者以廣播的形式,讓在線的Subscriber接收消息事件。
4.Subscriber:是訂閱者, 收到事件總線發下來的消息。即Handle方法被執行。注意參數類型必須和發布者發布的參數一致。
5、總結
surging 0.0.0.1版本還有很多需要完善的地方,比如路由容錯,服務降級、熔斷,監控平台和配置服務平台,以及后續的第三方中間件的集成,這些任務都已經規划到日程,再不久的將來會看到1.0穩定版本的發布 ,如有興趣可以加入QQ群:615562965