メモリ・ストレージ

ウェアレベリング

フラッシュの書き込み回数を分散し寿命を延ばす技術。

概要

ウェアレベリング(Wear Leveling)は、フラッシュメモリの各メモリブロックへの書き込み(消去・再書き込み)回数を均等に分散させることで、特定ブロックの早期劣化を防ぎ、フラッシュ全体の寿命を最大限に活用する技術です。

フラッシュメモリには書き換え回数の上限があります(SLC: 約100,000回、MLC: 約3,000〜10,000回、TLC: 約1,000〜3,000回)。単純に同じアドレスに繰り返し書き込むと、そのブロックだけが先に寿命を迎え、デバイス全体の使用可能容量が急速に失われます。ウェアレベリングはこの問題を解決する根本的な技術です。

eMMC・SSD・SDカードなどのフラッシュストレージデバイスには内蔵コントローラが自動的にウェアレベリングを実施しています。NANDフラッシュを生(Raw NAND)で使う場合はLinux MTD/UBIサブシステム、またはFatFs・LittleFS等のファイルシステムレベルで実装が必要です。組み込みマイコンでNORフラッシュに設定値を保存する場合も、書き込み頻度が高ければウェアレベリングの考慮が必要です。

歴史・背景

フラッシュメモリが1980年代末〜1990年代に普及し始めると、書き換え回数制限という固有の課題が明らかになりました。FAT(File Allocation Table)ファイルシステムはFAT領域を頻繁に更新するため、FAT領域が配置されたブロックだけが先に消耗するという問題が発生しました。

1990年代にM-Systems(後にSandiskが買収)がDiskOnChip製品でFTL(Flash Translation Layer)の概念を提案・実装しました。FTLは論理アドレスと物理アドレスのマッピングを動的に変更することで、書き込みを全ブロックに分散させます。

2000年代に入りNANDフラッシュの大容量化・低価格化が進むとともに、各メーカーが独自のウェアレベリングアルゴリズムを洗練させました。2010年代のSSD普及により、ウェアレベリング技術はさらに高度化し、Write Amplification Factor(WAF)を最小化するためのアルゴリズム競争が続いています。

Linux向けにはUBI(Unsorted Block Images)・UBIFS・JFFS2・YAFFSなどのNAND対応ファイルシステムが開発されました。マイコン向けにはCoffeeCatch・LittleFS・NVS(Zephyr)などが登場し、小さなフットプリントでウェアレベリングを実現しています。

技術仕様

ウェアレベリングの種類

1. 動的ウェアレベリング(Dynamic Wear Leveling)

書き込みが発生したときに、書き込み回数が少ないフリーブロックを選んで書き込む方式。頻繁に更新されるデータは分散されるが、めったに変更されない「コールドデータ」は同じ物理ブロックに留まり続ける。

論理ブロック0 → 物理ブロックA(書き込み回数5)
論理ブロック1 → 物理ブロックC(書き込み回数: 0)← 次の書き込み先
論理ブロック2 → 物理ブロックB(書き込み回数3)
... (フリーブロックのうち最も使用回数が少ないものを選ぶ)

2. 静的ウェアレベリング(Static Wear Leveling)

コールドデータ(頻繁に変更されない静的データ)が入っているブロックも定期的に移動させ、そこに「新鮮な」(使用回数が多い)ブロックを充てる方式。フラッシュ全体をより均等に消耗させられる。

定期的な再配置:
論理ブロック5 (コールドデータ) → 物理ブロックZ (使用回数多い) へ移動
物理ブロック5 (元コールド領域) → フリープール(使用回数少ない)へ

3. グローバルウェアレベリング

デバイス全体(複数のダイ・チップ)にまたがってウェアレベリングを実施。eMMC・SSDの内蔵コントローラが実施。

WAF(Write Amplification Factor)

ウェアレベリング・ガベージコレクションによって、実際にホストが書き込んだデータ量より多くのフラッシュへの書き込みが発生します。この比率をWAF(Write Amplification Factor)と呼びます。

WAF = フラッシュへの実際の書き込み量 / ホストが書き込んだデータ量

理想: WAF = 1.0
実際のSSD: WAF = 1.05〜3.0 程度
状態が悪い場合: WAF = 10以上

WAFを小さくするには、書き込みパターンをシーケンシャルに近づける・適切なオーバープロビジョニング(予備領域の確保)が有効です。

動作原理

FTL(Flash Translation Layer)

FTLはウェアレベリングの核心となるソフトウェア層です。論理ブロックアドレス(LBA)と物理ブロックアドレス(PBA)のマッピングテーブルを管理し、書き込み時に最適な物理ブロックを選択します。

ホスト(OS)
    │ LBA(論理アドレス)で読み書き

  FTL(Flash Translation Layer)
    │ LBA → PBA マッピング変換
    │ ウェアレベリングアルゴリズム
    │ Bad Block管理
    │ ガベージコレクション

  物理NANDフラッシュ
    (実際のPBAでアクセス)

ガベージコレクション(GC)

フラッシュは上書きができないため、更新時は「無効化」→「新ブロックに書き込み」→「空きが少なくなったらGCで整理」というサイクルになります。

GCの流れ:
1. 有効データが少なくなったブロック(被GCブロック)を選択
2. 被GCブロック内の有効データを他のフリーブロックにコピー
3. 被GCブロックを消去(これがフリーブロックになる)
4. マッピングテーブルを更新

注意: GCにより追加の書き込み・消去が発生 → WAFが増加

UBI(Unsorted Block Images)

LinuxのUBIはRaw NANDに対してウェアレベリングを実施するソフトウェア層です:

UBIの役割:
- 物理消去ブロック(PEB)と論理消去ブロック(LEB)のマッピング
- 各PEBの消去回数(erase counter)を追跡
- 消去回数が少ないPEBを優先的に割り当て(動的ウェアレベリング)
- 消去回数差が閾値を超えたPEB間でデータを移動(静的ウェアレベリング)

LittleFS(組み込みマイコン向け)

LittleFSはマイコンのNORフラッシュ向けのファイルシステムで、ウェアレベリング・電源断耐性を持ちます。ログ構造(Log-Structured)ファイルシステムであり、上書きせずに新しいバージョンを別ブロックに書くことで書き込みを分散させます。

// ESP-IDF (ESP32) でのLittleFS使用例
#include "esp_littlefs.h"

esp_vfs_littlefs_conf_t conf = {
    .base_path = "/littlefs",
    .partition_label = "storage",
    .format_if_mount_failed = true,
};
esp_vfs_littlefs_register(&conf);

// 通常のファイル操作でウェアレベリングが自動実施される
FILE *f = fopen("/littlefs/config.txt", "w");
fprintf(f, "key=value\n");
fclose(f);

用途・ユースケース

eMMC・SSD内蔵コントローラ

eMMC・SSDではコントローラ内蔵のFTLが自動的にウェアレベリングを実施します。ユーザー(OS・アプリ)は意識する必要がありません。ただし、TRIM(Linux: blkdiscard)コマンドを活用することで、GCの効率を上げてWAFを下げられます。

# Linux でTRIMを実行(eMMC/SSDの効率化)
$ fstrim -v /
/: 1.5 GiB (1610612736 bytes) trimmed

# /etc/fstabでdiscardオプションを指定すると自動TRIM
UUID=xxxx /  ext4  defaults,noatime,discard  0  1

Raw NAND + UBI/UBIFS

組み込みLinuxでRaw NANDを直接使う場合、MTD→UBI→UBIFSのスタックでウェアレベリングを実現します。

# UBIをアタッチ
$ ubiattach /dev/ubi_ctrl -m 0  # MTDデバイス0にUBIをアタッチ
$ ubimkvol /dev/ubi0 -N rootfs -s 500MiB  # UBIボリューム作成
$ mount -t ubifs ubi0:rootfs /mnt/rootfs  # UBIFSとしてマウント

マイコンの設定値保存(NVS: Non-Volatile Storage)

ESP-IDFのNVS(Non-Volatile Storage)は、ESP32のNORフラッシュにウェアレベリング付きでキー・バリュー形式のデータを保存します。複数のページをローテーションすることで書き込みを分散させます。

// ESP-IDF NVS 使用例
#include "nvs_flash.h"
#include "nvs.h"

nvs_flash_init();   // NVS初期化(内部でウェアレベリング管理)

nvs_handle_t handle;
nvs_open("storage", NVS_READWRITE, &handle);
nvs_set_i32(handle, "boot_count", 42);
nvs_commit(handle);
nvs_close(handle);

Zephyr OSのNVS

Zephyr RTOSにはFlashベースのNVS(Non-Volatile Storage)システムが含まれており、フラッシュメモリ上にウェアレベリング付きでデータを保存できます。

実装・開発のポイント

オーバープロビジョニング(OP)

フラッシュの公称容量の一部(10〜28%程度)を予備領域として確保し、ウェアレベリング・GC・Bad Block置換に使います。ユーザーからは見えませんが、WAFの低減・パフォーマンス安定化に寄与します。

例: 128GB SSDの実際のNAND容量は128GB × 1.28 = 約164GB
    → 28%をOPとして確保

書き込みパターンの最適化

アプリケーション側でも書き込みパターンを工夫することでWAFを下げられます:

// 悪い例: 頻繁に小さなデータを書き込む
for (int i = 0; i < 1000; i++) {
    write_config_value(key, value);  // 毎回書き込み
}

// 良い例: バッファして一括書き込み
accumulate_changes(&buffer);
if (buffer.dirty) {
    write_config_batch(&buffer);    // まとめて書き込み
    buffer.dirty = false;
}

書き換え回数のモニタリング

eMMCはExtended CSD(拡張CSD)レジスタでデバイスの寿命情報を公開しています:

# mmc-utils でeMMC寿命確認
$ mmc extcsd read /dev/mmcblk0 | grep -E "DEVICE_LIFE_TIME|PRE_EOL"
PRE_EOL_INFO [267]: 0x01
  # 0x01: Normal
  # 0x02: Warning(容量の80%消耗)
  # 0x03: Urgent(容量の90%消耗)
DEVICE_LIFE_TIME_EST_TYP_A [268]: 0x02  # 10-20%消耗
DEVICE_LIFE_TIME_EST_TYP_B [269]: 0x01  # 0-10%消耗

電源断安全性の確保

ウェアレベリング実施中(データ移動中)に電源断が発生しても、データが失われないように冪等性(idempotency)を保つ設計が必要です。UBI・LittleFS・ZephyrのNVSはこの点を考慮した設計になっています。

他技術との比較

ウェアレベリング vs RAID

RAID(Redundant Array of Independent Disks)はストレージの冗長化でデータ保護を行い、ウェアレベリングは寿命を延ばす技術です。目的が異なりますが、産業用フラッシュストレージではウェアレベリング+RAID的な冗長構成を組み合わせることがあります。

ソフトウェアウェアレベリング vs ハードウェアウェアレベリング

ハードウェアウェアレベリング(eMMC・SSD内蔵コントローラ)はホストから透過的に動作し、ソフトウェアの実装不要です。ソフトウェアウェアレベリング(UBI・LittleFS等)はRaw NANDやNOR Flashに対して適用でき、アルゴリズムの細かい制御が可能です。コスト・実装工数の観点からは、できるだけハードウェアウェアレベリング済みのeMMCを使うことが推奨されます。

関連用語

参考リンク