您现在的位置是:Instagram刷粉絲, Ins買粉絲自助下單平台, Ins買贊網站可微信支付寶付款 > 

04 消息訂閱發布模式多線程(網絡請求不做異步處理放在什么位置)

Instagram刷粉絲, Ins買粉絲自助下單平台, Ins買贊網站可微信支付寶付款2024-05-19 15:51:08【】5人已围观

简介省了系統資源JDK15_update10版本使用epoll替代了傳統的select/poll,極大地提升了NIO通信的性能,它的工作原理如圖1-1所示圖1-1非阻塞I/O工作原理Netty是一個開源的

省了系統資源

JDK1

5_update10版本使用epoll替代了傳統的select/poll,極大地提升了NIO通信的性能,它的工作原理如圖1-1所示

圖1-1非阻塞I/O工作原理Netty是一個開源的高性能NIO通信框架:它的I/O線程NioEventLoop由于聚合了多路復用器Selector,可以同時并發處理成百上千個客戶端Channel

由于讀寫操作都是非阻塞的,這就可以充分提升I/O線程的運行效率,避免由于頻繁I/O阻塞導致的線程掛起

另外,由于Netty采用了異步通信模式,一個I/O線程可以并發處理N個客戶端連接和讀寫操作,這從根本上解決了傳統同步阻塞I/O一連接一線程模型,架構的性能、彈性伸縮能力和可靠性都得到了極大的提升

Netty被精心設計,提供了很多獨特的性能提升特性,使它做到了在各種NIO框架中性能排名第一,它的性能優化措施總結如下

1)零拷貝:(1)Netty的接收和發送ByteBuffer采用DIRECTBUFFERS,使用堆外直接內存進行Socket讀寫,不需要進行字節緩沖區的二次拷貝

如果使用傳統的堆內存(HEAPBUFFERS)進行Socket讀寫,JVM會將堆內存Buffer拷貝一份到直接內存中,然后才寫入Socket中

相比于堆外直接內存,消息在發送過程中多了一次緩沖區的內存拷貝

(2)Netty提供了組合Buffer對象,可以聚合多個ByteBuffer對象,用戶可以像操作一個Buffer那樣方便地對組合Buffer進行操作,避免了傳統通過內存拷貝的方式將幾個小Buffer合并成一個大的Buffer

(3)Netty的文件傳輸采用了transferTo方法,它可以直接將文件緩沖區的數據發送到目標Channel,避免了傳統通過循環write方式導致的內存拷貝問題

2)內存池:隨著JVM虛擬機和JIT即時編譯技術的發展,對象的分配和回收是個非常輕量級的工作

但是對于緩沖區Buffer,情況卻稍有不同,特別是對于堆外直接內存的分配和回收,是一件耗時的操作

為了盡量重用緩沖區,Netty提供了基于內存池的緩沖區重用機制

性能測試表明,采用內存池的ByteBuf相比于朝生夕滅的ByteBuf,性能高23倍左右(性能數據與使用場景強相關)

3)無鎖化的串行設計:在大多數場景下,并行多線程處理可以提升系統的并發性能

但是,如果對于共享資源的并發訪問處理不當,會帶來嚴重的鎖競爭,這最終會導致性能的下降

為了盡可能地避免鎖競爭帶來的性能損耗,可以通過串行化設計,即消息的處理盡可能在同一個線程內完成,期間不進行線程切換,這樣就避免了多線程競爭和同步鎖

為了盡可能提升性能,Netty采用了串行無鎖化設計,在I/O線程內部進行串行操作,避免多線程競爭導致的性能下降

表面上看,串行化設計似乎CPU利用率不高,并發程度不夠

但是,通過調整NIO線程池的線程參數,可以同時啟動多個串行化的線程并行運行,這種局部無鎖化的串行線程設計相比一個隊列-多個工作線程模型性能更優

4)高效的并發編程:volatile的大量、正確使用;CAS和原子類的廣泛使用;線程安全容器的使用;通過讀寫鎖提升并發性能

2

高性能序列化框架影響序列化性能的關鍵因素總結如下

1)序列化后的碼流大小(網絡帶寬的占用)

2)序列化&反序列化的性能(CPU資源占用)

3)是否支持跨語言(異構系統的對接和開發語言切換)

4)并發調用的性能表現:穩定性、線性增長、偶現的時延毛刺等

相比于JSON等文本協議,二進制序列化框架性能更優異,以Java原生序列化和Protobuf二進制序列化為例進行性能測試對比,結果如圖1-2所示

圖1-2序列化性能測試對比數據在序列化框架的技術選型中,如無特殊要求,盡量選擇性能更優的二進制序列化框架,碼流是否壓縮,則需要根據通信內容做靈活選擇,對于圖片、音頻、有大量重復內容的文本文件(例如小說)可以采用碼流壓縮,常用的壓縮算法包括GZip、Zig-Zag等

3

高性能的Reactor線程模型該模型的特點總結如下

1)有專門一個NIO線程:Acceptor線程用于監聽服務端,接收客戶端的TCP連接請求

2)網絡I/O操作:讀、寫等由一個NIO線程池負責,線程池可以采用標準的JDK線程池實現,它包含一個任務隊列和N個可用的線程,由這些NIO線程負責消息的讀取、解碼、編碼和發送

3)1個NIO線程可以同時處理N條鏈路,但是1個鏈路只對應1個NIO線程,防止產生并發操作

由于Reactor模式使用的是異步非阻塞I/O,所有的I/O操作都不會導致阻塞,理論上一個線程可以獨立處理所有I/O相關的操作,因此在絕大多數場景下,Reactor多線程模型都可以完全滿足業務性能需求

Reactor線程調度模型的工作原理示意如圖1-3所示

圖1-3高性能的Reactor線程調度模型1

2業務最佳實踐要保證高性能,單依靠分布式服務框架是不夠的,還需要應用的配合,應用服務化高性能實踐總結如下:1)能異步的盡可能使用異步或者并行服務調用,提升服務的吞吐量,有效降低服務調用時延

2)無論是NIO通信框架的線程池還是后端業務線程池,線程參數的配置必須合理

如果采用JDK默認的線程池,最大線程數建議不超過20個

因為JDK的線程池默認采用N個線程爭用1個同步阻塞隊列方式,當線程數過大時,會導致激烈的鎖競爭,此時性能不僅不會提升,反而會下降

3)盡量減小要傳輸的碼流大小,提升性能

本地調用時,由于在同一塊堆內存中訪問,參數大小對性能沒有任何影響

跨進程通信時,往往傳遞的是個復雜對象,如果明確對方只使用其中的某幾個字段或者某個對象引用,則不要把整個復雜對象都傳遞過去

舉例,對象A持有8個基本類型的字段,2個復雜對象B和C

如果明確服務提供者只需要用到A聚合的C對象,則請求參數應該是C,而不是整個對象A

4)設置合適的客戶端超時時間,防止業務高峰期因為服務端響應慢導致業務線程等應答時被阻塞,進而引起后續其他服務的消息在隊列中排隊,造成故障擴散

5)對于重要的服務,可以單獨部署到獨立的服務線程池中,與其他非核心服務做隔離,保障核心服務的高效運行

6)利用Docker等輕量級OS容器部署服務,對服務做物理資源層隔離,避免虛擬化之后導致的超過20%的性能損耗

7)設置合理的服務調度優先級,并根據線上性能監控數據做實時調整

2

事務一致性問題服務化之前,業務采用本地事務,多個本地SQL調用可以用一個大的事務塊封裝起來,如果某一個數據庫操作發生異常,就可以將之前的SQL操作進行回滾,只有所有SQL操作全部成功,才最終提交,這就保證了事務強一致性,如圖2-1所示

服務化之后,三個數據庫操作可能被拆分到獨立的三個數據庫訪問服務中,此時原來的本地SQL調用演變成了遠程服務調用,事務一致性無法得到保證,如圖2-2所示

圖2-2服務化之后引入分布式事務問題假如服務A和服務B調用成功,則A和B的SQL將會被提交,最后執行服務C,它的SQL操作失敗,對于應用1消費者而言,服務A和服務B的相關SQL操作已經提交,服務C發生了回滾,這就導致事務不一致

從圖2-2可以得知,服務化之后事務不一致主要是由服務分布式部署導致的,因此也被稱為分布式事務問題

2

1分布式事務設計方案通常,分布式事務基于兩階段提交實現,它的工作原理示意圖如圖2-3所示

圖2-3兩階段提交原理圖階段1:全局事務管理器向所有事務參與者發送準備請求;事務參與者向全局事務管理器回復自己是否準備就緒

階段2:全局事務管理器接收到所有事務參與者的回復之后做判斷,如果所有事務參與者都可以提交,則向所有事務提交者發送提交申請,否則進行回滾

事務參與者根據全局事務管理器的指令進行提交或者回滾操作

分布式事務回滾原理圖如圖2-4所示

圖2-4分布式事務回滾原理圖兩階段提交采用的是悲觀鎖策略,由于各個事務參與者需要等待響應最慢的參與者,因此性能比較差

第一個問題是協議本身的成本:整個協議過程是需要加鎖的,比如鎖住數據庫的某條記錄,且需要持久化大量事務狀態相關的操作日志

更為麻煩的是,兩階段鎖在出現故障時表現出來的脆弱性,比如兩階段鎖的致命缺陷:當協調者出現故障,整個事務需要等到協調者恢復后才能繼續執行,如果協調者出現類似磁盤故障等錯誤,該事務將被永久遺棄

對于分布式服務框架而言,從功能特性上需要支持分布式事務

在實際業務使用過程中,如果能夠通過最終一致性解決問題,則不需要做強一致性;如果能夠避免分布式事務,則盡量在業務層避免使用分布式事務

2

2分布式事務優化既然分布式事務有諸多缺點,那么為什么我們還在使用呢?有沒有更好的解決方案來改進或者替換呢?如果我們只是針對分布式事務去優化的話,發現其實能改進的空間很小,畢竟瓶頸在分布式事務模型本身

那我們回到問題的根源:為什么我們需要分布式事務?因為我們需要各個資源數據保持一致性,但是對于分布式事務提供的強一致性,所有業務場景真的都需要嗎?大多數業務場景都能容忍短暫的不一致,不同的業務對不一致的容忍時間不同

像銀行轉賬業務,中間有幾分鐘的不一致時間,用戶通常都是可以理解和容忍的

在大多數的業務場景中,我們可以使用最終一致性替代傳統的強一致性,盡量避免使用分布式事務

在實踐中常用的最終一致性方案就是使用帶有事務功能的MQ做中間人角色,它的工作原理如下:在做本地事務之前,先向MQ發送一個prepare消息,然后執行本地事務,本地事務提交成功的話,向MQ發送一個買粉絲mit消息,否則發送一個rollback消息,取消之前的消息

MQ只會在收到買粉絲mit確認才會將消息投遞出去,所以這樣的形式可以保證在一切正常的情況下,本地事務和MQ可以達到一致性

但是分布式調用存在很多異常場景,諸如網絡超時、VM宕機等

假如系統執行了local_tx()成功之后,還沒來得及將買粉絲mit消息發送給MQ,或者說發送出去由于網絡超時等原因,MQ沒有收到買粉絲mit,發生了買粉絲mit消息丟失,那么MQ就不會把prepare消息投遞出去

MQ會根據策略去嘗試詢問(回調)發消息的系統(checkCommit)進行檢查該消息是否應該投遞出去或者丟棄,得到系統的確認之后,MQ會做投遞還是丟棄,這樣就完全保證了MQ和發消息的系統的一致性,從而保證了接收消息系統的一致性

3

研發團隊協作問題服務化之后,特別是采用微服務架構以后

研發團隊會被拆分成多個服務化小組,例如AWS的TwoPizzaTeam,每個團隊由2~3名研發負責服務的開發、測試、部署上線、運維和運營等

隨著服務數的膨脹,研發團隊的增多,跨團隊的協同配合將會成為一個制約研發效率提升的因素

3

1

很赞哦!(42538)

Instagram刷粉絲, Ins買粉絲自助下單平台, Ins買贊網站可微信支付寶付款的名片

职业:程序员,设计师

现居:江苏淮安楚州区

工作室:小组

Email:[email protected]