Test : une alternative à la NVMe, la clé USB Rasberry Flash Drive

Bonjour à tous,

J’ai toujours rêvé d’utiliser un disque dur SSD au format d’une clé USB, et c’est justement ce que propose la Raspberry foundation depuis peu :

https://www.raspberrypi.com/products/flash-drive/

Les cartes micro-SD ont un gros défaut : elles n’ont pas de contrôleur mémoire réallouant les secteurs défectueux. Souvent quand le système écrit sur une micro-SD, il écrit dans les mêmes zones mémoires menant à une usure prématurée. Tout cela n’arrive pas (ou plus lentement) avec un SSD dont le contrôleur mémoire gère le vieillissement et la répartition des secteurs.

Il y a quelques mois, j’ai acheté trois USB Raspberry Pi Flash drive de 128G, puis j’en ai racheté une il y a quelques jours, chez ce fournisseur bien connu :

Les caractéristiques de la clé USB Raspberry :

  • 128GB ou 256GB
  • Compatible USB 3.0 et USB 2.0.
  • Support UASP support (SCSI protocol over USB)
  • Rapports Smartcrl
  • Support Trim (nécessaire une configuration udev)
  • Vitesse d’écriture séquentielle : 75MB/s
  • Vitesse de lecture séquentielle : 150MB/s
  • Boîtier aluminium

La durée de vie n’est pas spécifiée, mais on doit s’attendre à une durée de vie bien supérieure à celle d’un micro-SD, proche d’un SSD. Mes premiers tests et retours sont excellents :

  1. Interrogation Smart

J’ai utilisé la commande :
sudo /sbin/smartctl -d sat,12 -x /dev/sdb

Le contrôleur communique sur 12bit et non pas 16bit, ce qui explique la commande non-standard. J’ai configuré smart pour m’alerter en cas de vieillissement de la clé USB.

  1. Tests

J’ai utilisé les commandes :

# 1. SLC cache — ~10 min
sudo fio --name=precond --filename=/dev/sdb --rw=write \
--bs=128k --iodepth=32 --ioengine=libaio --size=100% --numjobs=1


# 2. Sequential read
sudo fio --name=read --filename=/dev/sdb --rw=read \
--bs=1M --iodepth=32 --ioengine=libaio \
--size=100% --runtime=30 --time_based


# 3. Sequential write
sudo fio --name=write --filename=/dev/sdb --rw=write \
--bs=1M --iodepth=32 --ioengine=libaio \
--size=100% --runtime=30 --time_based

precond: (g=0): rw=write, bs=(R) 128KiB-128KiB, (W) 128KiB-128KiB, (T) 128KiB-128KiB, ioengine=libaio, iodepth=32
fio-3.41
Starting 1 process
Jobs: 1 (f=1): [W(1)][100.0%][w=74.6MiB/s][w=596 IOPS][eta 00m:00s]
precond: (groupid=0, jobs=1): err= 0: pid=15507: Wed Mar 11 18:25:24 2026
write: IOPS=665, BW=83.2MiB/s (87.2MB/s)(120GiB/1471475msec); 0 zone resets
slat (usec): min=21, max=23671, avg=1494.18, stdev=4197.70
clat (usec): min=26, max=83042, avg=46578.21, stdev=11301.87
lat (usec): min=864, max=83165, avg=48072.39, stdev=11221.54
clat percentiles (usec):
|  1.00th=[  881],  5.00th=[28705], 10.00th=[32900], 20.00th=[40109],
| 30.00th=[43779], 40.00th=[46924], 50.00th=[47973], 60.00th=[51643],
| 70.00th=[52167], 80.00th=[55837], 90.00th=[59507], 95.00th=[60031],
| 99.00th=[66847], 99.50th=[67634], 99.90th=[70779], 99.95th=[71828],
| 99.99th=[71828]
bw (  KiB/s): min=62976, max=3696384, per=100.00%, avg=85304.24, stdev=69498.67, samples=2942
iops        : min=  492, max=28878, avg=666.25, stdev=542.96, samples=2942
lat (usec)   : 50=0.01%, 1000=1.39%
lat (msec)   : 2=0.12%, 4=0.60%, 20=1.14%, 50=54.54%, 100=42.22%
cpu          : usr=0.90%, sys=6.66%, ctx=104636, majf=0, minf=12
IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.1%, 32=100.0%, >=64=0.0%
submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.1%, 64=0.0%, >=64=0.0%
issued rwts: total=0,979456,0,0 short=0,0,0,0 dropped=0,0,0,0
latency   : target=0, window=0, percentile=100.00%, depth=32


Run status group 0 (all jobs):
WRITE: bw=83.2MiB/s (87.2MB/s), 83.2MiB/s-83.2MiB/s (87.2MB/s-87.2MB/s), io=120GiB (128GB), run=1471475-1471475msec


Disk stats (read/write):
sdb: ios=0/240794, sectors=0/246573056, merge=0/30581219, ticks=0/4397895, in_queue=4397895, util=100.00%
[sudo] Mot de passe de mario :
read: (g=0): rw=read, bs=(R) 1024KiB-1024KiB, (W) 1024KiB-1024KiB, (T) 1024KiB-1024KiB, ioengine=libaio, iodepth=32
fio-3.41
Starting 1 process
Jobs: 1 (f=1): [R(1)][100.0%][r=384MiB/s][r=384 IOPS][eta 00m:00s]
read: (groupid=0, jobs=1): err= 0: pid=20368: Wed Mar 11 18:26:30 2026
read: IOPS=297, BW=297MiB/s (311MB/s)(8948MiB/30123msec)
slat (usec): min=119, max=421419, avg=3268.65, stdev=33211.47
clat (usec): min=29, max=433188, avg=100482.71, stdev=161002.73
lat (msec): min=4, max=464, avg=103.75, stdev=162.75
clat percentiles (msec):
|  1.00th=[    5],  5.00th=[    5], 10.00th=[    5], 20.00th=[    6],
| 30.00th=[    7], 40.00th=[   10], 50.00th=[   12], 60.00th=[   13],
| 70.00th=[   13], 80.00th=[  355], 90.00th=[  397], 95.00th=[  405],
| 99.00th=[  422], 99.50th=[  426], 99.90th=[  430], 99.95th=[  435],
| 99.99th=[  435]
bw (  KiB/s): min=43008, max=524288, per=100.00%, avg=314779.14, stdev=116002.48, samples=58
iops        : min=   42, max=  512, avg=307.36, stdev=113.26, samples=58
lat (usec)   : 50=0.01%
lat (msec)   : 10=42.74%, 20=32.43%, 500=24.82%
cpu          : usr=0.25%, sys=16.41%, ctx=17689, majf=0, minf=537
IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.2%, 32=99.7%, >=64=0.0%
submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.1%, 64=0.0%, >=64=0.0%
issued rwts: total=8948,0,0,0 short=0,0,0,0 dropped=0,0,0,0
latency   : target=0, window=0, percentile=100.00%, depth=32


Run status group 0 (all jobs):
READ: bw=297MiB/s (311MB/s), 297MiB/s-297MiB/s (311MB/s-311MB/s), io=8948MiB (9383MB), run=30123-30123msec


Disk stats (read/write):
sdb: ios=18214/0, sectors=18644896/0, merge=0/0, ticks=315536/0, in_queue=315536, util=90.06%
write: (g=0): rw=write, bs=(R) 1024KiB-1024KiB, (W) 1024KiB-1024KiB, (T) 1024KiB-1024KiB, ioengine=libaio, iodepth=32
fio-3.41
Starting 1 process
Jobs: 1 (f=1): [W(1)][100.0%][w=70.1MiB/s][w=70 IOPS][eta 00m:00s]
write: (groupid=0, jobs=1): err= 0: pid=20387: Wed Mar 11 18:27:01 2026
write: IOPS=202, BW=202MiB/s (212MB/s)(6068MiB/30007msec); 0 zone resets
slat (usec): min=184, max=27488, avg=4926.81, stdev=6879.01
clat (usec): min=28, max=464141, avg=153107.56, stdev=134413.92
lat (msec): min=6, max=480, avg=158.03, stdev=138.63
clat percentiles (msec):
|  1.00th=[    7],  5.00th=[    7], 10.00th=[    7], 20.00th=[    7],
| 30.00th=[   53], 40.00th=[   75], 50.00th=[  122], 60.00th=[  188],
| 70.00th=[  241], 80.00th=[  275], 90.00th=[  372], 95.00th=[  376],
| 99.00th=[  435], 99.50th=[  456], 99.90th=[  460], 99.95th=[  464],
| 99.99th=[  464]
bw (  KiB/s): min=69493, max=3641344, per=99.99%, avg=207043.10, stdev=461452.32, samples=60
iops        : min=   67, max= 3556, avg=201.92, stdev=450.70, samples=60
lat (usec)   : 50=0.02%
lat (msec)   : 10=29.04%, 20=0.08%, 50=0.77%, 100=18.44%, 250=24.23%
lat (msec)   : 500=27.42%
cpu          : usr=1.15%, sys=11.60%, ctx=1913, majf=0, minf=8
IO depths    : 1=0.1%, 2=0.1%, 4=0.1%, 8=0.1%, 16=0.3%, 32=99.5%, >=64=0.0%
submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.1%, 64=0.0%, >=64=0.0%
issued rwts: total=0,6068,0,0 short=0,0,0,0 dropped=0,0,0,0
latency   : target=0, window=0, percentile=100.00%, depth=32


Run status group 0 (all jobs):
WRITE: bw=202MiB/s (212MB/s), 202MiB/s-202MiB/s (212MB/s-212MB/s), io=6068MiB (6363MB), run=30007-30007msec


Disk stats (read/write):
sdb: ios=65/7641, sectors=2032/7824384, merge=0/970661, ticks=73/88192, in_queue=88265, util=99.02%

Verdict :
Sequential read: 311 MB/s
Sequential write: 212 MB
Read latency: 355ms
Write latency: 275ms

A noter que la clé chauffe assez facilement lorsqu’elle est très sollicitée, comme durant le test de performance. En règle générale, elle reste tiède. Comme toute clé USB, il faut veiller à ne pas l’éjecter durant le fonctionnement du système, surtout si un trim est en cours.

Si l’on considère que la Raspberry Flash Drive est un disque SSD monté sur une interface USB3, on est quand même en dessous des performances d’un SSD ou d’une NVMe : en débit et en durée de vie (c’est lié au contrôleur qui est de meilleure qualité sur un SSD/NVMe).

Pour simplifier mon avis, en terme de fiabilité et de débit lecture/écriture :
clé USB Raspberry Flash Drive < Disque dur SSD USB3 < NVMe
mais en terme de rapport qualité-prix c’est la clé USB qui l’emporte.

Aussi, j’ai décidé de les utiliser sur mes projets Raspberry comme alternative à la NVMe et aux CF. Pour rappel, les Rpi 3, 4 et 5 peuvent booter sur USB.

Dernier point.: j’ai acheté les clés USB avec mon argent et ce n’est pas de la publicité.

Et voici quelques photos pour avoir une meilleure idée du produit :


USB Flash Drive sur une RPi4 pour projet RTKbase


USB Flash Drive sur une RPi5 destinée à une imprimante Voron

Happy Hacking!
Cordialement,

Salut,

Je réfléchis à sécuriser mon installation HA sur mon PI5, encore sur SD à ce jour. J’hésite entre le nvme et cette clé grace à ton article. Dans les projets que tu mentionnes, tu as également une instance HA ? Ça te paraît adapté ? J’utilise actuellement 20go sur la sd donc niveau stockage 126 suffit amplement.

La micro-SD est vraiment le point faible des RPi. Pour être honnête, je les ai presque toutes éliminées, leur préférants NVMe et clés USB Raspberry :

  • 3 x RPi5-CM avec NVMe (HA)
  • 1 x Rpi4 avec USB Raspberry Flash Drive
  • 2 x RPi5 dont une avec USB Raspberry Flash Drive
  • 2 x RPi3B avec USB Raspberry Flash Drive
  • 1 x RPi1B avec CF

Cette clé est toute récente, avec peu de retour. Les RPi 3B seront installées en extérieur dans des boîtiers étanches, été comme hiver, pour un projet RTK. J’en aurai une autre sous une imprimante 3D Voron qui chauffe bien.

On saura rapidement si elles tiennent le coup.

Tout indique que c’est de la qualité. La fondation Raspberry a l’habitude de fournir des produits en utilisant des composants de qualité. C’est pour cela que les RPi tombent rarement en panne. La qualité est excellente.

C’est surtout le rapport qualité-prix qui est excellent. Cependant un NVMe est certainement plus durable en raison de son meilleur contrôleur.