StratoVirt 是計(jì)算產(chǎn)業(yè)中面向云數(shù)據(jù)中心的企業(yè)級虛擬化 VMM,實(shí)現(xiàn)了一套架構(gòu)統(tǒng)一支持虛擬機(jī)、容器、Serverless 三種場景。StratoVirt 在輕量低噪、軟硬協(xié)同、Rust 語言級安全等方面具備關(guān)鍵技術(shù)競爭優(yōu)勢。
背景介紹:
通常,在同一臺(tái)服務(wù)器上存在著不同的用戶,而多數(shù)用戶對內(nèi)存的使用情況是一種間斷性的使用。也就是說用戶對內(nèi)存的使用率并不是很高。在服務(wù)器這種多用戶的場景中,如果很多個(gè)用戶對于內(nèi)存的使用率都不高的話,那么會(huì)存在服務(wù)器實(shí)際占用的內(nèi)存并不飽滿這樣一種情況。實(shí)際上各個(gè)用戶使用內(nèi)存的分布圖可能如下圖所示(黃色部分表示 used 部分,綠色部分表示 free 的部分)。
解決方案:
為了解決上述服務(wù)器上內(nèi)存使用率低的問題,可以將虛擬機(jī)中暫時(shí)不用的內(nèi)存回收回來給其他虛擬機(jī)使用。而當(dāng)被回收內(nèi)存的虛擬機(jī)需要內(nèi)存時(shí),由 host 再將內(nèi)存歸還回去。有了這樣的內(nèi)存伸縮能力,服務(wù)器便可以有效提高內(nèi)存的使用率。在 StratoVirt 中,我們使用 balloon 設(shè)備來對虛擬機(jī)中的空閑內(nèi)存進(jìn)行回收和釋放。下面詳細(xì)了解一下 StratoVirt 中的 balloon 設(shè)備。
balloon 設(shè)備簡介:
由于 StratoVirt 只是負(fù)責(zé)為虛擬機(jī)分配內(nèi)存,只能感知到每個(gè)虛擬機(jī)總的內(nèi)存大小。但是在每個(gè)虛擬機(jī)中如何使用內(nèi)存,內(nèi)存剩余多少。StratoVirt 是無法感知的,也就無法得知該從虛擬機(jī)中回收多少內(nèi)存了。為此,需要在虛擬機(jī)中放置一個(gè)“氣球(balloon)”設(shè)備。該設(shè)備通過 virtio 半虛擬化框架來實(shí)現(xiàn)前后端通信。當(dāng) Host 端需要回收虛擬機(jī)內(nèi)部的空閑內(nèi)存時(shí),balloon 設(shè)備“充氣”膨脹,占用虛擬機(jī)內(nèi)部內(nèi)存。而將占用的內(nèi)存交給 Host 使用。如果虛擬機(jī)的空閑內(nèi)存被回收后,虛擬機(jī)內(nèi)部由于業(yè)務(wù)要求突然需要內(nèi)存時(shí)。位于虛擬機(jī)內(nèi)部的 balloon 設(shè)備可以選擇“放氣”縮小。釋放出更多的內(nèi)存空間給虛擬機(jī)使用。
balloon 實(shí)現(xiàn):
balloon 的具體代碼實(shí)現(xiàn)位于 StratoVirt 項(xiàng)目的/virtio/src/balloon.rs 文件中,相關(guān)細(xì)節(jié)可閱讀代碼理解。代碼架構(gòu)如下:
virtio ├──Cargo.toml └──src ├──balloon.rs ├──block.rs ├──console.rs ├──lib.rs ├──net.rs ├──queue.rs ├──rng.rs ├──vhost │├──kernel ││├──mod.rs ││├──net.rs ││└──vsock.rs │└──mod.rs ├──virtio_mmio.rs └──virtio_pci.rs
由于 balloon 是一個(gè) virtio 設(shè)備,所以在前后端通信時(shí)也使用了 virtio 框架提供的 virtio queue。當(dāng)前 StratoVirt 支持兩個(gè)隊(duì)列:inflate virtio queue(ivq)和 deflate virtio queue(dvq)。這兩個(gè)隊(duì)列分別負(fù)責(zé) balloon 設(shè)備的“充氣”和“放氣”。
氣球的充放氣時(shí),前后端的信息是通過一個(gè)結(jié)構(gòu)體來傳遞。
structVirtioBalloonConfig{ ///NumberofpageshostwantsGuesttogiveup. pubnum_pages:u32, ///Numberofpageswe'veactuallygotinballoon. pubactual:u32, }
因此后端向前端要內(nèi)存的時(shí)候,只需要修改這個(gè)結(jié)構(gòu)體中的 num_pages 的數(shù)值,然后通知前端。前端讀取配置結(jié)構(gòu)體中的 num_pages 成員。并與本身結(jié)構(gòu)體中的 actual 對比,判斷是進(jìn)行 inflate 還是 deflate。
inflate
如果是 inflate,那么虛擬機(jī)以 4k 頁為單位去申請?zhí)摂M機(jī)內(nèi)存,并將申請到的內(nèi)存地址保存在隊(duì)列中。然后通過 ivq 將保存了分配好的頁面地址的數(shù)組分批發(fā)往后端處理(virtio queue 隊(duì)列長度最大 256,也就是一次最多只能傳輸 1M 內(nèi)存信息,對于大于 1M 的內(nèi)存只能分批傳輸)。后端通過得到信息后,找到相應(yīng)的 MemoryRegion,將對應(yīng)的 page 標(biāo)記為”WILLNEED“。然后通知前端,完成配置。
deflate
如果是 deflate 則從保存申請到的內(nèi)存地址隊(duì)列中彈出一部分內(nèi)存的地址。通過 dvq 分批次傳輸給后端處理。后端將 page 標(biāo)記為“DONTNEED"。
下面結(jié)合代碼進(jìn)行說明:
定義 BalloonIoHandler 結(jié)構(gòu)體作為處理 balloon 事件的主體。
structBalloonIoHandler{
///Thefeaturesofdriver.
driver_features:u64,
///Addressspace.
mem_space:Arc,
///Inflatequeue.
inf_queue:Arc>,
///InflateEventFd.
inf_evt:EventFd,
///Deflatequeue.
def_queue:Arc>,
///DeflateEventFd.
def_evt:EventFd,
/*省略*/
}
其中包含上述的兩個(gè) virtio 隊(duì)列inf_queue和def_queue,以及對應(yīng)的觸發(fā)事件描述符(EventFd)inf_evt和def_evt。兩個(gè)隊(duì)列均使用了Mutex鎖,保證了隊(duì)列在同一時(shí)刻只有一個(gè)使用者對該隊(duì)列進(jìn)行操作。保證了多線程共享的數(shù)據(jù)安全。
fnprocess_balloon_queue(&mutself,req_type:bool)->Result<()>{
letqueue=ifreq_type{
&mutself.inf_queue
}else{
&mutself.def_queue
};//獲得對應(yīng)的隊(duì)列
letmutunlocked_queue=queue.lock().unwrap();
whileletOk(elem)=unlocked_queue
.vring
.pop_avail(&self.mem_space,self.driver_features)
{
matchRequest::parse(&elem){
Ok(req)=>{
if!self.mem_info.has_huge_page(){
//進(jìn)行內(nèi)存標(biāo)記
req.mark_balloon_page(req_type,&self.mem_space,&self.mem_info);
}
/*省略*/
}
Err(e)=>{
/*省略錯(cuò)誤處理*/
}
}
}
/*省略*/
}
當(dāng)相應(yīng)的EventFd被觸發(fā)后process_balloon_queue函數(shù)將會(huì)被調(diào)用。通過判斷請求類型確定是“充氣”還是”放氣“,然后再從相應(yīng)的隊(duì)列中取數(shù)據(jù)進(jìn)行內(nèi)存標(biāo)記。其中while let是 Rust 語言提供的一種循環(huán)模式匹配機(jī)制。借助該語法可以將隊(duì)列中 pop 出來的所有數(shù)據(jù)遍歷取出到elem中。
內(nèi)存標(biāo)記及優(yōu)化:
標(biāo)記內(nèi)存在mark_balloon_page函數(shù)中進(jìn)行實(shí)現(xiàn),起初的實(shí)現(xiàn)思路為:將虛擬機(jī)傳送過來的地址逐個(gè)進(jìn)行標(biāo)記。即,從隊(duì)列中取出一個(gè)元素,轉(zhuǎn)化為地址后立即進(jìn)行標(biāo)記。后來經(jīng)過測試發(fā)現(xiàn):balloon 設(shè)備在對頁地址進(jìn)行一頁一頁標(biāo)記內(nèi)存時(shí)花費(fèi)時(shí)間巨大。而同時(shí)也發(fā)現(xiàn)通過虛擬機(jī)傳回來的地址中有大段的連續(xù)內(nèi)存段。于是通過改變標(biāo)記方法:由原來的一頁一頁標(biāo)記改為將這些連續(xù)的內(nèi)存統(tǒng)一標(biāo)記。大大節(jié)省了標(biāo)記時(shí)間。下面代碼為具體實(shí)現(xiàn):
fnmark_balloon_page( &self, req_type:bool, address_space:&Arc, mem:&BlnMemInfo, ){ letadvice=ifreq_type{ libc::MADV_DONTNEED }else{ libc::MADV_WILLNEED }; /*略*/ foriovinself.iovec.iter(){ letmutoffset=0; letmuthvaset=Vec::new(); whileletSome(pfn)=iov_to_buf:: (address_space,iov,offset){ offset+=std:: ()asu64; letgpa:GuestAddress=GuestAddress((pfnasu64)<addr, None=>{ /*略*/ } }; //將hva地址保存在hvaset的vec中 hvaset.push(hva); } //對hvaset進(jìn)行從小到大排序。 hvaset.sort_by_key(|&b|Reverse(b)); /*略*/ //將hvaset中連續(xù)的內(nèi)存段進(jìn)行標(biāo)記 whileletSome(hva)=hvaset.pop(){ iflast_addr==0{ free_len+=1; start_addr=hva; }elseifhva==last_addr+BALLOON_PAGE_SIZE{ free_len+=1; }else{ memory_advise( start_addras*constlibc::c_voidas*mut_, (free_len*BALLOON_PAGE_SIZE)asusize, advice, ); free_len=1; start_addr=hva; } ifcount_iov==iov.iov_len{ memory_advise( start_addras*constlibc::c_voidas*mut_, (free_len*BALLOON_PAGE_SIZE)asusize, advice, ); } count_iov+=std:: ()asu64; last_addr=hva; } /*略*/ } } }
首先將 virtio 隊(duì)列中的地址全部取出,并保存在 vec 中,然后將該 vec 進(jìn)行從小到大的排序。有利于快速找出連續(xù)的內(nèi)存段并進(jìn)行標(biāo)記。由于 hvaset 中的地址是按照從小到大排列的,因此可以從頭開始遍歷 hvaset,遇到不連續(xù)的地址后將前面的連續(xù)段進(jìn)行標(biāo)記。這樣就完成了由原來逐頁標(biāo)記到連續(xù)內(nèi)存段統(tǒng)一標(biāo)記的優(yōu)化。
經(jīng)過測試,StratoVirt 的 balloon 速度也有了極大的提高。
原文標(biāo)題:StratoVirt 基于 Rust 的 balloon 功能實(shí)踐
文章出處:【微信公眾號:openEuler】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
-
服務(wù)器
+關(guān)注
關(guān)注
14文章
10262瀏覽量
91528 -
虛擬機(jī)
+關(guān)注
關(guān)注
1文章
972瀏覽量
30493 -
數(shù)據(jù)安全
+關(guān)注
關(guān)注
2文章
769瀏覽量
30857
原文標(biāo)題:StratoVirt 基于 Rust 的 balloon 功能實(shí)踐
文章出處:【微信號:openEulercommunity,微信公眾號:openEuler】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
initrd 中沒有帶有自編譯內(nèi)核的 nvme 設(shè)備?
半導(dǎo)體制造中晶圓清洗設(shè)備介紹
太誘產(chǎn)品在通用電子設(shè)備中的使用指南及技術(shù)剖析
如何在Linux中列出USB設(shè)備
SP系列連接器在呼吸機(jī)與麻醉設(shè)備中的應(yīng)用
SNMP協(xié)議在設(shè)備監(jiān)控中的使用
CAN轉(zhuǎn)PROFINET網(wǎng)關(guān)設(shè)備基本功能介紹
智能設(shè)備中Leadway電源模塊的應(yīng)用案例
振動(dòng)馬達(dá)在VR設(shè)備中的應(yīng)用優(yōu)點(diǎn)分析
高校智慧教室多媒體教學(xué)設(shè)備介紹
StratoVirt 中的 balloon 設(shè)備介紹
評論