Java開源:traffic-shm-異步無鎖 IPC 類庫
traffic-shmanna是Java版的異步無鎖IPC類庫,支持多生產者-單消費者模式,可配合Bson等序列化協議,作為同一服務器中Java進程間的輕量級通訊組件使用,吞吐量可達到百萬級TPS。 traffic-shm anna具有良好的跨平臺移植性,支持在主流的操作系統如:Linux、macOS、Windows、AIX和HP-UX中運行。本文主要介紹 traffic-shm anna的實現細節。
1. 內存映射文件
操作系統使用虛擬內存來進行內存管理。虛擬內存是一個抽象的概念,它為每個為應用進程提供了使用虛擬地址取代物理內存地址進行內存訪問的功能。
操作系統通過將一個虛擬內存區域與一個磁盤上的普通文件關聯起來,以初始化這個虛擬內存區域的內容,這個過程稱為內存映射。Java語言中,可通過FileChannel類的map()方法進行操作,實現過程由操作系統的mmap()實現。
內存映射使用文件系統建立從用戶空間直到可用文件系統頁的虛擬內存映射。這樣做有幾個好處:
- 用戶進程把文件數據當作內存,所以無需發布read()或write()系統調用。
- 當用戶進程碰觸到映射內存空間,缺頁錯誤會自動產生,從而將文件數據從磁盤讀進內存。如果用戶修改了映射內存空間,相關頁會自動標記為臟,隨后刷新到磁盤,文件得到更新。
- 操作系統的虛擬內存子系統會對頁進行智能高速緩存,自動根據系統負載進行內存管理。
- 數據總是按頁對齊的,無需執行緩沖區拷貝。
- 大型文件使用映射,無需耗費大量內存,即可進行數據拷貝。
2. 內存對齊
- 頁對齊 操作系統對內存采用頁式管理機制,對于用mmap()映射的普通文件來,進程會在自己的地址空間新增一塊空間,空間大小由mmap()的len參數指定。進程能夠訪問的有效地址大小取決于文件被映射部分的大小。超過這個空間大小,內核會根據超過的嚴重程度返回發送不同的信號給進程。示例如下:
因此,考慮到不同操作系統及處理器架構,內存映射文件的大小及mmap()映射的內存空間 大小均需要按頁大小進行對齊。
- 數據類型對齊 簡單來講,數據類型對齊需要滿足以下條件:數據所在的內存虛擬地址要能被這個數據的長度所整除。數據域單個數據塊以4字節進行對齊。
3. 字節順序
不同的處理器架構使用不同的字節順序存儲數據,目前常見有大端小端兩種存儲方式。一個多位的整數將按照其存儲地址的最低或最高字節排列,如果低位字節存放在內存的低地址端,高位字節存放在內存的高地址端,稱為小端模式,反之為大端模式。以下以0x0A0B0C0D為例,分別解釋小端模式及大端模式。
-
小端模式
1 2 3 4 0x0D 0x0C 0x0B 0x0A -
大端模式
1 2 3 4 0x0A 0x0B 0x0C 0x0D
為了保證在不同操作系統及處理器架構下的可移植性, traffic-shm anna約定按照大端模式存儲數據。
4. 數據結構
如下圖所示,隊列由元數據域及數據域兩部分組成,公共信息及讀寫位置指針在元數據域維護,數據塊為數據域的最小單位。
同時為了節約內存空間,避免頻繁映射造成的內存浪費,針對數據域采用了RingBuffer數據結構。
5. 并發控制
- 可見性 為保證可見性,使用Unsafe的volatile方法對讀寫位置指針及ACK域進行操作。
- 原子性 為了保證在多生產者模式下的原子性,對ACK域的一個int類型先后進行了兩次無符號short型填充。
參考:
- 《深入理解計算機系統》
- 《Java NIO》
項目主頁:http://www.baiduhome.net/lib/view/home/1495805565723