概要
本稿では、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
をプロットした結果を下記に示す。
fioによる書き込みを 10,000回したが、いずれもスループットは 18MB/s が得られた。 さらに、カーネルからエラーメッセージや警告が出力されていないことから、SDメモリカードは正常に動作していると判断した。
また、項目write_kb
を合算した結果 (アプリケーションから見た総書き込み量)、11,205,597,184 KB (約10TB) であった。
仮に、新品のSDメモリカードが全領域で均一化できたとして、約700回に抑えることができる *2。TLC の書き込み上限を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
をプロットした結果を下記に示す。
fioによる書き込みを 計 100,000回したが、カーネルからエラーメッセージや警告が出力されなかった。
スループットは34MB/s、8MB/s、4MB/s 近傍という結果となった。 3つの近傍が出たのは fio による書き込みが数秒で終わるほど短時間であったため、正常な計測できていない可能性も考えられるが、それについては回数と傾向によって判断する。 スループットの傾向としては、おおよそ変化はないように見える。
これらのスループットの傾向やカーネルメッセージから、SDメモリカードは正常に動作していると判断した。
この実験では、前の実験とは異なり ダイナミックウェアレベリングが有効には動作できない状況下であったにも関わらず、平滑化されているように見える。 実験の合間に スタティックウェアレベリングのような何かが動作しているのではないかとも考えられる。
変更履歴
- 2024/03/05: 記事公開
- 2024/03/29: 実験2 を追加