服務框架的核心
- 大型服務框架的核心:RPC通訊
- 微服務的核心是遠程通訊和服務治理
- 遠程通訊提供了服務之間通訊的橋樑,服務治理提供了服務的後勤保障
- 服務的拆分增長了通訊的成本,所以遠程通訊很容易成爲系統瓶頸
- 在知足必定的服務治理需求的前提下,對遠程通訊的性能需求是技術選型的主要影響因素
- 不少微服務框架中的服務通訊是基於RPC通訊實現的
- 在沒有進行組件擴展的前提下,Spring Cloud是基於Feign組件實現RPC通訊(基於HTTP+JSON序列化)
- Dubbo是基於SPI擴展了不少RPC通訊框架,包括RMI、Dubbo、Hessian等(默認爲Dubbo+Hessian序列化)
性能測試
基於Dubbo:2.6.4,單一TCP長鏈接+Protobuf(響應時間和吞吐量更優),短鏈接的HTTP+JSON序列化算法
RPC通訊
架構演化編程
不管是微服務、SOA、仍是RPC架構,都是分佈式服務架構,都須要實現服務之間的互相通訊,一般把這種通訊統稱爲RPC通訊緩存
概念
- RPC:Remote Process Call,遠程服務調用,經過網絡請求遠程計算機程序服務的通訊技術
- RPC框架封裝了底層網絡通訊和序列化等技術
- 只須要在項目中引入各個服務的接口包,就能夠在代碼中調用RPC服務(如同調用本地方法同樣)
RMI服務器
- RMI:Remote Method Invocation
- RMI是JDK自帶的RPC通訊框架,已經成熟地應用於EJB和Spring,是純Java網絡分佈式應用系統的核心解決方案
- RMI實現了一臺虛擬機應用對遠程方法的調用能夠同對本地方法調用同樣,RMI封裝好了遠程通訊的具體細節
實現原理
- RMI遠程代理對象是RMI中最核心的組件,除了對象自己所在的虛擬機,其餘虛擬機也能夠調用此對象的方法
- 這些虛擬機能夠分佈在不一樣的主機上,經過遠程代理對象,遠程應用能夠用網絡協議和服務進行通訊
高併發下的性能瓶頸
- Java默認序列化
- RMI的序列化方式採用的是Java默認序列化,性能很差,並且不支持跨語言
- TCP短鏈接
- RMI是基於TCP短鏈接實現的,在高併發狀況下,大量請求會帶來大量TCP鏈接的建立和銷燬,很是消耗性能
- 阻塞式網絡IO
- Socket編程中使用傳統的IO模型,在高併發場景下基於短鏈接實現的網絡通訊就很容易產生IO阻塞,性能將大打折扣
優化路徑
TCP / UDP網絡
- 網絡傳輸協議有TCP和UDP,兩個協議都是基於Socket編程
- 基於TCP協議實現的Socket通訊是有鏈接的
- 傳輸數據要經過三次握手來實現數據傳輸的可靠性,而傳輸數據是沒有邊界的,採用的是字節流模式
- 基於UDP協議實現的Socket通訊,客戶端不須要創建鏈接,只須要建立一個套接字發送數據給服務端
- 基於UDP協議實現的Socket通訊具備不可靠性
- UDP發送的數據採用的是數據報模式,每一個UDP的數據報都有一個長度,該長度與數據一塊兒發送到服務端
- 爲了保證數據傳輸的可靠性,一般狀況下會採用TCP協議
- 在局域網且對數據傳輸的可靠性沒有要求的狀況下,能夠考慮使用UDP協議,UDP協議的效率比TCP協議高
長鏈接
- 服務之間的通訊不一樣於客戶端與服務端之間的通訊
- 因爲客戶端數量衆多,基於短鏈接實現請求,能夠避免長時間地佔用鏈接,致使系統資源浪費
- 服務之間的通訊,鏈接的消費端不會像客戶端那麼多,但消費端向服務端請求的數量卻同樣多
- 基於長鏈接實現,能夠省去大量創建TCP鏈接和關閉TCP鏈接的操做,從而減小系統的性能消耗,節省時間
優化Socket通訊
- 傳統的Socket通訊主要存在IO阻塞,線程模型缺陷以及內存拷貝等問題,Netty4對Socket通訊編程作了不少方面的優化
- 實現非阻塞IO:多路複用器Selector實現了非阻塞IO通訊
- 高效的Reactor線程模型
- Netty使用了主從Reactor多線程模型
- 主線程:用於客戶端的鏈接請求操做,一旦鏈接創建成功,將會監聽IO事件,監聽到事件後會建立一個鏈路請求
- 鏈路請求將會註冊到負責IO操做的IO工做線程上,由IO工做線程負責後續的IO操做
- Reactor線程模型解決了在高併發的狀況下,因爲單個NIO線程沒法監聽海量客戶端和知足大量IO操做形成的問題
4.串行設計多線程
- 服務端在接收消息以後,存在着編碼、解碼、讀取和發送等鏈路操做
- 若是這些操做基於並行實現,無疑會致使嚴重的鎖競爭,進而致使系統的性能降低
- 爲了提高性能,Netty採用串行無鎖化完成鏈路操做,提供了Pipeline,實現鏈路的各個操做在運行期間不會切換線程
5.零拷貝架構
- 數據從內存發到網絡中,存在兩次拷貝,先是從用戶空間拷貝到內核空間,再從內核空間拷貝到網絡IO
- NIO提供的ByteBuffer可使用Direct Buffer模式
- 直接開闢一個非堆物理內存,不須要進行字節緩衝區的二次拷貝,能夠直接將數據寫入到內核空間
6.優化TCP參數配置,提升網絡吞吐量,Netty能夠基於ChannelOption來設置併發
- TCP_NODELAY:用於控制是否開啓Nagle算法
- Nagle算法經過緩存的方式將小的數據包組成一個大的數據包,從而避免大量發送小的數據包,致使網絡阻塞
- 在對時延敏感的應用場景,能夠選擇關閉該算法
- SO_RCVBUF / SO_SNDBUF:Socket接收緩衝區和發送緩衝區的大小
- SO_BACKLOG:指定客戶端鏈接請求緩衝隊列的大小
- 服務端處理客戶端鏈接請求是按順序處理的,同一時間只能處理一個客戶端鏈接
- 當有多個客戶端進來的時候,服務端將不能處理的客戶端鏈接請求放在隊列中等待處理
- SO_KEEPALIVE
- 鏈接會檢查長時間沒有發送數據的客戶端的鏈接狀態,檢測到客戶端斷開鏈接後,服務端將回收該鏈接
- 將該值設置得小一些,能夠提升回收鏈接的效率
定製報文格式
- 設計一套報文,用於描述具體的校驗、操做、傳輸數據等內容
- 爲了提升傳輸效率,能夠根據實際狀況來設計,儘可能實現報體小,知足功能,易解析等特性
字段長度(字節)備註魔數4協議的標識,相似於字節碼的魔數,一般爲固定數字版本號1序列化算法1Protobuf / Thrift指令1相似於HTTP中的增刪改查數據長度4數據N框架
編解碼tcp
- 實現一個通訊協議,須要兼容優秀的序列化框架
- 若是隻是單純的數據對象傳輸,能夠選擇性能相對較好的Protobuf序列化,有利於提升網絡通訊的性能
Linux的TCP參數設置
三次握手
四次揮手
配置項
1.fs.file-max = 194448 / ulimit
2.net.ipv4.tcp_keepalive_time
3.net.ipv4.tcp_max_syn_backlog
4.net.ipv4.ip_local_port_range
5.net.ipv4.tcp_max_tw_buckets
6.net.ipv4.tcp_tw_reuse
備註
1.Linux默認單個進程能夠打開的文件數量上限爲1024,Socket也是文件
2.與Netty的SO_KEEPALIVE配置項的做用一致
3.SYN隊列的長度,加大隊列長度,能夠容納更多等待鏈接的網絡鏈接數
4.客戶端鏈接服務器時,須要動態分配源端口號,該配置項表示向外鏈接的端口範圍
5. 當一個鏈接關閉時,TCP會經過四次揮手來完成一次關閉鏈接操做,在請求量比較大的狀況下,消費端會有大量TIME_WAIT狀態的鏈接,該參數能夠限制TIME_WAIT狀態的鏈接數量,若是TIME_WAIT的鏈接數量超過該值,TIME_WAIT將會當即被清除掉並打印警告信息
6.客戶端每次鏈接服務器時,都會得到一個新的源端口以實現鏈接的惟一性,在TIME_WAIT狀態的鏈接數量過大的狀況下,會增長端口號的佔用時間,因爲處於TIME_WAIT狀態的鏈接屬於關閉鏈接,因此新建立的鏈接能夠複用該端口號
最後
又到了咱們最喜歡的資料分享環節了
快來關注我吧!
關注+轉發,加個人交流羣772300343獲取哦!
我是小架,咱們下篇文章再見!