異構(gòu)計(jì)算關(guān)鍵技術(shù)之mmap
一祸泪、背景
1. 日志存儲(chǔ)系統(tǒng)
case 1:分布式日志存儲(chǔ)系統(tǒng),是一個(gè)基于raft協(xié)議自研分布式日志存儲(chǔ)系統(tǒng),logstore則是底層存儲(chǔ)引擎。
logstore中档悠,使用mmap對(duì)數(shù)據(jù)文件讀寫。
logstore的存儲(chǔ)結(jié)構(gòu)簡(jiǎn)化如下圖:
2. 普通bin文件讀取操作
最近博主需要讀取一個(gè)bin文件然爆,然后實(shí)時(shí)和FPGA接收到的數(shù)據(jù)進(jìn)行比對(duì)站粟,驗(yàn)證邏輯的正確性黍图,采用的mmap技術(shù)曾雕。
...
int id = open(Parameter::xxxbin.c_str(), O_RDONLY);
if (fd < 0) {
std::cout << "cannot open file: " << xxxbin << std::endl;
return -1;
}
m_binbuff = (char *)mmap(NULL, m_fileSize, PROT_READ, MAP_SHARED, fd, 0);
if(nullptr == m_binBuff){
std::cout << "Can't mmap file: " << Parameter::xxxbin << std::endl;
return;
}
close(fd);
3. Ceph分布式文件系統(tǒng)性能關(guān)鍵技術(shù)
分布式文件系統(tǒng)在處理大規(guī)模數(shù)據(jù)時(shí)起著至關(guān)重要的作用。
為了滿足日益增長的數(shù)據(jù)存儲(chǔ)需求助被,Ceph作為一種先進(jìn)的分布式文件系統(tǒng)方案被廣泛使用剖张。
然而,在Ceph的架構(gòu)中揩环,為了實(shí)現(xiàn)高性能和低延遲搔弄,諸如mmap等關(guān)鍵技術(shù)成為了不可或缺的一部分。
二丰滑、什么是mmap
在《深入理解計(jì)算機(jī)系統(tǒng)》書中顾犹,mmap定義為:linux通過將一個(gè)虛擬內(nèi)存區(qū)域與一個(gè)磁盤上的對(duì)象(object)關(guān)聯(lián)起來,以初始化這個(gè)虛擬內(nèi)存的內(nèi)容褒墨,這個(gè)過程稱為內(nèi)存映射(memory mapping)炫刷。
三、mmap的原理
1. mmap在進(jìn)程虛擬內(nèi)存做了什么
我們先來簡(jiǎn)單看一下mapping一個(gè)文件郁妈,mmap做了什么事情浑玛。如下圖所示:
假設(shè)我們mmap的文件是FileA,在調(diào)用mmap之后噩咪,會(huì)在進(jìn)程的虛擬內(nèi)存分配地址空間顾彰,創(chuàng)建映射關(guān)系极阅。
這里值得注意的是,mmap只是在虛擬內(nèi)存分配了地址空間涨享,舉個(gè)例子筋搏,假設(shè)上述的FileA(dd創(chuàng)建)是5M大小:
在mmap之后厕隧,查看mmap所在進(jìn)程的maps描述拆又,可以看到:
由上可以看到,在mmap之后栏账,進(jìn)程的地址空間7f1da0a0f000-7f1da0f0f000被分配帖族,并且map到FileA,7f1da0f0f000減去7f1da0a0f000挡爵,剛好是5242880(ps: 這里是整個(gè)文件做mapping)
2. mmap在物理內(nèi)存做了什么
在Linux中竖般,VM系統(tǒng)通過將虛擬內(nèi)存分割為稱作虛擬頁(Virtual Page,VP)大小固定的塊來處理磁盤(較低層)與上層數(shù)據(jù)的傳輸茶鹃。
一般情況下涣雕,每個(gè)頁的大小默認(rèn)是4096字節(jié)。同樣的闭翩,物理內(nèi)存也被分割為物理頁(Physical Page挣郭,PP),也為4096字節(jié)疗韵。
上述例子兑障,在mmap之后,如下圖:
在mmap之后蕉汪,并沒有在將文件內(nèi)容加載到物理頁上流译,只上在虛擬內(nèi)存中分配了地址空間。當(dāng)進(jìn)程在訪問這段地址時(shí)(通過mmap在寫入或讀取時(shí)FileA)者疤,若虛擬內(nèi)存對(duì)應(yīng)的page沒有在物理內(nèi)存中緩存福澡,則產(chǎn)生"缺頁",由內(nèi)核的缺頁異常處理程序處理驹马,將文件對(duì)應(yīng)內(nèi)容革砸,以頁為單位(4096)加載到物理內(nèi)存,注意是只加載缺頁糯累,但也會(huì)受操作系統(tǒng)一些調(diào)度策略影響算利,加載的比所需的多,這里就不展開了寇蚊。
缺頁處理后笔时,如下圖:
3. mmap的分類
mmap有兩種類型,一種是有backend仗岸,一種是沒有backend允耿。
有backend:
這種模式將普通文件做memory mapping(非MAP_ANONYMOUS)借笙,所以在mmap系統(tǒng)調(diào)用時(shí),需要傳入文件的fd较锡。這種模式常見的有兩個(gè)常用的方式业稼,MAP_SHARED與MAP_PRIVATE,但它們的行為卻不相同蚂蕴。
(1) MAP_SHARED
可以從兩個(gè)角度去看:
1. 進(jìn)程間可見:這個(gè)被提及太多低散,就不展開討論了
2. 寫入/更新數(shù)據(jù)會(huì)回寫backend,也就是回寫文件:這個(gè)是很關(guān)鍵的特性骡楼,是在Logstore設(shè)計(jì)實(shí)現(xiàn)時(shí)熔号,需要考慮的重點(diǎn)。
3. Logstore的一個(gè)基本功能就是不斷地寫入數(shù)據(jù)鸟整,從實(shí)現(xiàn)上看就是不斷地mmap文件引镊,往內(nèi)存寫入/更新數(shù)據(jù)以達(dá)到寫入文件的目的。但物理內(nèi)存是有限的篮条,在寫入數(shù)據(jù)超過物理內(nèi)存時(shí)弟头,操作系統(tǒng)會(huì)進(jìn)行頁置換,根據(jù)淘汰算法涉茧,將需要淘汰的頁置換成所需的新頁赴恨,而恰恰因?yàn)槭怯衎ackend的,所以mmap對(duì)應(yīng)的內(nèi)存是可以被淘汰的(若內(nèi)存頁是"臟"的伴栓,則操作系統(tǒng)會(huì)先將數(shù)據(jù)回寫磁盤再淘汰)伦连。
4. 這樣,就算mmap的數(shù)據(jù)遠(yuǎn)大于物理內(nèi)存挣饥,操作系統(tǒng)也能很好地處理除师,不會(huì)產(chǎn)生功能上的問題。
(2) MAP_PRIVATE
這是一個(gè)copy-on-write的映射方式扔枫。雖然他也是有backend的,但在寫入數(shù)據(jù)時(shí)锹安,他會(huì)在物理內(nèi)存copy一份數(shù)據(jù)出來(以頁為單位)短荐,而且這些數(shù)據(jù)是不會(huì)被回寫到文件的。這里就要注意叹哭,因?yàn)楦碌臄?shù)據(jù)是一個(gè)副本忍宋,而且不會(huì)被回寫,這就意味著如果程序運(yùn)行時(shí)不主動(dòng)釋放风罩,若更新的數(shù)據(jù)超過可用物理內(nèi)存+swap space糠排,就會(huì)遇到OOM Killer。
無backend:
無backend通常是MAP_ANONYMOUS超升,就是將一個(gè)區(qū)域映射到一個(gè)匿名文件入宦,匿名文件是由內(nèi)核創(chuàng)建的哺徊。
因?yàn)闆]有backend,寫入/更新的數(shù)據(jù)之后乾闰,若不主動(dòng)釋放落追,這些占用的物理內(nèi)存是不能被釋放的,同樣會(huì)出現(xiàn)OOM Killer涯肩。
四轿钠、mmap比內(nèi)存+swap空間大情況下,是否有問題
到這里病苗,這個(gè)問題就比較好解析了疗垛。我們可以將此問題分離為:
- 虛擬內(nèi)存是否會(huì)出問題
- 物理內(nèi)存是否會(huì)出問題
虛擬內(nèi)存是否會(huì)出問題:
回到上述的"mmap在進(jìn)程虛擬內(nèi)存做了什么",我們知道m(xù)map會(huì)在進(jìn)程的虛擬內(nèi)存中分配地址空間硫朦,比如1G的文件继谚,則分配1G的連續(xù)地址空間。那究竟可以maping多少呢阵幸?在64位操作系統(tǒng)花履,尋址范圍是2^64 ,除去一些內(nèi)核挚赊、進(jìn)程數(shù)據(jù)等地址段之外诡壁,基本上可以認(rèn)為可以mapping無限大的數(shù)據(jù)(不太嚴(yán)謹(jǐn)?shù)恼f法)。
物理內(nèi)存是否會(huì)出問題:
回到上述"mmap的分類"荠割,對(duì)于有backend的mmap妹卿,而且是能回寫到文件的,映射比內(nèi)存+swap空間大是沒有問題的蔑鹦。但無法回寫到文件的夺克,需要非常注意,主動(dòng)釋放嚎朽。
五铺纽、mmap的性能
mmap的性能經(jīng)常與系統(tǒng)調(diào)用(write/read)做對(duì)比。
我們將讀寫分開看哟忍,先嘗試從原理上分析兩者的差異狡门,然后再通過測(cè)試驗(yàn)證。
1. mmap的寫性能
我們先來簡(jiǎn)單講講write系統(tǒng)調(diào)用寫文件的過程:
Step1:進(jìn)程(用戶態(tài))調(diào)用write系統(tǒng)調(diào)用锅很,并告訴內(nèi)核需要寫入數(shù)據(jù)的開始地址與長度(告訴內(nèi)核寫入的數(shù)據(jù)在哪)其馏。
Step2:內(nèi)核write方法,將校驗(yàn)用戶態(tài)的數(shù)據(jù)爆安,然后復(fù)制到kernel buffer(這里是Page Cache)叛复。
Step3: 由操作系統(tǒng)調(diào)用,將臟頁回寫到磁盤(通常這是異步的)
再來簡(jiǎn)單講講使用mmap時(shí),寫入文件流程:
Step1:進(jìn)程(用戶態(tài))將需要寫入的數(shù)據(jù)直接copy到對(duì)應(yīng)的mmap地址(內(nèi)存copy)
Step2:
(2.1) 若mmap地址未對(duì)應(yīng)物理內(nèi)存褐奥,則產(chǎn)生缺頁異常咖耘,由內(nèi)核處理
(2.2) 若已對(duì)應(yīng),則直接copy到對(duì)應(yīng)的物理內(nèi)存
Step3:由操作系統(tǒng)調(diào)用抖僵,將臟頁回寫到磁盤(通常這是異步的)
系統(tǒng)調(diào)用會(huì)對(duì)性能有影響鲤看,那么從理論上分析:
1. 若每次寫入的數(shù)據(jù)大小接近page size(4096),那么write調(diào)用與mmap的寫性能應(yīng)該比較接近(因?yàn)橄到y(tǒng)調(diào)用次數(shù)相近)
2. 若每次寫入的數(shù)據(jù)非常小耍群,那么write調(diào)用的性能應(yīng)該遠(yuǎn)慢于mmap的性能义桂。
下面我們對(duì)兩者進(jìn)行性能測(cè)試:
每次寫入大小 | mmap 耗時(shí) | write 耗時(shí)
--------------- | ------- | -------- | --------
| 1 byte | 22.14s | >300s
| 100 bytes | 2.84s | 22.86s
| 512 bytes | 2.51s | 5.43s
| 1024 bytes | 2.48s | 3.48s
| 2048 bytes | 2.47s | 2.34s
| 4096 bytes | 2.48s | 1.74s
| 8192 bytes | 2.45s | 1.67s
| 10240 bytes | 2.49s | 1.65s
可以看到mmap在100byte寫入時(shí)已經(jīng)基本達(dá)到最大寫入性能,而write調(diào)用需要在4096(也就是一個(gè)page size)時(shí)蹈垢,才能達(dá)到最大寫入性能慷吊。
從測(cè)試結(jié)果可以看出,在寫小數(shù)據(jù)時(shí)曹抬,mmap會(huì)比write調(diào)用快溉瓶,但在寫大數(shù)據(jù)時(shí),反而沒那么快谤民。
2. mmap的讀性能
我們還是來簡(jiǎn)單分析read調(diào)用與mmap的流程:
從圖中可以看出堰酿,read調(diào)用確實(shí)比mmap多一次copy。因?yàn)閞ead調(diào)用张足,進(jìn)程是無法直接訪問kernel space的触创,所以在read系統(tǒng)調(diào)用返回前,內(nèi)核需要將數(shù)據(jù)從內(nèi)核復(fù)制到進(jìn)程指定的buffer为牍。但mmap之后哼绑,進(jìn)程可以直接訪問mmap的數(shù)據(jù)(page cache)。
從原理上看碉咆,read性能會(huì)比mmap慢抖韩。
每次讀取大小 | mmap 耗時(shí) | write 耗時(shí)
--------------- | ------- | -------- | --------
| 1 byte | 8215.4ms | > 300s
| 100 bytes | 86.4ms | 8100.9ms
| 512 bytes | 16.14ms | 1851.45ms
| 1024 bytes | 8.11ms | 992.71ms
| 2048 bytes | 4.09ms | 636.85ms
| 4096 bytes | 2.07ms | 558.10ms
| 8192 bytes | 1.06ms | 444.83ms
| 10240 bytes | 867.88μs | 475.28ms
由上可以看出,在read上面疫铜,mmap比write的性能差別還是很大的茂浮。測(cè)試結(jié)果與理論推導(dǎo)吻合。
3. 總結(jié)
mmap被廣泛應(yīng)用于提高讀取性能块攒。傳統(tǒng)上励稳,讀取數(shù)據(jù)需要通過復(fù)制數(shù)據(jù)到用戶空間,這一過程涉及系統(tǒng)調(diào)用和數(shù)據(jù)拷貝操作囱井,消耗大量的CPU資源和時(shí)間。而通過使用mmap趣避,用戶可以直接在內(nèi)存中讀取文件庞呕,避免了這些開銷。因此,在Ceph中使用mmap可以提高文件讀取的效率住练。
然而地啰,并不是所有場(chǎng)景下mmap都適用。比如讲逛,對(duì)于大型文件或者需要修改文件內(nèi)容的場(chǎng)景亏吝,mmap可能并不是最佳選擇。因?yàn)橐坏┦褂胢map映射了文件盏混,文件的全部?jī)?nèi)容都會(huì)加載到內(nèi)存中蔚鸥,這會(huì)導(dǎo)致內(nèi)存消耗過大。并且许赃,修改文件內(nèi)容會(huì)引起復(fù)制寫操作止喷,降低寫入性能。因此混聊,在使用mmap時(shí)弹谁,需要根據(jù)實(shí)際情況進(jìn)行權(quán)衡和選擇。
六句喜、未完待續(xù)
下章將繼續(xù)介紹異構(gòu)計(jì)算的關(guān)鍵技術(shù):多線程的深度探索與應(yīng)用预愤。
歡迎關(guān)注知乎:北京不北,+vbeijing_bubei
歡迎+V:beijing_bubei
歡迎關(guān)注douyin:near.X (北京不北)
獲得免費(fèi)答疑咳胃,長期技術(shù)交流植康。