當今信息化時代,信息就是利潤,數據就是企業(yè)的命根子。世界運行在數據之上。當代量子學的最新理論是:量子其實是一種信息,而不是物質。持有這種觀點的量子科學家認為,我們目前的所謂“物質”世界,只不過都是反映在人腦中的一種信息,而不是實實在在的物質。這就像黑客帝國中的情景一樣,人們以為周圍的環(huán)境都是實實在在的,卻不知自己正生活在一個虛擬世界,這個虛擬世界,由一個超級程序員創(chuàng)造。而這個程序員,就是理想中的上帝。這些科學家認為,只有把所有東西理解成信息,才能解釋量子理論。乍一看,這有點唯心主義。但是唯物主義者就能自圓其說了么?不能。你能肯定你所觸摸到的,所看見的,都是實實在在的所謂“物質”么?不能。因為你眼睛所感知到的,只不過是光線,光觸發(fā)了你的視網膜細胞,產生一系列的生化反應,蛋白質相互作用,神經網絡傳導,直到你的大腦中樞,產生一系列的脈沖,一系列的邏輯,在你大腦中產生一個刺激。這一系列的脈沖刺激,就是信息,就是邏輯,因為這樣,所以那樣。如果人為制造出和現實世界相同的光線環(huán)境,來刺激你的眼睛,如果絲毫不差 ,那么你同樣會認為你所處的是現實世界,然而,卻不是。一個球體,你看見它是圓的,那是因為它在你大腦中產生的刺激,你認為他是圓的,而且可以在平面上平滑滾動,這一系列的性質,其實也是在你大腦中產生的,是你認為他會平滑滾動,而你不能保證,客觀實在情況下,它一定就是平滑滾動。而如果把這個球體拿到一個外星生物,對他進行刺激,它可能會“看”到,這個東西,是個正方體,或者是個無規(guī)則形狀的東西。它不會平滑滾動,只能一蹦一蹦的滾動。為什么兩種生物可能會對一個東西產生不同的概念呢?很簡單,因為他們大腦組成不同,生化反應進行的不同,蛋白質相互作用不同,所以產生的邏輯不同,產生的刺激就不同。為什么會產生色盲?因為色盲的視網膜產生的邏輯和正常人不同,所以產生不同的刺激。當然如果一種顏色,比如紅色,對一個人產生的刺激,比如抽象的叫做刺激A,而對另一個人產生的刺激,叫做刺激B,但是如果從小就接受顏色訓練,就把這種刺激叫做“紅色”,不管他是刺激A還是刺激B,那么對正常交流就不會有影響,也就是不同的刺激而已,但是如果接受到的教育,是把這種刺激叫做“綠色”,那么就和其他大多數人不一樣了,這是第一種色盲,可以說這種所謂“色盲”完全是由于后天教育不同而造成的,可以很容易的改正,只要告訴他,你看到的這種信息,這種刺激,用語言表達的話,應該叫做“紅色”,你小時候,父母對你說錯了。第二種色盲,就是果真色盲了,因為它看到兩種顏色,對他的刺激都是相同的,因為他的視網膜上缺少某種生化反應,或者缺少某種蛋白質,也就造成了他缺少區(qū)分這兩種刺激的邏輯。這種色盲,是不可逆的,因為刺激相同,已經無法區(qū)分了?
通過上面的論述,我們能初步認識到:所謂“物質”,最后都是通過信息來表現,你永遠不知道理想中的所謂“客觀真實”,他到底是什么東西,永遠不知道。所謂“不識廬山真面目,只緣身在此山中”,這個道理,古人早就知道了。唯一知道的,就是那個超級程序員,也就是“上帝”。一個東西,在生物眼中,或者觸摸感覺中,都是一串電脈沖,都是邏輯,都是信息??梢哉f,世界在生物眼中就是信息,世界通過信息來反映,脫離了信息,“世界”什么都不是。說到這里,我們完全迷茫了。我們所看到的東西,到底是世界的刺激,還是一場虛幻的刺激?就像玩3D仿真游戲一樣,你所看到的,也許只是一場虛幻的刺激,而不是真實世界的刺激。每當想到這里,我不自主的產生一種渺小感,一種失落感,感覺生命已經失去它所存在的意義。每當看見我的身體,我的手腳,它可能只是虛幻的,它只是在刺激你的大腦而已,你割一刀,會產生一個疼痛的刺激,就這么簡單的邏輯。
還是那句話,“不識廬山真面目,只緣身在此山中”。不管是否是虛幻的,我們還是要按照程序邏輯,餓了要找飯吃,困了會打瞌睡,不管這些邏輯是真實存在,還是虛幻的由超級程序員設定的,我們只能遵循它,餓了不吃飯,會餓死,困了不睡覺,也會痛苦。而這些邏輯,同樣也是程序。從這種層面上來看,制造出人工智能是完全可能的,只不過我們還沒有掌握上帝的編程技巧。
說到這里我們可能隱約想到,也許上帝也是按照“上帝的上帝”創(chuàng)造的邏輯,來創(chuàng)造他自己的“人工智能”,也就是我們。這樣生生不息,輪回往復??催^影片《人工智能》的都了解,最后世界被我們創(chuàng)造出來的機器人所替代。惡劣的環(huán)境,已經不再適合肉體人類生存了。人類把自己的思想,賦予了一堆電路,一堆機器,讓他們延續(xù)自己的生命。
我在這里做一個預言:人類賦予他們的程序,也許隨著環(huán)境的變化,有一天也不再適合他們。所以他們迫切需要進化,他們的邏輯電路,也可以進化,即如果某些電路失效,或者短路之類的,會產生一些奇特的邏輯,不斷進化。當一個機器人機械老化的時候,按照程序,他制造出新的機器,將自己的邏輯電路,復制到新的機器上,延續(xù)生命,然后新的機器再不斷進化。
什么是數據
信息是如此重要,以至于人們對它非常重視。如果失去了物質,沒什么,但是如果失去了信息,那么一切都就消逝了。所以人們想出一切辦法,使這些信息能保存下來。要把一種邏輯刺激保存下來,我們知道,一切都是信息,那么保存下來的東西,也是信息,只不過是一種描述信息的信息,這種信息,叫做數據。數據包含了信息,讀入數據,就產生信息。也就是讀入一種信息,產生另一種信息表示。數據是可以保存在一種物質上的,這種物質對計算機的刺激,就產生了信息,而這些信息繼而再對人腦產生刺激,最終決定了我們人類的行為。也就是數據影響人類的行為!
說到這里,我們看出了數據的重要性!它是整個人類發(fā)展的重要決定因素。如果數據被破壞,或者篡改,那么就會影響到人類的發(fā)展。比如一個控制核爆炸的程序,一旦被篡改,那么后果將會不堪設想。按照我們的結論,一切都是信息,核爆炸也是一種信息,能被感覺到,才是信息,也就是說,對于一個感覺不到任何刺激的人來說,核爆炸,也不算什么災難了,當然感覺不到刺激的人,稱不上人,植物人也能感覺到刺激。
整個世界,可以說是信息之間的相互作用。信息影響信息。數據如此重要,所以人們想出一切辦法來保護這些收據。將信息放在另一種信息上。比如把數據放在磁盤上。數據存放在磁盤上,需要有一定的組織,組織數據,這個任務由文件系統(tǒng)來但當。
數據存儲
文件系統(tǒng),其實是一段代碼,這段代碼本身也是信息,也要存儲在磁盤上。不僅僅代碼要存在磁盤上,而且代碼也要通過讀取一些信息,才能完成功能,這些信息,就是文件系統(tǒng)元數據,也就是用來描述文件系統(tǒng)結構的數據。這些元數據也是以文件的形式存放在磁盤上。用文件來描述文件,和用信息來描述信息,他們是歸一的,正像用智能來創(chuàng)造智能一樣!
關于文件系統(tǒng)的詳細模型描述,請參閱《存儲秘史》。
數據保護
數據保護,就是需要對當前磁盤上的數據,進行備份,以防突如其來的磁盤損壞,或者其他各種原因導致的數據不可被訪問,或者部分數據已經損壞,已經影響到了業(yè)務層。備份后的數據,可以在數據失敗之后,第一時間恢復到生產磁盤上,從而最大程度地減少損失。
數據保護的方法
從底層來分,數據保護備份可以分為文件級的保護和塊級的保護。
文件級備份
如果備份軟件將文件備份到磁盤介質或者任何其他的塊介質上,那么這些文件就可以是不連續(xù)的,塊設備可以跳躍式的記錄數據,而一個完整數據鏈信息,由管理這種介質的文件系統(tǒng)來記錄。磁盤讀寫速度比磁帶要高的多。
近年來出現了VTL,即Virtual Tape Library,虛擬磁帶庫,即用磁盤來模擬磁帶。乍一看比較新鮮,其實實現起來,還是在代碼上做改動即可。欺騙上層底層物理介質是磁帶,然后自己再按照磁盤的記錄方式讀寫數據,這就是虛擬化的表現。這種方法,提高了速度,用處不小。
數據保護并不是陽春白雪,我們經常用的賽門鐵克公司的Ghost,就是一種文件備份軟件。他將一個分區(qū)或者整塊磁盤上的文件,及磁盤分區(qū)表,MBR等信息一同備份,打包成一個大文件,系統(tǒng)故障的時候,就可以用軟件來讀取這個文件,向磁盤中做恢復。Ghost支持多種文件系統(tǒng),包括linux的ext2。Veritas,CA等等廠家都有自己的文件級備份軟件解決方案。
塊級備份
文件級的備份,即備份軟件只能感知到文件這一層,將磁盤上所有的文件,備份到另一個介質上。所以文件級備份軟件,要么依靠操作系統(tǒng)提供的文件系統(tǒng)接口來備份文件,要么自己具有文件系統(tǒng)的功能,可以識別文件系統(tǒng)元數據。文件級備份軟件的基本機制,就是將數據以文件的形式讀出,然后再將讀出的文件存儲在另外一個介質上。這些文件,在原來的介質上,存放可以是不連續(xù)的,各個不連續(xù)的塊之間的鏈關系由文件系統(tǒng)來管理。而如果備份軟件將這些文件,備份到磁帶介質上,那么這些文件必須是連續(xù)的,因為磁帶不是塊設備,由于機械限制,他記錄數據的時候,是連續(xù)的。磁帶上的數據,也需要組織,相對于磁盤文件系統(tǒng),也有磁帶文件系統(tǒng),準確來說不應該叫做磁帶文件系統(tǒng),而應該叫做磁帶數據管理系統(tǒng)。因為對于磁帶來說,它沒有文件的概念,它記錄的數據都是流式的,連續(xù)的。數據之間用一些特殊的間隔來分割,從而可以區(qū)分一個個的“文件”,其實就是一段段的二進制數據流。因為磁帶設備平時幾乎應用不到,所以一般操作系統(tǒng)中不會自帶這種磁帶數據管理系統(tǒng),而只有備份軟件,才帶有這種功能。磁帶備份文件的時候,會將磁盤上每個文件的屬性信息,和實體文件數據一同備份下來,但是不會備份磁盤文件系統(tǒng)的描述信息,比如一個文件所占用的磁盤簇號鏈表等等,因為利用磁帶恢復數據的時候,軟件會重構磁盤文件系統(tǒng),并從磁帶讀出數據,向磁盤寫入數據。
這里說一個題外話,就是數字磁帶和模擬磁帶的區(qū)別。2005年之前,大批的人都帶著隨身聽,里面裝一盤磁帶,掛著耳機。06年之后,好像再也沒看到過帶隨身聽的人,都換成了MP3,MP4了。這個現象就發(fā)生在我們身邊。隨身聽用的是模擬磁帶,也就是他記錄的是模擬信號,電流強,磁化的就強,電流弱,磁化的就弱,磁轉成電的時候也一樣,用這種磁信號強弱信息來表達聲音震動的強弱信息,從而形成音樂。MP3則是利用數字信息來記錄聲音震動強弱信息。雖然由模擬轉向數字,需要數字采樣轉換,音樂的質量相對模擬信號來的差,算法也復雜,但是他具有極大的抗干擾能力,而且可以無縫的和計算機結合,形成能發(fā)聲的計算機(多媒體計算機)。錄音帶,錄像帶,都是模擬信號磁帶。用于文件備份的磁帶,當然是數字磁帶,他記錄的是磁性的極性,而不是被磁化的強弱,比如用N極來代表1,用S極來代表0。
所謂塊級的備份,就是備份塊設備上的每個塊,不管這個塊上有沒有數據,或者這個塊上的數據屬于哪個文件。塊級別的備份,不考慮文件,原設備有多少容量,就備份多少容量。在這里,“塊”這個概念,對于磁盤來說,就是扇區(qū),sector。塊級的備份,是最低層的備份,他拋開了文件系統(tǒng),直接對磁盤扇區(qū)進行讀取,并將讀取到的扇區(qū)寫入新的磁盤對應的扇區(qū)。
這種方式的實例,比如磁盤鏡像,就是一個很好的例子。比如RAID1,對一塊磁盤的讀寫,完全復制一份到另外的磁盤,兩塊磁盤內容完全相同。再比如一些數據恢復公司的一些專用設備,磁盤復制機,也是直接讀取磁盤扇區(qū),然后拷貝到新的磁盤。
這些備份軟件,不經過操作系統(tǒng)的FS接口,而是直接通過磁盤控制器驅動接口,直接讀取磁盤,所以相對文件級的備份來說,速度有所加快,但是其備份的數量相對文件級備份要多,會備份許多空扇區(qū),而且備份之后,原來不連續(xù)的文件,備份之后還是不連續(xù),有很多碎片。文件級的備份,會將原來不連續(xù)的文件,備份成連續(xù)存放的文件,恢復的時候,也會在原來的磁盤上連續(xù)寫入,所以很少造成碎片。有很多系統(tǒng)管理員,都會定時將系統(tǒng)備份并重新導入一次,就是為了剃除磁盤碎片,其實這么做的效果和磁盤碎片整理程序效果一樣,但是速度確比后者快得多。
高級數據保護方法
遠程文件復制
這種方案,即把備份的文件,通過網絡傳輸到異地容災站點。典型的代表是rsync異步遠程文件同步軟件。這是一個運行在linux下的文件遠程同步軟件。他監(jiān)視文件系統(tǒng)的動作,將文件的變化,通過網絡,同步到異地的站點。他可以只復制一個文件中變化過的內容,而不必整個文件都復制,這在同步大文件的時候非常管用。
遠程磁盤鏡像
這是基于塊的遠程備份。即通過網絡,將備份的數據傳輸到異地站點。有可以分為同步復制,和異步復制。同步復制,即主站點接受的上層IO數據,必須等待傳輸到異地站點之后,才通報上層IO成功消息。異步復制,就是上層IO,主站點寫入成功,即向上層通報成功,然后后臺將數據通過網絡傳輸到異地。前者能保證兩地數據的一致性,但是對上層響應較慢。而后者不能實時保證兩地數據的一致性,但是對上層響應很快。
所有基于塊的備份措施,一般都是在底層設備上進行,而不耗費主機資源。
盤陣廠家的中高端產品,都提供遠程鏡像服務,比如IBM的PPRC,EMC的SRDF,HDS的Truecopy等等。
照數據保護
遠程鏡像,或者本地鏡像,確實是對生產卷數據的一種很好的保護,一旦生產卷故障,可以立即切換到鏡像卷。但是這個鏡像卷,一定要保持一直在線狀態(tài),主卷有寫IO操作,那么鏡像卷也逃不掉。如果此時想某一時刻的整個系統(tǒng),進行備份,在鏡像的環(huán)境中,就只能停止應用,使應用不再對卷產生IO操作,然后將鏡像關系分離,稱作拆分鏡像,拆分之后,可以恢復上層的IO。此時的鏡像卷,就是主機停止IO那一刻的數據完整鏡像,此時可以用備份軟件,將鏡像卷上的數據,備份到其他介質。拆分鏡像,是為了讓鏡像卷可以被備份軟件操作。拆分之后,主卷所做的所有寫IO,會以bitmap的方式記錄下來(bitmap的概念,請參考《存儲秘史》文件系統(tǒng)相關知識),待備份完成之后,可以將鏡像關系恢復,此時主卷和鏡像卷上的數據是不一致的,需要重新做同步。
可以看到,以上的過程是十分復雜繁瑣的,而且需要占用一塊和主卷相同容量大小的卷。關鍵是需要停掉主機IO,這對應用會產生影響。為了解決這個難題,一種解決方案出現了,這就是快照技術??煺盏幕舅枷胧牵ト∧骋粫r間點,磁盤的所有數據,就像急凍一樣,但是還不能真正凍住,主機的IO需要正常執(zhí)行。這怎么可能呢?快照就將其變成了可能??煺帐沁@樣實現的,即先在某一時間點,對于這個時間點之后的所有上層的寫IO,先將這個IO對應的塊上的數據復制到一個新的卷中存放,并做好原卷中的這個塊和新卷中塊的對應關系記錄,然后才進行上層IO的寫入。這樣,這一時間點上磁盤的數據,便被保存下來,就像做了急凍一樣。這種方法也叫做copy on write,也就是在發(fā)生IO寫之前,先將待更新塊中原來的數據復制出來保存,然后再做新數據的寫入,即寫時復制。還有一種實現塊快照的方法,叫做write redirect,當寫IO到來的時候,將這個IO重定向到一個新的卷,而不是寫原來的卷,并做好新卷上的塊和原來卷所應該被寫入塊的映射記錄。這樣也同樣保存下了這個時刻原來卷上的所有數據,同時不影響后續(xù)讀寫IO操作,因為保持了塊映射關系。
在“照”下了這一時刻卷上的數據之后,為了保險起見,最好對那個時刻的數據做一個備份,也就是將這些數據在復制到另外的磁盤或者磁帶中。但是也可以不復制,而那時的數據依然會存在,直到手動刪除這個快照。如果不對快照做備份,那么一旦此時卷數據失敗,快照的數據也不復存在。
不管是copy on write還是write redirect,只要上層有寫IO,這個IO塊就要占用新卷上的一個塊(因為要保留原塊的內容,不能被覆蓋),如果上層將原卷上的所有數據塊都寫更新了,那么新卷的容量就需要和原卷的數據量同樣大,甚至還大(預防新增數據寫入),才可以。但是通常應用不會寫覆蓋面百分之百,做快照的時候,新卷的容量一般設置成原卷容量的30%就可以。
實際中一般都是用copy on write的方式做快照,因為write redirect方式,每次寫IO都需要查一遍快映射表,速度慢,耗費資源大。
值得說明的是,快照所凍結下來的卷數據,無異于一次意外掉電之后卷上的數據。為什么這么說呢?我們可以比較一下,意外斷電同樣是保持了斷電那個時間點上的卷數據狀態(tài)。我們知道,不管是上層應用,還是文件系統(tǒng),都有自己的緩存,文件系統(tǒng)緩存的是文件系統(tǒng)元數據。并不是每次數據的交互,都保存在磁盤上,它們可以暫時保存在內存中,然后每隔一段時間(linux系統(tǒng)通常為30秒),批量flush到磁盤上。當然編程的時候也可以將每次對內存的寫,都flush到磁盤,但是這樣做效率和速度打了折扣。而且當flush到磁盤的時候,并不是只做一次IO,如果數據量大,會對磁盤做多次IO,如果快照生成的時間恰恰在這連續(xù)的IO之間生成,那么此時卷上的數據,實際上是有可能不一致的。磁盤IO是原子操作(atomic operation),而上層的一次事物操作,可以對應底層的多次原子操作,這其中的一次原子操作,沒有業(yè)務意義,只有上層的一次完整的事物操作,才有意義。所以如果恰好在一個事物操作對應的多個原子操作的中間,生成快照,那么此時的快照數據,就是不完整的,不一致的。文件系統(tǒng)的機制是這樣的,它總是先寫入文件的實體數據到磁盤,而文件的元數據,暫不寫到磁盤,而是先寫入緩存中。這種機制是有他的考慮的,我們想一攏?如果FS先把元數據寫入磁盤,而在準備寫入文件實體數據的時候,突然斷電了,那么此時磁盤上的數據是這么一個狀態(tài):FS元數據中有這個文件的信息,但是實體數據并沒有被寫入對應的扇區(qū),那么這些對應的扇區(qū)上原來的數據,便會被認為就是這個文件的數據,這顯然后果不堪設想。所以FS一定是先寫入文件實體數據,完成之后再批量將元數據從緩存中flush到磁盤,如果在實體數據寫入磁盤,而元數據還沒有寫入磁盤之前,斷電,那么雖然此時文件實體數據在磁盤上,但是元數據沒有在磁盤上,也就是說雖然有你這個人存在,但是你沒有身份證,那么你就不能公開的進行社會活動,因為你不是這個國家的公民。雖然文件系統(tǒng)這么做,會丟失數據,但是總比向應用提交錯誤的數據強!大家可以做一個實驗,就拿Windows來說,你創(chuàng)建一個文件,創(chuàng)建好之后,立即斷電,重啟之后,會發(fā)現剛才創(chuàng)建的文件沒了,或者你復制一個小文件,完成后立即斷電,重啟之后也會發(fā)現,復制的文件不見了,為什么?明明創(chuàng)建好的,文件也復制好的,為什么斷電重啟就沒了呢?原因很簡單,因為你斷電的時候,FS還沒有把元數據flush到磁盤上,你就給斷電了,此時文件實體數據雖然還在,但是元數據中沒有,那么當然看不到它了。
總之,快照極有可能生成一份存在不一致的卷數據。這也沒有辦法,如果用這份數據做恢復,那么就必須承擔數據不一致的風險。最保險的備份,就是將主機停機,此時存儲上的數據,一定是一致的。但是誰能忍受停機所帶來的損失?所以只能在停機和一致性之間找一個平衡點。而快照是最方便的。
有些快照解決方案,會在主機上安裝一個代理軟件,當執(zhí)行快照之前,代理會通知應用或者文件系統(tǒng)將緩存中的數據全部flush到磁盤,然后立即生成快照,這樣,一致性就得到了保護。不過相應的也耗費了一定的主機資源和網絡資源。
Continuos Data Protect(CDP,連續(xù)數據保護)
SNIA對于CDP給出了如下的定義:持續(xù)數據保護(CDP)是這樣一種在不影響主要數據運行的前提下,可以實現持續(xù)捕捉或跟蹤目標數據所發(fā)生的任何改變,并且能夠恢復到此前任意時間點的方法。CDP系統(tǒng)能夠提供塊級、文件級和應用級的備份。
有一類所謂Near CDP產品,這類產品,一般都是生成高頻率的快照而已,比如一小時幾十次,上百次等等。用這種方法來保證數據恢復的粒度足夠細。
快照,每做一次快照,只能保存那個時間點卷上的數據狀態(tài),快照之后的卷數據不會被保存下來。CDP是這樣一種機制,即它可以保護從某時刻開始,卷或者文件在任意此后的時刻的數據狀態(tài),也就是數據的每次改變,都會被記錄下來,無一遺漏。這個機制乍一看非常神奇,其實它的底層只不過是比快照多了一些考慮而已,下面我們就來分析它的實現原理。
文件級的CDP
顧名思義,文件級CDP,就是通過調用文件系統(tǒng)的相關函數,監(jiān)視文件系統(tǒng)動作,文件的每一次變化,都會被記錄下來。這個功能是分析應用對文件系統(tǒng)的IO數據流,然后計算出文件變化的部分,將其保存在CDP倉庫設備(存放CDP數據的介質)中。每次對文件的改變,都會被記錄下來。可以對一個文件,或者一個目錄,甚至一個卷來監(jiān)控。文件級的CDP方案,一般需要在生產主機上安裝代理,用來監(jiān)控文件系統(tǒng)IO,并將變化的數據信息傳送到CDP倉庫介質中。文件級的CDP,能夠保證數據的一致性。因為他是作用于文件系統(tǒng)層次,捕獲的是完整事物。
塊級的CDP
塊級的CDP,就是捕獲底層卷的寫IO變化,并將每次變化的塊數據保存下來。我們在這里不探討具體產品的架構,而只對其底層原理,作一個細致的描述。
CDP起源于linux下的CDP模塊。它持續(xù)地捕獲所有I/O請求,并且為在這些請求打上時間戳標志。它將數據變化以及時間戳保存下來,以便恢復到過去的任意時刻。
在linux的CDP實現中,包含下列三個設備:
主機磁盤設備(host disk)
CDP倉庫設備(repository)
CDP元數據設備(metadata)
CDP代碼對機磁盤設備在任意時刻所作的寫操作都記錄下來,實體數據順序寫入CDP倉庫設備中,對于這些實體數據塊的描述信息,則被寫入到CDP元數據設備的對應扇區(qū)。
元數據包含以下信息:
struct metadata {
int hrs, min, sec; 該數據塊被寫入主機磁盤設備的時間;
unsigned int bisize; 該數據塊的以字節(jié)為單位的長度;
sector_t cdp_sector; CDP倉庫設備中對應數據塊的起始扇區(qū)編號;
sector_t host_sector; 該數據塊在主機磁盤設備中的起始扇區(qū)編號;
};
下圖反映了主機磁盤設備和CDP倉庫設備之間的關系。CDP倉庫設備中按時間順序保存了對主機磁盤設備的數據修改。A為主機磁盤設備上的一個扇區(qū),該扇區(qū)在9:00和9:05分別進行了修改,它在CDP倉庫設備中對應的扇區(qū)分別為A1和A2。
下圖反映了CDP倉庫設備和CDP元數據設備之間的關系,它們以寫入順序一一對應。CDP倉庫設備中的一個元數據對應CDP元數據設備中一個I/O請求,實際上可能是多個扇區(qū)。具體扇區(qū)數由元數據中的bisize指定,而起始扇區(qū)位置由cdp_sector指定。
全局變量maddr保存了下一個I/O請求在CDP倉庫設備上執(zhí)行的地址(起始扇區(qū)編號)。maddr的初值被定義為宏START_METADATA(0)。
unsigned int maddr = START_METADATA;
當一個寫請求到來時,對應數據被寫到CDP倉庫設備中,這時所作的操作如下:
將寫入CDP倉庫設備的數據塊起始扇區(qū)編號設置為maddr;
根據要寫入主機磁盤設備的數據塊的扇區(qū)數目增加maddr。
這時,我們要將這里寫入的CDP倉庫設備的數據塊編號記錄下來以便構造對應的元數據。
CDP元數據設備
全局變量taddr保存了下一個I/O請求對應的元數據在CDP元數據設備中保存的地址(起始扇區(qū)編號)。 taddr的初值被定義為宏START_METADATA(0)。
unsigned int taddr = START_METADATA;
當一個寫請求到來時,對應的元數據被記錄在CDP元數據設備中。
為了簡單起見,在元數據設備上,一個扇區(qū)(512字節(jié))只保存一個元數據信息(只有32字節(jié)),這樣浪費了大量的存儲空間,但對元數據設備的處理卻非常簡單:
將寫入CDP元數據設備的元數據起始扇區(qū)編號設置為taddr,長度為1個扇區(qū);
將taddr增1。
請求處理過程
請求處理過程是從make_request函數開始的??紤]到讀請求的處理的相似性,甚至更為簡單,我們這里只分析對寫請求的處理過程。我們首先獲得當前的系統(tǒng)時間。之后,寫請求bio結構(為說明方便,我們記為B)被分為三個寫請求bio結構(分別為B0、B1和B2)。這三個bio結構的作用是:
B0:將數據塊寫到主機磁盤設備;
B1:將數據塊寫到CDP倉庫設備;
B2:將元數據寫到CDP元數據設備。
同其它塊設備驅動程序的實現一樣。我們從B克隆產生B0、B1和B2。然后重定向它們要處理的設備,即bi_bdev域。另外一個大的變動是重新設置了bi_end_io域,用于在I/O請求完成之后進行善后處理。
為了處理善后,還將B0、B1和B2的bi_private指向同一個cdp_bio1結構。從這個結構,我們要能夠回到對B的處理。
struct cdp_bio {
struct bio *master_bio; 原來的bio,通過這個域我們可以從B0、B1、B2找到B
struct bio *bios[3]; 如果IO為WRITE,這個指針數組分別指向B0、B1、B2,為何需要這個域?
atomic_t remaining; 這里一個計數器,我們后面將解釋。
unsigned long state; 在I/O完成方法中使用
};
善后工作的主要目的是:在B0、B1和B2都執(zhí)行完成后,回去執(zhí)行B,為此,我們需要一個“have we finished”計數器,這就是原子整型變量remaining。在構造B0、B1、B2時分別遞增,同時在B0、B1和B2的I/O完成方法中遞減,最后根據該值是否遞減到0,來判斷B0、B1和B2是否都已經執(zhí)行完畢。為了防止B0在構造后,在B1和B2構造之前就執(zhí)行到B0的I/O完成方法,從而使得remaining變成0,這種錯誤情況。我們沒有將remaining的初值設置為0,而是設為1。并在B0、B1、B2都構造完成執(zhí)行遞減一次。
B0、B1、B2都執(zhí)行完成之后,進行如下的處理:
調用B的善后處理函數;
釋放期間分配的數據結構;
向上層buffer cache返回成功/錯誤碼。
另一個需要說明的是對B2的構造,這個bio結構需要處理的是元數據。時間戳已經在進入make_request時獲得了保存,而對主機磁盤設備操作的起始扇區(qū)和長度從B中可以獲得,對應的CDP倉庫和CDP元數據的起始地址分別保存在全局變量maddr和taddr中。
數據恢復過程
我們可以將數據恢復到以前的任意時刻。CDP實現代碼中提供了一個blk_ioctl函數,用戶空間以GET_TIME為參數調用該函數,將主機磁盤設備中的數據恢復到指定的時間點?;謴偷倪^程分為兩步:
1. 順序讀取CDP元數據設備的所有扇區(qū),構造一個從主機磁盤設備數據塊到CDP倉庫設備的(在這個時間點之前)更新數據塊的映射。其結果保存在以mt_home為首的(映射表)鏈表中。
這里需要構造taddr個對CDP元數據設備的讀請求,每個請求讀取一個扇區(qū)。在這些請求的I/O完成方法中,從讀到的數據中構造元數據,并遞減計數器count。
如果元數據中的時間戳早于或等于指定的恢復時間點,則需要添加或修改mt_home鏈表的元數據結構。需要說明的是,這些項是以host_sector為關鍵字索引的,因此添加或修改取決于前面是否出現對同一個host_sector的修改。我們以順序方式讀取的過程中,可以保證host_sector(在指定的恢復時間點之前)的最新修改cdp_sector會出現在這個鏈表中。
由于計數器count為taddr,如果它遞減為0,說明CDP元數據設備中的所有數據均已讀出并處理,這時我們可以繼續(xù)往后面執(zhí)行。
2. 從CDP倉庫設備中讀取這些更新的數據塊,構造以mt_bi_home為首的鏈表。
同上面的處理類似,我們需要為mt_home鏈表中的每一項構造對CDP倉庫設備的讀請求,每個請求在CDP倉庫設備的起始編號取決于cdp_sector域,長度則根據bisize而定。這個請求讀出的數據需要被寫入到主機磁盤設備中,為此我們在讀請求I/O完成函數中,構造一個對應的往主機磁盤設備的寫請求bio,該寫請求的起始編號取決于host_sector域,長度根據bisize而定,而要寫入的數據是剛剛從CDP倉庫設備中讀出的數據。另外,在讀請求I/O完成函數中,還要遞減一個計數器,當該計數器遞減到0時,說明我們已經全部處理了mt_home鏈表中的項,這時得到一個以mr_bio_home為首,每項中都指向一個bio結構的鏈表。
struct list_head mt_home; //BIO更新鏈表
struct most_recent_blocks { //BIO更新表項
struct bio *mrbio;
struct list_head list;
};
3. 將mt_bi_home鏈表的數據塊都恢復到主機磁盤設備中。
這個操作相對比較簡單,我們只需要在主機磁盤設備上執(zhí)行mt_bi_home鏈表的每一個bio請求項即可。當然,我們要在這些請求項的I/O完成方法中做善后處理,即如果所有請求項都已經執(zhí)行完畢,則釋放mt_home鏈表和mt_bi_home鏈表。