LeavaTailの日記

LeavaTailの日記

Linuxエンジニアを目指した技術者の備忘録

SDメモリカードで摩耗平滑化の恩恵を体感してみる

概要

本稿では、Raspberry Pi 4 上で KIOXIA社の16GB SDメモリカードに書き込みを続けたときの状態を確認した。 先頭から 約1GB の書き込みを 10,000回繰り返してみたが、メモリカードは故障の兆しが見られなかった。

背景

SDメモリカードは、フラッシュメモリ技術を利用してデータを保存する記憶装置である。 フラッシュメモリはデータを記録する最小単位 メモリセルが複数個から構成されており、絶縁体に囲まれたに浮遊ゲートに電子を出し入れすることで情報を記憶する。

フラッシュメモリの基本動作

近年では、大容量化を実現するため一つのメモリセルに複数のデータを記憶する仕組みがある。 一つのメモリセルに1bitデータを記憶する仕組み Single Level Cell(SLC)、2bitデータを記憶する仕組み Multi Level Cell(MLC)、3bitデータを記憶する仕組み Triple Level Cell(TLC) などが存在する。

1つのメモリセルに多くのデータを記憶することでデータ量あたりのコストを下げることができるが、性能や耐久性といった課題がある。 フラッシュメモリでは、データの記憶(や消去)を繰り替えすことで絶縁体が劣化し、電子を正常に取り扱えなくなる恐れがある。 SLCでは100,000回の書き込みに耐えられるといわれているが、MLCでは10,000回程度、TLCでは3,000回程度と言われている。

各メーカーは、大容量化・高耐久性・省コスト化など様々な工夫によって他のメーカーとの差別化を目指している。 その中でもウェアレベリングは、書き込みが一か所に集中しないように均等に分散するように制御する一般的な仕組みである。

ウェアレベリング技術のイメージ

ウェアレベリングをサポートしていない場合、同じデータを繰り返し更新していると、一か所に書き込みが集中してしまう。 ウェアレベリングによって、書き込み箇所を平滑化することによって長寿命化を目指す。

このウェアレベリング技術には、2種類 ダイナミックウェアレベリングスタティックウェアレベリングに大別できる。

ダイナミックウェアレベリングのイメージ

ダイナミックウェアレベリングは、 データが書かれていない領域のみに対して、摩耗していないブロックを書き込みをウェアレベリング対象先する。 例えば、書き換えが多発しているブロック#9に対して更新したとき、未使用で書き換えが少ない#16に記録することで書き込み箇所を平滑化している。

スタティックウェアレベリングのイメージ

一方で、スタティックウェアレベリングでは、ストレージが待機状態となっているときなどに実施される。 書き込みが発生しにくいと判断されたブロックを移動させることで、摩耗しているブロックへの摩耗を最小限にすることができる。 例えば、ブロック#13, #14, #15, #16は書き換えがほぼ発生しなかったデータであるとき、摩耗しかけているブロック#9, #10, #11, #12に移動させる。

目的

SDメモリカードに書き込みを続けた場合の挙動を確認する。

実行環境

Raspberry Pi 4 Model B (Raspberry Pi 4) は USBフラッシュドライブ経由でRaspberry Pi OSを起動させる。 測定用のSDカードは Raspberry Pi 4の microSD card slot に挿入する。

計測環境の概要

ここで使用するRaspberry Pi 4のスペックについて、必要な情報だけ抜粋したものを下記に示す。

項目 Raspberry Pi 4
CPU Cortex-A72 (ARM v8) 1.5GHz
メモリ 4GB LPDDR4-3200
OS Raspberry Pi OS (Dec 5th 2023)
ケース 陽極酸化アルミニウム製ヒートシンクケース
ストレージ KTHN-MW016G

ここで、実験に使用するストレージ (SDメモリカード) は新品未開封のものを使用する。

また、各実験の前に、このストレージで発行できる discard 処理を発行してある。 *1

pi@raspberrypi:~$ sudo blkdiscard -z /dev/mmcblk0
pi@raspberrypi:~$ sudo blkdiscard /dev/mmcblk0

実験

本記事では、2つの条件下でSDメモリカードに負荷をかけ(Flexible I/O Tester (fio)による書き込み)、その時の挙動を確認する。

未使用領域が十分に確保できる状態での書き込み

書き込みは先頭からシーケンシャルで1MB単位に実施していき、60s を 1 Iterationとする。 このとき、Rasperry Pi OS による影響を抑えるために、ダイレクトI/O や none I/O scheduler を使用する。

ただし、SDメモリカードの仕様が公式から明記されていないため、価格やスペックなどから TLC と仮定し、iterationの回数を 10,000 とした。

// 1:
    #!/bin/bash

    CNT=${1:-10000}
        
    for i in `seq ${CNT}`; do
            sync; sync; sync;
            echo 3 > /proc/sys/vm/drop_caches
    
            fio --name=test \
                --readwrite=write \
                --ioengine=libaio --iodepth=4 \
                --bs=1M --size=16G \
                --filename=/dev/mmcblk0 \
                --runtime=60 --time_based \
                --invalidate=1 --direct=1 \
                --ioscheduler=none \
                --output /tmp/fio.log --output-format=terse
    done

fio の実行結果 (/tmp/fio.log) から 項目write_bandwidthをプロットした結果を下記に示す。

スループット遷移 (実験1)

fioによる書き込みを 10,000回したが、いずれもスループットは 18MB/s が得られた。 さらに、カーネルからエラーメッセージや警告が出力されていないことから、SDメモリカードは正常に動作していると判断した。

また、項目write_kbを合算した結果 (アプリケーションから見た総書き込み量)、11,205,597,184 KB (約10TB) であった。 仮に、新品のSDメモリカードが全領域で均一化できたとして、約700回に抑えることができる *2TLC の書き込み上限を3,000回としても、この結果は妥当であると考えられる。

つまり、ユーザプログラムからは局所的な書き込みをしているが、ウェアレベリングによって書き込み箇所を平滑化されているように見受けられた。

未使用領域が十分に確保できない状態での書き込み

SDカードコントローラによって未使用領域を扱われないよう、領域を 0xff で埋めた状態で改めて局所的な書き込みを続ける。

root@raspberrypi:/home/pi# tr '\0' '\377' < /dev/zero > /dev/mmcblk0

書き込みは局所化させるために、先頭から4MBを書き込む。これを 1 Iterationとする。 このとき、Rasperry Pi OS による影響を抑えるために、ダイレクトI/O や none I/O scheduler を使用する。

// 1:
    #!/bin/bash

    CNT=${1:-1000}
        
    for i in `seq ${CNT}`; do
            sync; sync; sync;
            echo 3 > /proc/sys/vm/drop_caches
            blkdiscard -z -l 4194304 /dev/mmcblk0

            fio --name=test \
                --readwrite=write \
                --ioengine=sync \
                --bs=4M --size=4M \
                --loops=100 \
                --filename=/dev/mmcblk0 \
                --invalidate=1 --direct=1 \
                --fsync_on_close=1 \
                --ioscheduler=none \
                --output /tmp/fio.log --output-format=terse
    done

fio の実行結果 (/tmp/fio.log) から 項目write_bandwidthをプロットした結果を下記に示す。

スループット遷移 (実験2)

fioによる書き込みを 計 100,000回したが、カーネルからエラーメッセージや警告が出力されなかった。

スループットは34MB/s、8MB/s、4MB/s 近傍という結果となった。 3つの近傍が出たのは fio による書き込みが数秒で終わるほど短時間であったため、正常な計測できていない可能性も考えられるが、それについては回数と傾向によって判断する。 スループットの傾向としては、おおよそ変化はないように見える。

これらのスループットの傾向やカーネルメッセージから、SDメモリカードは正常に動作していると判断した。

この実験では、前の実験とは異なり ダイナミックウェアレベリングが有効には動作できない状況下であったにも関わらず、平滑化されているように見える。 実験の合間に スタティックウェアレベリングのような何かが動作しているのではないかとも考えられる。

変更履歴

  • 2024/03/05: 記事公開
  • 2024/03/29: 実験2 を追加

参考文献

*1:今回のSDメモリカードでは secure eraseは未サポートであるため実行していない

*2:ここでは 愚直に14.4GBで除算しているため値は正確ではない