一直都在想,不管用誰的電腦,我都可以得到一個完全一致的工作環境,上面有我喜愛的軟件,有我保存的重要資料,甚至瀏覽器的各種偏好都得一模一樣!現在的云計算技術可以部分解決這個問題,但是遠遠不夠。我的理想境界是,無論身處何地,一開機,看到的就是自己的電腦,或者相當于自己的電腦!自己可以任意處理自己的數據,不把隱私泄露給別人,當然也不要破壞人家已有的軟件環境。要實現該理想,有幾個辦法:
1.?隨時帶一個筆記本或者上網本。到哪里都用它。
2.?帶一個小小的U盤,里面裝好操作系統和軟件,到哪里都可以用它。
3.?只要有一個網絡帳號,到哪里都可以得到一個專屬于自己的安全的軟件環境(含操作系統和應用軟件,以及個人的數據)。
辦法1太麻煩,辦法3需要云計算技術的進一步發展,且網絡帶寬進一步提升。辦法2最現實,也最好用。本文就集中精力來講解如何在U盤上裝一個Linux,自己的軟件和數據都可以在上面永久保存。
A.?版本選擇
Linux的版本很多,這里選擇Ubuntu。理由就是好用,官方和民間的支持都不錯,對PC或者筆記本的兼容性好,本身集成的內容已經能夠滿足桌面用戶的基本需求,在上面用自帶的軟件包管理器獲取軟件也極其方便。不用像其他發行版一樣,經常為了支持某個驅動絞盡腦汁,或者要安裝某個特殊的軟件不得不反復設置。
最新的穩定版是Ubuntu10.04。便攜U盤的目的是提供一個方便的辦公環境,所以應該選擇桌面版,不需要選擇服務器版,除非硬要做一個移動的服務器,呵呵。在32位和64位這兩個版本之間我猶豫了一會兒。理論上64位的性能更好(所以服務器一般都用64位),但是32位的兼容性理所當然會超過64位(很多軟件只有32位版本),且這個U盤系統有可能會跑在比較老的32位CPU上面,所以最終我最終選擇了32位。
B.?Live?USB的制作
很多Linux都支持Live?CD的制作,Ubuntu當然也不例外。Live?CD不僅可以引導電腦安裝系統,它本身就是一個功能豐富的Linux系統,預裝了常用的軟件,完全通過光盤啟動可以進入桌面,瀏覽網頁,在線聊天,編輯文件,樣樣都不在話下。甚至我們可以安裝軟件,不過,由于我們所做的改動都是在內存中進行的,重啟電腦之后,新裝的軟件沒有了,所有改動也都消失了。
現在的Ubuntu也支持Live?USB的制作,省去了刻錄光盤的麻煩。幾乎所有較新的電腦都支持USB啟動,所以,Live?USB可以方便地用來引導系統。當然,它擁有Live?CD的全部功能,更重要的是,U盤本身是可讀可寫的,我們甚至有機會用它來保存自己的更改,這比Live?CD強多了。
我按照官方網站上的指導教程(http://www.ubuntu.com/desktop/get-ubuntu/download),下載了Universal?USB?Installer(版本1.7.9.8),在Windows上很方便地用4G?U盤制作了一個Live?USB。興致沖沖地用它來啟動電腦,果然看到了漂亮的Ubuntu桌面!于是,我給它配好網絡,安裝了一些常用的軟件。過了一會兒,我關閉電腦,把U盤插在另一臺電腦上面。啟動之后,發現系統又變得干干凈凈,自己的改動完全沒有保留!這,這不跟Live?CD是一模一樣的嗎?
上網搜索了一番,有不少制作能夠永久保留用戶數據的U盤版Ubuntu的方法。比如,這篇文章就提到了好幾種方法:https://wiki.ubuntu.com/LiveUsbPendrivePersistent。最直接的就是直接把U盤當成硬盤來安裝。這樣安裝原理簡單,但是對U盤的磨損也是最大的。我們都知道,U盤里面用來存儲的芯片都是Nand?Flash。Flash芯片的每一個塊(block)都有一定的擦除/寫入次數限制,超過這個限制該塊就很可能被壞掉。典型的寫入次數有1萬次和10萬次。平常我們使用的大容量U盤一般都用MLC?Flash芯片,寫入周期大概是1萬次。U盤里的固件做了磨損平衡和壞塊處理等算法,我們把它用作平常保存數據的介質,綽綽有余,也不用擔心寫1萬次就會把U盤寫壞的情況。但是如果用來直接跑系統,由于臨時文件等諸多因素,其寫入的壓力會大很多,在這種情況下,我們不得不考慮U盤的使用時間。所以,直接用U盤當硬盤來裝Linux不推薦。因為這樣的話,即使禁掉了SWAP分區,/tmp分區還會在硬盤上面,該分區的臨時文件會加速U盤的磨損。我按照另外一種辦法http://rudd-o.com/en/linux-and-free-software/a-better-way-to-create-a-customized-ubuntu-live-usb-drive來制作了一個U盤,但是重啟之后,只能停在GRUB的控制臺里,無法啟動Linux。正當我準備詳細琢磨該辦法的時候,我發現Universal?USB?Installer本來就支持制作能夠持久保存數據的U盤,只是之前我沒有注意而已!請看下圖:
之前我忽略了Step?4,用的是No?Persistence的默認值。其實該選項的目的就是讓你選擇合適的大小來保存自己的修改數據。我選擇了2GB?Casper-RW,這樣,我對系統做的任何修改(包括新裝軟件,增加的文件等等),都會被存在casper-rw這個文件當中,該文件最大可以是2G。當然,用戶完全可以不關心casper-rw這個文件,按照以往的用法來使用U盤的Ubuntu。
談到這里,制作U盤版的Ubuntu就告一段落了。利用工具做好的U盤,幾乎可以在任何主流的電腦上面啟動。裝好的軟件也會按照原樣保存下來,爽哉!如果你就像簡單地嘗試一下U盤Linux,看到這里就可以跳過本文其他部分了。如果你想了解有關U盤Linux的部分技術細節,想利用U盤來有效地移動辦公,請繼續看下去。
C.?U盤的分區
U盤當然是容量越大體積越小就越小。現在4G和8G的U盤都很便宜了。我手頭最多的U盤為4G的,所以本文中的U盤大小默認都為4G。我做好一個U盤,還可以把整個U盤的內容備份到一個文件里面,隨時可以恢復系統,且可以方便地把它克隆到另外的U盤上,讓我的移動工作環境進一步實用——它不需要物理上依賴于某個特定的U盤,只要我手頭有備份的鏡像文件,就可以隨時恢復整個系統。
不過,4G的U盤實際容量并沒有4G。這主要是單位換算不同造成的。在Windows,是按照1K=1024字節,1M=1024K,1G=1024來進行計算,U盤的廠商一般按照1K=1000字節,1M=1000K,1G=1000M來計算。所以,在Windows中看到的U盤的實際容量經常為3.7-3.8G(不同的U盤略有差別)。假定我有2個4G的U盤,一個容量是3.7G,一個是3.8G。如果我在3.7G的U盤上裝好系統,然后復制到3.8G的U盤上,沒有任何問題;但是反過來,就會有一部分數據丟掉,可能會導致潛在的問題。為了提高兼容性,我給U盤重新分區,劃了一個3.5G的FAT32分區用來制作系統。Universal?USB?Installer制作U盤Linux的時候,似乎必須要求U盤本身已經被格成FAT格式,否則不能選擇該盤。事實上,U盤Linux的分區本身采用的就是FAT格式,只是上面的文件可能在Linux啟動之后又被當作塊設備,以其他的文件系統格式再次被加載(稍后我會再講)。大家再制作自己的Linux系統時,如果考慮到方便復制等兼容性因素,也可以給U盤保留一點點容量。
Windows的磁盤管理不能直接對U盤進行分區,我們可以借助第三方的工具來進行。我是用二進制編輯工具直接打開U盤,修改第一個扇區(MBR)的分區表來實現預留3.5G大小的分區的。剩下的200MB空間我就讓它保留著好了。因為Flash需要用磨損平衡算法來提高使用壽命,這200MB額外的空間被用到全局的磨損平衡當中,對延長U盤的使用時間很可能有一定的好處。
D.?aufs文件系統
啟動U盤版Ubuntu,輸入mount命令,得到如下的輸出:
aufs?on?/?type?aufs?(rw)none?on?/proc?type?proc?(rw,noexec,nosuid,nodev)none?on?/sys?type?sysfs?(rw,noexec,nosuid,nodev)none?on?/dev?type?devtmpfs?(rw,mode=0755)none?on?/dev/pts?type?devpts?(rw,noexec,nosuid,gid=5,mode=0620)/dev/sdb1?on?/cdrom?type?vfat?(rw,relatime,fmask=0022,dmask=0022,codepage=cp437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro)/dev/loop0?on?/rofs?type?squashfs?(ro,noatime)none?on?/sys/fs/fuse/connections?type?fusectl?(rw)none?on?/sys/kernel/debug?type?debugfs?(rw)none?on?/sys/kernel/security?type?securityfs?(rw)none?on?/dev/shm?type?tmpfs?(rw,nosuid,nodev)tmpfs?on?/tmp?type?tmpfs?(rw,nosuid,nodev)none?on?/var/run?type?tmpfs?(rw,nosuid,mode=0755)none?on?/var/lock?type?tmpfs?(rw,noexec,nosuid,nodev)none?on?/lib/init/rw?type?tmpfs?(rw,nosuid,mode=0755)binfmt_misc?on?/proc/sys/fs/binfmt_misc?type?binfmt_misc?(rw,noexec,nosuid,nodev)gvfs-fuse-daemon?on?/home/ubuntu/.gvfs?type?fuse.gvfs-fuse-daemon?(rw,nosuid,nodev,user=ubuntu)
我們暫且不考慮proc,sysfs等用來對系統進行輔助管理的特殊文件系統,只考慮和U盤的實際存儲打交道的部分。在上述列表里,沒有看到我們最熟悉的ext3/ReiserFS等Linux下的主流文件系統。那到底U盤上建立的是什么文件系統,是如何進行數據保存的呢?
前面已經提到,制作U盤的時候,需要U盤上已有一個FAT32的分區。制作工具把必備的文件拷入到該分區,并不會對分區本身做修改。所以,現在的U盤理所當然地具有一個FAT32的分區。從mount的輸出可以看到,設備/dev/sdb1(就是U盤的第一個分區,電腦的本地硬盤被識別成/dev/sda)被mount到/cdrom,格式為VFAT。顧名思義,該分區的功能類似于Live?CD,我們可以簡單地理解它里面包含了一張Ubuntu安裝光盤所包含的必要內容。因為所有的軟件和數據都保存在/dev/sdb1上,所以/cdrom理所當然地包含了我們需要的一切內容。
但是從/cdrom里面能夠找到的只是有限的文件,似乎大部分都和安裝有關,熟悉的就是/cdrom/casper目錄下的內核文件vmlinuz以及initrd.lz。并不能找到我們所熟悉的其他Linux系統文件以及配置文件。既然/cdrom已經囊括全部了,那根目錄下的/bin,/sbin,/etc又來自哪里呢?
/cdrom/casper下有一個巨大無比的文件filesystem.squashfs,大概700MB,從名字可以猜測,這個文件是不是本身就包含了運行Linux所必需的文件系統?且它的大小也能夠容納足夠的應用程序。在Linux中,單一文件可以被加載成一個loop設備,然后它就可以當作普通的塊設備使用,被mount成其他文件系統。(文件a可以作為塊設備block_a,上面又存在一個文件b,那文件b又可以被作為塊設備block_b,上面又存在一個文件c…一層套一層,這就是《盜夢空間》的文件系統版演繹。)用下面的命令查看當前使用的loop設備信息:
$?sudo?losetup?-a/dev/loop0:?[0811]:27?(/cdrom/casper/filesystem.squashfs)/dev/loop1:?[0811]:33?(/casper-rw-backing/casper-rw)
系統創建了兩個loop設備,其中/dev/loop0就是基于filesystem.squashfs創建的。結合前面mount命令的輸出,我們得以知道/dev/loop0被mount到/rofs目錄,文件系統類型是squashfs。squashfs是一種只讀壓縮文件系統,在很多Linux上普遍使用,速度快,壓縮比例高,乃Live?CD制作的首選。在Ubuntu里簡要查詢了一下,/rofs下共有文件10萬多個,總容量大概是1.7GB。想想原始的filesystem.squashfs的大小才700MB,squashfs的表現已經很不錯。從這里也可以了解到Live?CD(Live?USB)上為什么可以放這么多的內容。
/rofs目錄下有幾乎我們所需要的一切,包括熟悉的bin,sbin,lib,etc,home等目錄。儼然整個Linux系統就被它納入囊中。可是它只是只讀的(rofs表示read?only?file?system),我們現在的U盤Linux對文件系統是可讀可寫的。而且,/rofs下面有一個bin,根目錄下也有/bin,這兩者是什么關系呢?比較了一下,/rofs/bin怎么和/bin似乎一模一樣?
秘密在于aufs?(Another?Union?FS)這個特殊的文件系統。它不是一個普通的文件系統,而是把現有的不同文件系統組合在一起,形成一個統一的文件系統。假設有有兩個文件系統,fs_a和fs_b,它們所掛載的目錄分別是/a和/b。利用aufs,可以讓它們合并起來,/a和/b均可重新映射到根目錄/。實際使用的時候,一般用戶只需要關心根目錄/所對應的文件系統是aufs即可,不必關心太多的底層細節。談到這里,有人就有疑問了。比如,在aufs下創建一個文件,那該文件到底是存在于/a下面,還是/b下面呢?這不存在著很明顯的沖突問題嗎?
實際上,aufs并不具有把任意文件系統聚合在一起的功能。它一般只組合兩個文件系統,其中一個是只讀的,另外一個是可讀可寫的。讀取文件的時候,如果僅僅只讀的文件系統上有該文件,則從只讀該處讀取;如果可讀寫的文件系統上也有該文件,則從可讀寫的文件系統上讀取。寫文件的話,理所當然地就只能往可讀寫文件系統上寫。只讀文件系統可以認為是基礎,可讀寫文件系統是補充,采取copy?on?write(COW,寫時復制)的方式來保存用戶的修改。因為僅僅保存修改部分,所以可以很大程度的節約空間。
就本文的例子來說,/rofs是一個只讀文件系統,另外用了一個文件casper-rw來保存用戶的更改數據。casper-rw是Universal?USB?Installer直接創建在U盤根目錄下的。如果該文件的大小是2G,則可以保存2G的修改內容。如果U盤的空間允許,我們可以向這個文件的末尾追加內容,擴大文件以便增加可保存數據的容量。該文件本身被加載成一個loop設備,從losetup?-a的輸出來看,該設備為/dev/loop1。在此設備上創建好了ext2文件系統,被mount到/cow中。aufs把/rofs和/cow合并起來,一起加載到根目錄/下。/rofs放的是原始文件,/cow保存用戶修改。所以,我們可以看到根目錄下的文件結構基本和/rofs下一模一樣,只是新裝的軟件和新建的文件在/rofs下無法查看。?(aufs的創建位于initrd里的相關腳本,在啟動之后,是無法直接查看/cow等目錄的。)
我們可以這么簡單理解,這個U盤版Ubuntu的基本系統存放于文件filesystem.squashfs當中,對它的修改都存放于文件casper-rw當中。
E.?減少對U盤的磨損
由于Flash芯片的擦除/寫入次數限制,我們在保證滿足自己需要的前提下,盡量減少U盤的寫入次數。默認情況下,U盤版Ubuntu已經禁掉了SWAP分區,且把/tmp掛載到了內存,這些都是延長U盤使用時間的有效手段。
在系統中,默認會把最后一次訪問文件的時間(last?access?time)給記錄到該文件的元數據當中。這個操作的開銷實際上很大,比如,我僅僅打開一個文件不對該文件做任何寫操作,都會導致系統底層對磁盤至少有一次寫操作。對U盤來說,last?access?time的更新也是降低性能,磨損U盤的一個重要因素。該時間對于普通的應用來說沒有任何實際用處,所以我們可以把它禁掉。(有少數程序需要依賴于last?access?time來進行一些特殊判斷,不過,從大局考慮,去掉它是U盤版Linux提高性能減少磨損的一個重要手段。)Linux的mount命令有一個noatime的選項,加上它可以實現禁用last?access?time的功能。(還有一個針對目錄的禁用last?access?time選項,叫nodiratime。但是有人分析只要加了noatime,就會實現nodiratime的功能。)比如,如果把/dev/sdc加載成ext3文件系統,并禁掉last?access?time,我們可以這樣調用mount:
mount?-t?ext3?-o?noatime?/dev/sdc?/mnt/myfs
事實上,在制作U盤版Ubuntu的過程當中,/rofs已經被設置了noatime。加載到/cow打casper-rw以及aufs也都被設置了noatime(mount輸出無法直接查看,但是在initrd.lz的相關腳本中可以看到)。另外,/cdrom是以relatime的方式來mount的。相比noatime來說,relatime是一個考慮性能和功能的折衷方案。只有當文件的last?access?time早于最后修改時間的時候,才會對它進行更新。因此,用relatime的方式,可以記錄文件修改之后的第一次訪問的時間。
日志文件系統(比如ext3)會額外向磁盤寫入日志,以保證文件系統的完整性。但是對于U盤來說,增加的日志無疑會帶來更多的寫入操作。因此,如果對系統的穩定性不敏感的話,建議capser-rw上采用不帶日志的ext2文件系統。事實上,該U盤版Ubuntu在初始化capser-rw時用的就是ext2.
Linux中,除了特別的需求,文件一般都是按異步模式寫入磁盤當中。也就是說,應用程序寫入的數據,會先放在頁緩存(page?cache)里面,等合適的時間再刷(flush)到磁盤當中。這種方式可以提高性能,同時也能夠有效地降低寫入的次數。Linux的內核導出了幾個proc文件,可以供我們調節相關的flush參數。U盤版Ubuntu已經對Linux的默認參數做了一定的修改。相關的proc文件以及Ubuntu的設置值如下:
/proc/sys/vm/dirty_ratio:?20/proc/sys/vm/dirty_background_ratio:?10/proc/sys/vm/dirty_writeback_centisecs:?1500/proc/sys/vm/dirty_expire_centisecs:?3000
簡單解釋如下:當page?cache里的臟數據(dirty?data)超過內存20%(dirty_ratio)的時候,會被馬上刷到磁盤中;如果超過內存10%(dirty_background_ratio),進程pdflush會在后臺異步地把數據刷到磁盤中。如果10%的閾值一直未達到,也不要緊,內核會每隔15秒(dirty_writeback_centisecs)啟動一次flush操作,只要臟數據待在cache的時間超過了30秒(dirty_expire_centisecs),也會被刷到磁盤當中。
為了進一步減少寫的次數,讓臟數據在cache中待得更久,我們可以在啟動腳本里更改部分參數,比如,修改dirty_writeback_centisecs為6000,表示把后臺周期性flush的時間調成60秒一次。修改dirty_expire_centisecs為6000,表示臟數據的超時時間為60秒。另外兩個參數可以不用修改,因為在小量寫入的時候,臟數據一般也達不到內存總量的10%,在大量數據寫入的時候,也沒有必要把臟數據緩存更久。同時請注意,更改這些數據之后,系統突然斷電等異常情況導致數據丟失的概率會相對較大一點。所以如何選擇,得根據自己的需求權衡一下。
另外,U盤上請只裝自己需要的軟件,不要像普通Linux那樣亂裝一通。這是減少U盤寫次數非常重要也非常簡單的一個手段。
F.?備份和還原
U盤版Ubuntu做了一些設置,提高了性能,理論上也應該延長了U盤的使用時間。但是這些操作也會帶來一定的風險,比如系統突然斷電的情況下,最近修改的數據就更容易丟失。我們在此U盤上運行的是桌面系統,主要就是為了方便,功能夠用,不像服務器那樣要求很嚴格,也能夠承擔此風險(如果有更高的可靠性要求,請不要采用此U盤系統)。但是,即使U盤質量再好,我們自己也很注意,它總有可能會損壞,因此,強烈建議對U盤進行定期備份。備份之后的鏡像文件,可以隨時恢復到容量足夠大的U盤上,讓該系統具有迅速克隆的功能。即使你忘記帶了U盤,也可以通過網絡取得該鏡像(網絡速度要足夠快),迅速恢復一個專屬于自己的工作環境。
Windows下的很多工具都具有整盤復制功能。Linux下用dd也可以方便地進行備份(假設U盤的設備名為/dev/sda):
dd?if=/dev/sdb?of=/mnt/backup/ubuntu_bak1.img?bs=1M
塊大小(bs)設置大一點有助于提高性能,尤其是往U盤寫入數據的時候。(大塊的寫入有利于降低U盤的底層IO。對于一般的Flash來說,一次寫1個字節和一次寫4K所產生的IO是一樣的,甚至更多。)假設插入另外一塊U盤/dev/sdc,可以把備份的鏡像燒錄到該U盤上,讓此U盤立馬成為我的定制版Ubuntu:
dd?if=/mnt/backup/ubuntu_bak1.img?of=/dev/sdc?bs=1M
當然,如果想加快備份速度的話,也可以單獨備份casper-rw文件,因為自己所作的修改全部保存在該文件當中。