no-image

AliOS Things KV元件的寫平衡特性

                                    

摘要: KV元件的寫平衡(磨損平衡)特性就是通過異地更新、垃圾回收等策略來平衡flash介質各個儲存區塊的磨損程度,以避免某些“特定”儲存區塊因過度使用而形成壞區,從而延長flash的使用壽命。

前言

 

KV元件是AliOS Things中一個以Key-Value方式進行持久化儲存的輕量級元件,主要為基於nor flash的小型MCU裝置(Micro Control Unit)提供通用的Key-Value持久化儲存介面。KV元件支援寫平衡(磨損平衡)、掉電保護特性,且具有相當低的footprint。這裡主要介紹KV元件在設計寫平衡特性時的一些考量。

What — KV元件的寫平衡特性是什麼

 

對於flash介質而言,它是有一定的擦寫次數限制的。如果針對介質上一個固定地址進行重複的擦除、寫入,將會導致該區域的使用壽命降低,甚至出現介質損壞的情況。KV元件的寫平衡(磨損平衡)特性就是通過異地更新、垃圾回收等策略來平衡flash介質各個儲存區塊的磨損程度,以避免某些“特定”儲存區塊因過度使用而形成壞區,從而延長flash的使用壽命。

Why — KV元件為何需要寫平衡特性

KV元件的設計初衷是為了給基於nor flash的小型MCU裝置提供一個可以儲存配置資訊的模組。對於單個配置資訊而言,一般所需儲存的位元組數大多在十幾個位元組~幾百個位元組量級,而一般nor flash的最小擦除單位(sector)都在4K位元組以上,且根據flash介質需先擦再寫的特點,如果沒有寫平衡特性,每次新寫入或更新配置資訊都會帶來一次flash介質擦除操作,這將大大影響flash介質的使用壽命(一般nor flash的擦除次數限制大約10萬次左右)。

 

下表是flash介質在有無寫平衡特性下重複寫入使用壽命的理論計算對比:

(限制條件:flash擦除sector大小為4k, 擦除次數限制為10W次,每日寫入次數5000次)

有無寫平衡特性 每次寫入資料量(byte) 平均每日擦除次數 使用壽命
yes 50 ≈62 ≈4.4年
no 50 5000 20天
yes 500 ≈610 ≈163天
no 500 5000 20天

 

根據上表的對比,KV元件的寫平衡特性在幾百個位元組量級的寫入情況下起碼可以延長flash 8倍以上的使用壽命。

How — KV元件寫平衡特性的實現考量

由於小型物聯網嵌入式裝置的硬體資源較為匱乏,對code size以及RAM的佔用size比較敏感。所以基於資源消耗的考量,寫平衡特性在KV元件中的實現遵循make it simple原則,主要依賴以下兩個策略來實現:

 

1. 異地更新策略:

Key-Value鍵值對採用順序寫入、異地更新的方式,即不再在原儲存位置擦除重寫,而是在其餘空閒位置寫入新鍵值並將原鍵值標記無效等待回收。這樣既可以減少flash的擦除操作次數,又可以提高flash的空間利用率,也避免了對“特定”儲存區塊過度使用的問題。

示意圖如下:

 

ea52cecb633d6303425c1e3c7242179fafd0327b

 

2. 垃圾回收策略:

當flash儲存區塊的剩餘可用空間達到閾值時,會觸發垃圾回收機制。垃圾回收機制採用基礎的SGC演算法進行資源回收釋放,即當系統觸發垃圾回收時,從當前寫入塊的下一個儲存塊開始依次檢查儲存塊的管理狀態,若儲存塊的管理狀態為Dirty狀態,則將該儲存塊中的有效資料依次挪向垃圾回收預留的空閒儲存塊,當資料遷移完成後,會擦除Dirty儲存塊並標記可用空閒狀態。

示意圖如下:

 

eafefafe8c7177b8aa3c4a23dd669b634c506bf7

 

小結

KV元件的寫平衡特性,在兼顧footprint需求的同時,也能有效的提升flash的使用壽命。不過也是由於footprint的要求,寫平衡特性在演算法的實現相對較為簡單,在資源更豐富的場景下,可以採用更復雜高效一些的平衡演算法。


(adsbygoogle = window.adsbygoogle || []).push({});

function googleAdJSAtOnload() {
var element = document.createElement(“script”);
element.src = “//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js”;
element.async = true;
document.body.appendChild(element);
}
if (window.addEventListener) {
window.addEventListener(“load”, googleAdJSAtOnload, false);
} else if (window.attachEvent) {
window.attachEvent(“onload”, googleAdJSAtOnload);
} else {
window.onload = googleAdJSAtOnload;
}