天天看點

Android存儲系統如何優化?

Android存儲系統如何優化?

答案是我也不知道…

那為什麼會想到要寫這篇文章哪?主要是因為有天晚上和以前一個同僚讨論到Android手機存儲系統的優化問題,我想把我知道的寫下來。用過Android手機的人可能都會有這麼個感覺,就是手機用久了之後系統會越來越慢。慢,其中很重要的一點就是和Android的存儲系統有關。我們現在主流手機的内置存儲晶片一般都是EMMC,一些旗艦級的Android手機已經在使用UFS接口的存儲晶片,而iphone 6S開始更是用上了NVME接口的存儲晶片。同僚是做linux kernel相關工作的,他在想,是不是可以在kernel層面優化下Android的存儲系統,改善下EMMC的壞塊管理、磨損均衡等内容。

接觸過一年的SSD固件開發,沒有接觸過EMMC。但是根據我的了解,EMMC其實就是一個弱化版或者叫精簡版的SSD,核心原理和思想是一樣的。是以我得出的答案是:同僚想做的那些事,kernel什麼也做不了。首先來一張大圖,我們可以看到,磨損均衡、垃圾回收、壞塊管理,這些事情已經全部被SSD、EMMC做掉了,主機端在這些事情上可以說是完全透明的。同僚的想法其實還停留在若幹年前嵌入式系統使用裸的FLASH晶片,需要自己管理這些繁雜事情的年代。

Android存儲系統如何優化?

作為一篇科普貼,這篇文章的閱讀對象是對當今的FLASH和SSD不甚了解的朋友們,而并不是那些存儲界的老鳥們^_^

首先說下nand flash的種類,當今的nand flash主要分為三種:slc、mlc和tlc。slc每個cell存儲一個bit,可以表示0或者1。mlc每個cell存儲兩個bit,可以表示0-3。tlc每個cell存儲三個bit,可以表示0-7。

Android存儲系統如何優化?

先說說最簡單的slc,它是怎麼實作一個bit的存儲的。看下圖,四個黑點是可以加壓的地方。floating gate周圍包圍着一層絕緣層,在初始狀态下(也就是擦除狀态下),floating gate裡沒有電子,表示邏輯1。

Android存儲系統如何優化?

對這個cell程式設計就是把這個cell寫成邏輯0,這時需要在control gate加高壓,在substrate接地,使得電子被強行打穿絕緣層進入floating gate,并被一直困在裡面。

Android存儲系統如何優化?

而擦除動作就是逆向操作,在substrate加高壓,在control gate接地,使得困在floating gate的電子得以釋放,恢複邏輯1。

Android存儲系統如何優化?

在讀操作的時候,往source和drain兩邊加壓,假如floating gate裡有電子,會使得這個電路斷路,代表邏輯0。

Android存儲系統如何優化?

而假如floating gate裡沒有電子,則會使得這個電路導通,代表邏輯1。

Android存儲系統如何優化?

這樣,我們就可以通過往source和drain加壓後電路是否導通來判斷這個cell存儲的是1還是0了。譬如這裡加上2V的電壓,能通就代表邏輯1,不通就代表邏輯。

Android存儲系統如何優化?

mlc把打入電子這個動作做得更為精确細膩了,是以通過把電壓的區間劃分為更精細的四段來表示11、10、01和00。讀操作的時候,會嘗試1V、2V和3V三次,根據能否導通來确定cell裡面存儲的值。tlc亦是如此,隻是區間變成了8段。

Android存儲系統如何優化?

剛才看的一直是一個cell,這裡我們可以看到,橫向的同一個word line上的cell組成了一個page,寫操作的最小操作單元就是一個page。一共有多少個word line就代表這個block上有多少個page,擦除操作的最小操作單元就是一個block。

Android存儲系統如何優化?

看了那麼多的nand flash原理了,我們來看看實際的産品。這裡要介紹幾個概念就是package、target、lun(有的地方叫die,一個意思)。package你可以了解為我們日常能見到的封裝好的PCB闆上的flash晶片。package裡包含一個或多個target,每個target獨享實體管腳譬如ce、data[7:0],是以各個target之間是完全并行獨立的。然後一個target裡又可以包含一個或多個lun,lun也是可以獨立運作的單元,和target的差別在于lun之間共享實體管腳。

Android存儲系統如何優化?

再看一個lun裡有可以有一個或者多個plane,plane也是可以獨立運作指令的單元。是以總結一下,一塊flash晶片,通常來說,容量越大,target、lun、plane就越多,性能就越好,因為這些實體單元都可以獨立并行工作,使得效率最大化。這也就使得我們買的手機,自帶的存儲空間越大,性能就可能越好,其實就是越貴約好了,哈哈!

Android存儲系統如何優化?

這裡還要補充幾個知識點,有些資料有了很大變化,有些則是文檔裡沒有,靠經驗口口相傳的結論:

  • 大家都知道nand flash要擦了之後才可以寫,但是大家知道嗎,現在的mlc的擦寫次數已經和我們在書本裡學到的有天壤之别了。以前看到的什麼slc幾十萬次,mlc幾萬次那已經一去不複返了。由于flash的制造技術的提升,半導體越做越小。好處是flash的容量越來越大,但是帶來一個問題就是之前提到的floating gate周圍的絕緣層也越來越薄。電子每次被加壓強行穿過的時候,對絕緣層都會有一定的損傷。以前絕緣層厚,是以能擦寫幾萬次,而現在的mlc一般隻有可憐的3000(3k)次左右。有的2d的tlc更是到了慘不忍睹的300次。說到2d,那大家肯定會猜是不是還有3d。沒錯,由于工藝的提升,到的一定的程度,flash的耐久度到了極限了,于是以三星為代表的flash廠家想出了一個應對方法,就是把電路垂直往上疊,這樣的話,就可以在總容量不變的情況下,把工藝降低。這樣,容量也有了,耐久度也有了。是以3d tlc的擦寫次數又回到了兩三千次。
  • 擦寫次數并不是說标的3000,就是擦寫了3000次就壞了。有人做過實驗,實際可以擦寫幾萬次,還能正常工作。那這标的3000次又有什麼意義那?還要說到那個絕緣層,雖然絕緣層能困住大部分的電子,但是其實還是會有很少一部分電子偷偷跑出來的。随着時間的推移,譬如半年一年之後,這個cell裡的電子可能已經少了很多,而導緻讀出來的資料發生了錯誤。這就是flash的retention能力。每個廠商都會定一個這樣的時間,3000次的擦寫次數的意義就在于保證了在這3000次以内,retention能力是不會下降到可接受範圍以外的。超過了3000次,cell不會壞,但是retention能力會下降。假如真的擦寫了幾萬次之後一個block還能正常工作,那估計它的retention已經慘不忍睹了。

是以我們感覺到android系統用久了變慢,我能想到的和存儲相關的幾點就是:

  • flash确實發生了老化,不一定就是壞塊了,單至少穩定性變差、出錯機率變高,雖然通過bch、ldpc等糾錯算法可以恢複,但是需要的時間變長了。
  • 由于存儲卡越用越滿,後期發生的寫操作帶來巨大的寫放大,嚴重影響性能。說到寫放大,先要介紹一個名詞叫預留白間(Over provisioning),就是說預留一部分存儲空間不儲存資料。預設情況下,由于1024和1000的誤差,至少會有7%多一點點的OP存在,記住,沒有OP,SSD是不能工作的,或者說即使可以勉強工作,效率也很差。為什麼這麼說那?主要就是因為nand flash以塊擦以頁寫的特性。假設我們用零OP,那倒最後,所有的block上所有的page儲存的都是有用的資料。當我們想要更新當中某個page,由于不能直接覆寫寫,我們需要把整個block騰出來,然後擦掉它,再把更新好的資料寫回去。從上面的圖可以看到,現在一個block的大小有2MB(還有更大的)。對有DRAM的SSD而言,也許還能把這個block的資料緩存在DRAM中,但對沒有DRAM的低端SSD和emmc這種裝置,根本不會有那麼大的ram來緩存這些資料,那就陷入了死循環了。是以我們必須預留OP來做垃圾回收。
    Android存儲系統如何優化?
    OP是可以改變的,有的是廠商改,有的則是開放給了使用者改(譬如我家裡的三星ssd),但是猜想emmc給使用者改OP的機率不大。
    Android存儲系統如何優化?
    那如何提升性能哪?接下來就可以介紹寫放大(Write amplification)了。寫放大的定義就是主機要寫一份資料,而由于flash按塊擦按頁寫的特性,N份資料需要挪動到新的實體位置。最後ssd主要為了實作主機的一份寫而真是操作了N+1份寫,那寫放大就是N+1倍。那到底為什麼會這樣那?譬如我們就拿7%的OP來舉例。在長期使用之後,我們可以認為有用的資料和髒資料是很均勻的分部在flash上的。是以在滿盤的情況下,一個block假設如上圖有256個page,那差不多是238個存着有用的資料,而18(7%*256)個存着已經不要了的垃圾資料。為了寫新資料,就需要搬動老的資料。此時,不論盤有多滿,固件必須保證有一個block是空的,然後就把剛才那個block的238個有用page搬過來,再在後面寫入新的page,當然,之前那個block則又可以擦除了。為了寫這18個page,固件實際寫了256個page,寫放大十幾倍,性能就非常的差了,flash的壽命也會下降比較快。
  • 由于長時間的使用,原本連續的一個檔案的内容已經分部在多個不同的實體位置了,導緻讀取時間變長。

然而對于這些,kernel已經完全被屏蔽了,kernel讀寫emmc,隻會告訴它想要讀寫的邏輯位址LBA,emmc的FTL(Flash translation layer)負責把這個邏輯位址轉換為真正nand上的實體位址。連真正的位址都不知道的kernel,完全就是透明的了。而且現在的nand flash存在着各種坑,emmc這種形式的好處就是把需要關心的細節留給了emmc的固件開發人員。所謂術業有專攻,把這些複雜的東西留給專業的人搞,其實是個不錯的選擇,要不然廣大手機廠商還要自己關心這些細節,負擔大了不說,做出來的性能也不見得更好。

最後給出一張很權威很經典的圖。linux的存儲系統要做優化,從kernel層面我覺得可行的是自上而下優化file system、block layer、mmc driver。但是具體細節我也不懂,感歎一聲學無止盡啊!

Android存儲系統如何優化?