您好,登錄后才能下訂單哦!
KVM虛擬化原理中的塊設備IO虛擬化是怎樣的,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
作為另外一個重要的虛擬化資源,塊設備IO的虛擬化也是同樣非常重要的。同網絡IO虛擬化類似,塊設備IO也有全虛擬化和virtio的虛擬化方式(virtio-blk)。現代塊設備的工作模式都是基于DMA的方式,所以全虛擬化的方式和網絡設備的方式接近,同樣的virtio-blk的虛擬化方式和virtio-net的設計方式也是一樣,只是在virtio backend端有差別。
如上圖所示,我們把塊設備IO的流程也看做一個TCP/IP協議棧的話,從最上層說起。
Page cache層,這里如果是非直接IO,寫操作如果在內存夠用的情況下,都是寫到這一級后就返回。在IO流程里面,屬于writeback模式。 需要持久化的時候有兩種選擇,一種是顯示的調用flush操作,這樣此文件(以文件為單位)的cache就會同步刷到磁盤,另一種是等待系統自動flush。
VFS,也就是我們通常所說的虛擬文件系統層,這一層給我們上層提供了統一的系統調用,我們常用的create,open,read,write,close轉化為系統調用后,都與VFS層交互。VFS不僅為上層系統調用提供了統一的接口,還組織了文件系統結構,定義了文件的數據結構,比如根據inode查找dentry并找到對應文件信息,并找到描述一個文件的數據結構struct file。文件其實是一種對磁盤中存儲的一堆零散的數據的一種描述,在Linux上,一個文件由一個inode 表示。inode在系統管理員看來是每一個文件的唯一標識,在系統里面,inode是一個結構,存儲了關于這個文件的大部分信息。這個數據結構有幾個回調操作就是提供給不同的文件系統做適配的。下層的文件系統需要實現file_operation的幾個接口,做具體的數據的讀寫操作等。
struct file_operations { //文件讀操作 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); //文件寫操作 ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); int (*readdir) (struct file *, void *, filldir_t); //文件打開操作 int (*open) (struct inode *, struct file *); };
再往下就是針對不同的文件系統層,比如我們的ext3,ext4等等。 我們在VFS層所說的幾個文件系統需要實現的接口,都在這一層做真正的實現。這一層的文件系統并不直接操作文件,而是通過與下層的通用塊設備層做交互,為什么要抽象一層通用塊設備呢?我們的文件系統適用于不同的設備類型,比如可能是一個SSD盤又或者是一個USB設備,不同的設備的驅動不一樣,文件系統沒有必要為每一種不同的設備做適配,只需要兼容通用快設備層的接口就可以。
位于文件系統層下面的是通用快設備層,這一層在程序設計里面是屬于接口層,用于屏蔽底層不同的快設備做的抽象,為上層的文件系統提供統一的接口。
通用快設備下層就是IO調度層。用如下命令可以看到系統的IO調度算法.
? ~ cat /sys/block/sda/queue/scheduler noop deadline [cfq]
noop,可以看成是FIFO(先進先出隊列),對IO做一些簡單的合并,比如對同一個文件的操作做合并,這種算法適合比如SSD磁盤不需要尋道的塊設備。
cfq,完全公平隊列。此算法的設計是從進程級別來保證的,就是說公平的對象是每個進程。系統為此算法分配了N個隊列用來保存來自不同進程的請求,當進程有IO請求的時候,會散列到不同的隊列,散列算法是一致的,同一個進程的請求總是被散列到同一個隊列。然后系統根據時間片輪訓這N個隊列的IO請求來完成實際磁盤讀寫。
deadline,在Linux的電梯調度算法的基礎上,增加了兩個隊列,用來處理即將超時或者超時的IO請求,這兩個隊列的優先級比其他隊列的優先級較高,所以避免了IO饑餓情況的產生。
塊設備驅動層就是針對不同的塊設備的真實驅動層了,塊設備驅動層完成塊設備的內存映射并處理塊設備的中斷,完成塊設備的讀寫。
塊設備就是真實的存儲設備,包括SAS,SATA,SSD等等。塊設備也可能有cache,一般稱為Disk cache,對于驅動層來說,cache的存在是很重要的,比如writeback模式下,驅動層只需要寫入到Disk cache層就可以返回,塊設備層保證數據的持久化以及一致性。
通常帶有Disk cache的塊設備都有電池管理,當掉電的時候保證cache的內容能夠保持一段時間,下次啟動的時候將cache的內容寫入到磁盤中。
應用層的讀寫操作,都是通過系統調用read,write完成,由Linux VFS提供的系統調用接口完成,屏蔽了下層塊設備的復雜操作。write操作有直接IO和非直接IO之分(緩沖IO),非直接IO的寫操作直接寫入到page cache后就返回,后續的數據依賴系統的flush操作,如果在flush操作未完成的時候發生了系統掉電,那可能會丟失一部分數據。直接IO(Direct IO),繞過了page cache,數據必須達到磁盤后才返回IO操作完成。
對于I/O的讀寫流程,邏輯比較復雜,這里以寫流程簡單描述如下:
如上圖所示,在初始化IO設備的時候,會為IO設備分配一部分物理內存,這個物理內存可以由CPU的MMU和連接IO總線的IOMMU管理,作為共享內存存在。以一個讀取操作為例子,當CPU需要讀取塊設備的某個內容的時候,CPU會通過中斷告知設備內存地址以及大小和需要讀取的塊設備地址,然后CPU返回,塊設備完成實際的讀取數據后,將數據寫入到共享的內存,并以中斷方式通知CPU IO流程完成,并設置內存地址,接著CPU直接從內存中讀取數據。
寫請求類似,都是通過共享內存的方式,這樣可以解放CPU,不需要CPU同步等待IO的完成并且不需要CPU做過多的運算操作。
因為塊設備IO的虛擬化需要經過兩次IO協議棧,一次Guest,一次HV。所以需要把塊設備IO協議棧說的很具體一點。
至此,Linux塊設備的IO層就基本介紹完整了,以上內容也只是做一個簡單的介紹,這部分的內容可以很深入的去了解,在此限于篇幅限制,就不做過多介紹了。
塊設備的全虛擬化方式和網絡IO的DMA設備虛擬化方式類似,這里就不過多介紹了,主要介紹一下virtio-blk。
如上圖所示,藍色表示 writethrough,黃色表示 none,紅色表示 writeback。其中虛線表示寫到哪一個層次后write調用返回。
cache=writethrough (藍色線)
表示v-backend打開鏡像文件并寫入時候采用非直接IO+flush操作,也就是說每次寫入到Page cache并flush一次,直到數據被真實寫入到磁盤后write調用返回,這樣必然會導致數據寫入變慢,但是好處就是安全性較高。
cache=none (黃色線)
cache為none模式表示了v-backend寫入文件時候使用到了DIRECT_IO,將會繞過HV的Page cache,直接寫入磁盤,如果磁盤有Disk cache的話,寫入Disk cache就返回,此模式的好處在于保證性能的前提下,也能保證數據的安全性,在使用了Disk cache電池的情況下。但是對于讀操作,因為沒有寫入HV Page cache,所以會有一定性能影響。
cache=writeback (紅色線)
此模式表示v-backend使用了非直接IO,寫入到HV的Page后就返回,有可能會導致數據丟失。
塊設備IO的虛擬化方式也是統一的virtio-x模式,但是virtio-blk需要經過兩次IO協議棧,帶來了不必要的開銷。
看完上述內容,你們掌握KVM虛擬化原理中的塊設備IO虛擬化是怎樣的的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。