ストレージシステム
データの永続化はコンピューティングの根幹であり、ストレージ技術の進化がデジタル社会を支えている。
この章で学ぶこと
前提知識
1. HDD(ハードディスクドライブ)
1.1 内部構造
HDD の内部構造:┌───────────────────┐ プラッタ (磁気円盤) ┌─────────────┐ ───────── / トラック \ | ┌──────┐ | | スピンドル | | └──────┘ | \ セクタ / ───────── └─────────────┘ └───────────────────┘ ┌───────────────────────┐ アーム + ヘッド ←────────● ヘッド └───────────────────────┘
コンポーネント:
- プラッタ: 磁性体を塗布したアルミ/ガラス円盤(両面使用)
- スピンドル: プラッタを回転させるモーター(5400/7200/10000/15000 RPM)
- ヘッド: 磁気を読み書きする超小型電磁石(プラッタ表面から10nm浮上)
- アクチュエータアーム: ヘッドを目的のトラックに移動
1.2 アクセス時間の構成
HDDの読み取り時間 = シーク時間 + 回転待ち + 転送時間
シーク時間(Seek Time):
ヘッドを目的のトラックに移動する時間
平均: 3-10ms(フルストローク: 15-20ms)
回転待ち(Rotational Latency):
目的のセクタがヘッドの下に来るまで待つ時間
7200RPMの場合: 平均 4.17ms(半回転分)
計算: 60秒 / 7200回転 / 2 = 4.17ms
転送時間(Transfer Time):
データを実際に読み書きする時間
100-200 MB/s → 1MBの読み取りに5-10μs
典型的なランダム読み取り:
シーク(5ms) + 回転待ち(4ms) + 転送(0.01ms) ≈ 9ms
→ 1秒間に約110回のランダムI/O (110 IOPS)
1.3 HDDの詳細技術
プラッタの磁気記録方式:
■ 水平磁気記録(LMR: Longitudinal Magnetic Recording)
- 磁化方向: プラッタ面に水平
- 限界: 約100-200 Gbit/in²
- 2005年頃まで主流
■ 垂直磁気記録(PMR: Perpendicular Magnetic Recording)
- 磁化方向: プラッタ面に垂直
- 密度: 約500-1000 Gbit/in²
- 2005年以降の主流方式
■ シングル磁気記録(SMR: Shingled Magnetic Recording)
- トラックを瓦のように重ねて書く
- 密度: PMRの約25%向上
- 欠点: ランダム書き込みが極端に遅い(書き込み時に隣接トラックを再書き込み)
- 用途: アーカイブ、バックアップ用途
■ 熱アシスト磁気記録(HAMR: Heat Assisted Magnetic Recording)
- レーザーで加熱して磁化を容易にする
- 密度: 2000+ Gbit/in²
- Seagate が2024年に30TB HDDで実用化
■ マイクロ波アシスト磁気記録(MAMR: Microwave Assisted Magnetic Recording)
- マイクロ波で磁気共鳴を利用
- Western Digital が採用
- HAMR と競合する技術
HDDのキャッシュ構造:HDDファームウェア ┌─────────────────────────────────┐ DRAM キャッシュ(64-256MB) - 読み取りバッファ - 書き込みバッファ - 先読み(Read-Ahead)キャッシュ └─────────────────────────────────┘ ┌─────────────────────────────────┐ コマンドキューイング - NCQ(Native Command Queuing) - キュー深度: 最大32 - アクセス順序を最適化 └─────────────────────────────────┘
NCQの効果:
ランダム読み取り時、ヘッドの移動距離を最小化するよう
コマンドの実行順序を並べ替え
→ ランダムIOPSが約20-50%向上
1.4 HDDの障害と対策
HDDの典型的な障害パターン:
1. ヘッドクラッシュ
- ヘッドがプラッタ表面に接触
- 原因: 衝撃、振動、製造欠陥
- 結果: プラッタ表面の損傷、データ喪失
2. 不良セクタの増加
- 経年劣化で磁気記録が弱くなる
- SMART属性で監視可能
- Reallocated Sectors Count の増加は危険信号
3. スピンドルモーターの劣化
- ベアリングの摩耗
- 異音の発生、起動失敗
4. ファームウェア障害
- SA(Service Area)の破損
- アクセス不能になることがある
SMART(Self-Monitoring, Analysis and Reporting Technology):
重要なSMART属性:
│ ID │ 名称 │ 危険度 │
│─────│─────────────────────────│────────│
│ 5 │ Reallocated Sectors │ 高 │
│ 10 │ Spin Retry Count │ 中 │
│ 187 │ Reported Uncorrectable │ 高 │
│ 188 │ Command Timeout │ 中 │
│ 197 │ Current Pending Sectors │ 高 │
│ 198 │ Offline Uncorrectable │ 高 │
# Linux でSMART情報を確認
sudo smartctl -a /dev/sda
# SMART自己テストの実行
sudo smartctl -t short /dev/sda # 短時間テスト(約2分)
sudo smartctl -t long /dev/sda # 長時間テスト(数時間)
# SMART属性の表示
sudo smartctl -A /dev/sda
# macOS の場合
brew install smartmontools
sudo smartctl -a /dev/disk0
2. SSD(ソリッドステートドライブ)
2.1 NAND フラッシュの仕組み
SSD の内部構造:SSD コントローラ ┌──────┐ ┌──────┐ ┌──────┐ ┌───────┐ FTL ECC WL GC └──────┘ └──────┘ └──────┘ └───────┘ ┌──────────────────────────────────┐ NAND フラッシュチップ ┌────┐ ┌────┐ ┌────┐ ┌────┐ Die0 Die1 Die2 Die3 └────┘ └────┘ └────┘ └────┘ 各Dieの中: ┌─────────────────────────┐ Block 0 ┌─────┬─────┬─────┐ Page0 Page1 Page2 ... └─────┴─────┴─────┘ Block 1 ... └─────────────────────────┘ └──────────────────────────────────┘ ┌──────────────┐ DRAM キャッシュ (マッピングテーブル) └──────────────┘
FTL: Flash Translation Layer(論理→物理アドレス変換)
ECC: Error Correcting Code(エラー訂正)
WL: Wear Leveling(書き込み均等化)
GC: Garbage Collection(不要ブロックの回収)
2.2 NANDセルの種類と特性
NANDセルタイプの比較:
SLC (Single Level Cell): 1ビット/セル読み取り: 25μs 書き込み: 200μs 消去回数: 10万回
MLC (Multi Level Cell): 2ビット/セル読み取り: 50μs 書き込み: 600μs 消去回数: 3千回
TLC (Triple Level Cell): 3ビット/セル読み取り: 75μs 書き込み: 1ms 消去回数: 1千回
QLC (Quad Level Cell): 4ビット/セル読み取り: 100μs 書き込み: 2ms 消去回数: 300回
PLC (Penta Level Cell): 5ビット/セル読み取り: 150μs 書き込み: 3ms+ 消去回数: 100回
トレードオフ:
容量・コスト効率 SLC < MLC < TLC < QLC < PLC
速度・耐久性 SLC > MLC > TLC > QLC > PLC
→ ビット数を増やすほど安価で大容量だが、
電圧マージンが狭くなりエラー率と遅延が増加
2.3 SSD特有の制約と最適化
操作
可能な単位
速度
読み取り
ページ単位 (4-16KB)
〜25μs
書き込み
ページ単位 (4-16KB)
〜250μs
消去
ブロック単位 (256-512ページ)
〜2ms
重要 : SSDは「上書き」ができない。書き込み前に必ずブロック単位で消去が必要。
書き込み増幅(Write Amplification) : 1ページを更新するために、ブロック全体を読み→消去→書き戻す必要がある。
TRIM : OSがSSDに「このブロックはもう使わない」と通知し、GCの効率を向上させる。
SSDの内部最適化メカニズム:
■ FTL(Flash Translation Layer)
論理ブロックアドレス (LBA) → 物理ページアドレス (PPA) の変換OS NAND フラッシュ LBA: 100 ──FTL──→ Die2, Block5, Page 42
書き込み時:
1. 新しい空きページに書き込み
2. FTLテーブルを更新(LBA→新PPA)
3. 古いページを無効化マーク
→ 「上書き」ではなく「追記」方式
■ ガベージコレクション(GC)Block A(GC対象) ┌────┬────┬────┬────┐ 有効 無効 有効 無効 └────┴────┴────┴────┘
↓ GC実行
1. 有効ページを別ブロックにコピー
2. Block A をまるごと消去
3. 空きブロックとして再利用
GCのタイミング:
- バックグラウンドGC: アイドル時に実行
- フォアグラウンドGC: 空きブロック不足時(性能低下の原因)
■ ウェアレベリング(Wear Leveling)
全ブロックの消去回数を均等化
- 動的WL: 書き込み先を分散
- 静的WL: 読み取り専用データも定期的に移動
→ SSD寿命を最大化
■ オーバープロビジョニング(OP)
ユーザーに見せない予備領域(全容量の7-28%)
- GC用の空きブロック確保
- 不良ブロックの代替
- パフォーマンス安定化
例: 512GB SSD = 実際のNAND容量 560GB程度
48GB(約9%) がOP領域
2.4 SSD vs HDD
項目
HDD
SATA SSD
NVMe SSD
順次読み取り
100-200 MB/s
500 MB/s
3,500-14,000 MB/s
順次書き込み
100-200 MB/s
450 MB/s
3,000-12,000 MB/s
ランダムIOPS
100-200
50,000-100,000
500,000-2,000,000
レイテンシ
3-10 ms
50-100 μs
10-20 μs
消費電力
6-8W
2-3W
5-8W
寿命
〜5年(機械摩耗)
3-5年(書込制限)
3-5年(書込制限)
耐衝撃性
低い(ヘッドクラッシュ)
高い
高い
価格/TB
〜$15
〜$50
〜$60-100
2.5 SSD寿命の計算と管理
SSD寿命の計算方法:
TBW(Total Bytes Written):
SSDの寿命を書き込み総量で表す指標
例: Samsung 990 Pro 2TB
TBW = 1,200 TB
1日の書き込み量が50GBの場合:
寿命 = 1,200TB / (50GB × 365日) = 約65年
→ 一般用途では寿命を気にする必要はほぼない
DWPD(Drive Writes Per Day):
保証期間中に1日あたり何回全容量を書き込めるか
例: エンタープライズSSD 3.84TB, DWPD=3, 保証5年
1日の書き込み許容量 = 3.84TB × 3 = 11.52TB/日
TBW = 11.52TB × 365 × 5 = 21,024 TB
SSD寿命監視コマンド:
# Linux: NVMe SSD の寿命情報確認
sudo nvme smart-log /dev/nvme0n1
# 出力例:
# percentage_used : 3% ← 寿命消費率
# data_units_written : 12345 ← 書き込み量(512B単位 × 1000)
# data_units_read : 67890
# Linux: SATA SSD のSMART情報
sudo smartctl -a /dev/sda | grep -E "Wear_Leveling|Total_LBAs"
# macOS: diskutil でSSD情報確認
diskutil info disk0 | grep -i "smart\|wear\|life"
3. NVMe/PCIe
3.1 プロトコルスタック
ストレージI/Oプロトコルの進化:
SATA (2003):
CPU → AHCI → SATA → SSD
■ 1つのコマンドキュー、キュー深度32
■ 最大帯域: 600 MB/s (SATA III)
■ レガシーなHDD向けプロトコルの延長
NVMe over PCIe (2011):
CPU → NVMe → PCIe → SSD
■ 65,535個のコマンドキュー、各キュー深度65,536
■ 最大帯域: 32 GB/s (PCIe 5.0 x4)
■ SSD向けに一から設計されたプロトコル
■ CPU使用率も低い(割り込み削減)
比較:
│ 項目 │ AHCI/SATA │ NVMe/PCIe │
│───────────────│────────────│──────────────│
│ キュー数 │ 1 │ 65,535 │
│ キュー深度 │ 32 │ 65,536 │
│ 帯域幅 │ 600 MB/s │ 32+ GB/s │
│ レイテンシ │ 〜100 μs │ 〜10 μs │
│ CPU効率 │ 低い │ 高い │
3.2 NVMe の詳細アーキテクチャ
NVMe Submission/Completion Queue:ホスト(CPU側) Admin Queue: ┌─────────────────────────────┐ SQ (Submission Queue) → デバイス管理コマンド CQ (Completion Queue) → 完了通知 └─────────────────────────────┘ I/O Queue Pair 1: ┌─────────────────────────────┐ SQ1 ← CPU Core 0 専用 CQ1 ← 割り込みベクタ 1 └─────────────────────────────┘ I/O Queue Pair 2: ┌─────────────────────────────┐ SQ2 ← CPU Core 1 専用 CQ2 ← 割り込みベクタ 2 └─────────────────────────────┘ ...(CPUコアごとにキューペアを作成可能)
NVMe のI/O処理フロー:
1. アプリがread()を呼ぶ
2. ドライバがSQにコマンドを投入
3. Doorbell レジスタに書き込み(SSDに通知)
4. SSDがコマンドを実行
5. CQに完了エントリを書き込み
6. MSI-X割り込みでCPUに通知
7. ドライバが完了を処理
→ ロック不要(各CPUコアが自分のキューを使用)
→ 高並列度を実現
3.3 NVMe-oF(NVMe over Fabrics)
NVMe over Fabrics:
ローカルNVMe:
アプリ → NVMe → PCIe → ローカルSSD
レイテンシ: 〜10μs
NVMe over Fabrics:
アプリ → NVMe → ネットワーク → リモートSSD
レイテンシ: 〜30-100μs
サポートされるトランスポート:
│ トランスポート │ レイテンシ │ 帯域幅 │ 用途 │
│────────────────│─────────────│────────────│───────────────│
│ RDMA/RoCE v2 │ 30-50 μs │ 100+ Gbps │ データセンター │
│ TCP │ 50-100 μs │ 25+ Gbps │ 汎用 │
│ FC (Fibre Ch.) │ 30-50 μs │ 32 Gbps │ SAN │
応用: ストレージの disaggregation(分離)
→ コンピュートノードとストレージノードを別々にスケール
→ クラウドの基盤技術
4. ファイルシステム
4.1 主要ファイルシステム比較
FS
OS
最大ファイル
最大ボリューム
ジャーナリング
COW
特徴
ext4
Linux
16TB
1EB
あり
なし
Linux標準、安定
XFS
Linux
8EB
8EB
あり
なし
大規模ファイル向け
Btrfs
Linux
16EB
16EB
なし
あり
スナップショット、圧縮
ZFS
FreeBSD/Linux
16EB
256ZB
なし
あり
データ整合性最強
NTFS
Windows
16EB
256TB
あり
なし
Windows標準
APFS
macOS/iOS
8EB
—
なし
あり
Apple専用、暗号化
F2FS
Android
3.94TB
16TB
なし
なし
SSD/eMMC最適化
4.2 ジャーナリングの仕組み
ジャーナリング(ext4の場合):
通常の書き込み(ジャーナリングなし):
1. メタデータ更新
2. データ書き込み
→ 途中で電源断 → データ不整合(FSの破損)
ジャーナリング:
1. ジャーナル領域に「これから何をするか」を書く
2. 実際のメタデータ/データを更新
3. ジャーナルのトランザクションを「完了」にマーク
電源断が発生した場合:
→ 起動時にジャーナルを読み、未完了のトランザクションを
ロールバックまたはリプレイ
→ FSの一貫性が保証される1.記録 ───→ 2.実行 ───→ 3.完了 Journal Data Commit
↑ │
└───── 電源断時はここから再開 ─┘
ジャーナリングモードの比較(ext4):
■ journal(フルジャーナル)
- メタデータとデータの両方をジャーナル
- 安全性: 最高
- 性能: 最低(書き込み2倍)
- 用途: データベースサーバー
■ ordered(デフォルト)
- メタデータのみジャーナル
- データは先に書き込み、その後メタデータ
- 安全性: 高い
- 性能: 良好
- 用途: 一般的なサーバー
■ writeback
- メタデータのみジャーナル
- データとメタデータの順序保証なし
- 安全性: 低い(データ破損の可能性)
- 性能: 最高
- 用途: テンポラリデータ
4.3 Copy-on-Write(COW)
COW(Btrfs, ZFS, APFSの場合):
従来のFS:
データブロック → 直接上書き
→ 書き込み中の電源断でデータ破損
COW:
1. 新しいブロックにデータを書く
2. メタデータを新ブロックを指すように更新
3. 古いブロックを解放
→ 書き込み中の電源断でも古いデータが残る
利点:
- アトミックな書き込み(壊れない)
- スナップショットが O(1) で作成可能(メタデータのコピーのみ)
- 圧縮・重複排除が容易
欠点:
- フラグメンテーションが発生しやすい
- ランダム書き込みのオーバーヘッド
4.4 ZFS の詳細機能
ZFS の主要機能:
■ ストレージプール(zpool)ZFS Pool (zpool) ┌─────────────────────────────────┐ Dataset: /data Dataset: /data/mysql Dataset: /data/logs Zvol: /dev/zvol/pool/vm-disk └─────────────────────────────────┘ vdev: mirror-0 vdev: mirror-1 ┌──────┬──────┐ ┌──────┬──────┐ sda sdb sdc sdd └──────┴──────┘ └──────┴──────┘
■ データ整合性(チェックサム)
- 全ブロックにSHA-256チェックサム
- 読み取り時に自動検証
- サイレントデータ破損(bit rot)を検出・修復
■ スナップショット
- 作成: 瞬時(メタデータのポインタコピーのみ)
- 容量: 差分のみ消費
- ロールバック: 瞬時
■ 送受信(zfs send/recv)
- スナップショット間の差分を別プールに転送
- 増分バックアップに最適
- WAN経由のリモートレプリケーション
■ 圧縮
- LZ4(デフォルト): 高速、CPU負荷小
- ZSTD: 高圧縮率
- 透過的(アプリからは見えない)
■ 重複排除(dedup)
- 同じデータブロックを1つだけ保存
- メモリを大量消費(1TBあたり5GBのRAM)
- VMバックアップなどで効果的
# ZFS の基本操作
# プールの作成(ミラー構成)
sudo zpool create tank mirror /dev/sda /dev/sdb
# データセットの作成
sudo zfs create tank/data
sudo zfs create tank/data/mysql
# 圧縮の有効化
sudo zfs set compression=lz4 tank/data
# スナップショットの作成
sudo zfs snapshot tank/data/mysql@before-migration
# スナップショット一覧
sudo zfs list -t snapshot
# スナップショットからの復元
sudo zfs rollback tank/data/mysql@before-migration
# 増分送信(リモートバックアップ)
sudo zfs send -i @snap1 tank/data@snap2 | ssh remote zfs recv backup/data
# ディスク使用状況
sudo zpool status
sudo zfs list
5. RAID
5.1 RAIDレベル比較
RAID 0(ストライピング):性能: 読み書き2倍 冗長性: なし(1台死亡=全損)
RAID 1(ミラーリング):性能: 読み2倍、書き1倍 冗長性: 1台障害OK 容量: 50%
RAID 5(パリティ分散):Disk 0 Disk 1 Disk 2 B1 Bp B2 Cp C1 C2
性能: 読み(N-1)倍、書き遅い 冗長性: 1台障害OK 容量: (N-1)/N
RAID 6(二重パリティ):
RAID 5 + パリティ2つ → 2台同時障害OK
RAID 10(1+0: ミラー+ストライプ):Disk 0 Disk 1 Disk 2 Disk 3 A1 A1 A2 A2
ミラー対1 ミラー対2
性能: 読み4倍、書き2倍 冗長性: 各対1台OK 容量: 50%
5.2 RAID 選択ガイド
RAID
容量効率
読取性能
書込性能
耐障害性
用途
0
100%
最高
最高
なし
テンポラリ/キャッシュ
1
50%
良
普通
1台
OS、ブート
5
(N-1)/N
良
遅い
1台
ファイルサーバー
6
(N-2)/N
良
最遅
2台
大規模ストレージ
10
50%
最高
良
各対1台
DB、高パフォーマンス
5.3 RAID の詳細解説と計算
RAID 5 のパリティ計算:
パリティ = データ1 XOR データ2 XOR データ3 ...
例: 3ディスクのRAID 5
Disk 0: 10110011
Disk 1: 01101010
パリティ: 11011001 (= Disk0 XOR Disk1)
Disk 1 が故障した場合:
Disk 1 = Disk 0 XOR パリティ
= 10110011 XOR 11011001
= 01101010 ← 元のデータを復元!
RAID 5 書き込みペナルティ(Write Penalty):
1つのブロックの更新に必要な操作:
1. 古いデータを読む
2. 古いパリティを読む
3. 新しいパリティを計算(old_data XOR new_data XOR old_parity)
4. 新しいデータを書く
5. 新しいパリティを書く
→ 1回の論理書き込み = 2読み + 2書き = 4 I/O
RAID レベル別の書き込みペナルティ:
│ RAID │ ペナルティ │ 説明 │
│──────│────────────│─────────────────────────│
│ 0 │ 1 │ ストライプに直接書き込み │
│ 1 │ 2 │ ミラーに同時書き込み │
│ 5 │ 4 │ Read-Modify-Write │
│ 6 │ 6 │ 二重パリティ │
│ 10 │ 2 │ ミラーに同時書き込み │
RAID 性能計算の実例:
条件: 8台のSSD (各100K IOPS)、読み70%:書き30%
RAID 10:
読みIOPS = 8 × 100K × 0.7 = 560K IOPS
書きIOPS = (8/2) × 100K × 0.3 / 2 = 60K IOPS
合計 ≈ 620K IOPS
RAID 5:
読みIOPS = 7 × 100K × 0.7 = 490K IOPS
書きIOPS = 7 × 100K × 0.3 / 4 = 52.5K IOPS
合計 ≈ 542.5K IOPS
5.4 ソフトウェアRAID vs ハードウェアRAID
ハードウェアRAID:RAIDコントローラカード ┌──────────┐ ┌────────────┐ └──────────┘ └────────────┘ ┌──────────────────────────┐ └──────────────────────────┘
利点: CPUに負荷をかけない、BBUでキャッシュ保護
欠点: 高価、コントローラ自体が単一障害点
ソフトウェアRAID:
Linux mdadm:
- CPUでXOR計算(現代CPUでは十分高速)
- 無料、柔軟性が高い
- BBU不要(UPSで対応)
- 異なるコントローラのディスクを混在可能
ZFS RAIDZ:
- RAID-Z1 ≈ RAID 5(1パリティ)
- RAID-Z2 ≈ RAID 6(2パリティ)
- RAID-Z3(3パリティ、超大容量向け)
- コピーオンライトでRAID5の「書き込みホール」問題なし
# Linux mdadm でRAID構築
# RAID 1 の作成
sudo mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/sda1 /dev/sdb1
# RAID 5 の作成
sudo mdadm --create /dev/md1 --level=5 --raid-devices=3 /dev/sda1 /dev/sdb1 /dev/sdc1
# RAID の状態確認
cat /proc/mdstat
sudo mdadm --detail /dev/md0
# 障害ディスクの交換
sudo mdadm /dev/md0 --remove /dev/sdb1
sudo mdadm /dev/md0 --add /dev/sdd1
# リビルドの進捗確認
watch cat /proc/mdstat
6. I/Oスケジューラ
6.1 主要スケジューラ
スケジューラ
方式
適用
NOOP/None
FIFO(先入先出)
SSD(ハードウェアが最適化)
Deadline
デッドラインベース
DB、リアルタイム
CFQ
完全公平キューイング
デスクトップ(旧デフォルト)
BFQ
Budget Fair Queuing
デスクトップ(低レイテンシ)
mq-deadline
マルチキュー版
NVMe SSD
kyber
2レベルキュー
高性能NVMe
6.2 I/Oスケジューラの詳細と選択
各スケジューラの動作原理:
■ NOOP/None- 並べ替えなし、マージのみ
- SSDではハードウェアがスケジューリング
- NVMeにはこれで十分
■ mq-deadline読み取りキュー(デッドライン: 500ms) 書き込みキュー(デッドライン: 5s) → デッドラインが近い要求を優先
- 読み取り優先(レスポンス重視)
- デッドラインで飢餓状態を防止
- DBサーバーに最適
■ BFQ (Budget Fair Queuing)プロセスごとにI/O予算を割り当て → 対話型プロセスに高予算 → バックグラウンドプロセスに低予算
- デスクトップでスムーズな操作感
- 動画再生中のファイルコピーでカクつかない
■ kyber同期キュー(読み取り)→ 低レイテンシ 非同期キュー(書き込み)→ 高スループット → トークンベースでスロットリング
- 高性能NVMe向け
- 自動的にレイテンシ目標を維持
# 現在のI/Oスケジューラを確認
cat /sys/block/nvme0n1/queue/scheduler
# I/Oスケジューラを変更(一時的)
echo "mq-deadline" | sudo tee /sys/block/nvme0n1/queue/scheduler
# 永続的に変更(udevルール)
echo 'ACTION=="add|change", KERNEL=="nvme*", ATTR{queue/scheduler}="none"' | \
sudo tee /etc/udev/rules.d/60-scheduler.rules
# I/O統計の確認
iostat -x 1 # 1秒間隔で表示
# デバイスのキュー設定
cat /sys/block/nvme0n1/queue/nr_requests # キュー深度
cat /sys/block/nvme0n1/queue/read_ahead_kb # 先読みサイズ
7. クラウドストレージとストレージ階層
7.1 クラウドストレージサービス比較
AWS ストレージサービス:
■ EBS (Elastic Block Store)タイプ IOPS スループット 用途 ─────────────── ───────── ───────────── ─────────── gp3 16,000 1,000MB/s 汎用 io2 64,000 1,000MB/s DB io2 Express 256,000 4,000MB/s 高性能DB st1 500 500MB/s ログ sc1 250 250MB/s アーカイブ
■ S3 (Simple Storage Service)クラス 可用性 料金(GB/月) 用途 ───────────────── ───────── ───────────── ───────────── Standard 99.99% $0.023 頻繁アクセス Intelligent 自動 自動最適化 不明確 Standard-IA 99.9% $0.0125 低頻度 Glacier Instant 99.9% $0.004 アーカイブ Glacier Deep 99.99% $0.00099 長期保管
■ ストレージ階層設計(ティアリング):
ホットデータ(頻繁アクセス):
└─ io2 EBS / gp3 EBS
└─ コスト高、IOPS最高
ウォームデータ(時々アクセス):
└─ S3 Standard / S3 Standard-IA
└─ コスト中、遅延100ms程度
コールドデータ(稀にアクセス):
└─ S3 Glacier
└─ コスト低、取り出しに数分〜数時間
アーカイブ(ほぼアクセスしない):
└─ S3 Glacier Deep Archive
└─ コスト最低、取り出しに12時間
7.2 データ保護戦略
3-2-1 バックアップルール:
3: データを3コピー持つ
2: 2種類以上の異なるメディアに保存
1: 1つはオフサイト(遠隔地)に保存
実装例:プライマリ: NVMe SSD (RAID 10) ↓ 毎日 セカンダリ: NASサーバー (ZFS RAIDZ2) ↓ 毎週 オフサイト: S3 Glacier / Google Cloud
RPO(Recovery Point Objective)と RTO(Recovery Time Objective):
RPO: 許容できるデータ損失量(時間)
RTO: システム復旧までの許容時間
│ レベル │ RPO │ RTO │ 方式 │
│──────────────│──────────│──────────│─────────────────────│
│ ミッションクリティカル │ 0 │ 数秒 │ 同期レプリケーション │
│ 重要システム │ 数分 │ 数分 │ 非同期レプリケーション│
│ 一般業務 │ 数時間 │ 数時間 │ スナップショット │
│ アーカイブ │ 1日 │ 1日以上 │ 日次バックアップ │
8. ストレージの未来
技術
特徴
状況
CXL
CPU-メモリ間の新プロトコル、メモリプーリング
2024年実用化開始
Intel Optane
DRAMとSSDの中間の特性(終了)
生産終了、技術は他社へ
PLC NAND
5ビット/セル、大容量低コスト
量産開始
DNA Storage
1グラムで215PBのデータを保存
研究段階
ガラスストレージ
1000年以上の耐久性
Microsoft Project Silica
UCIe SSD
チップレット構成のSSD
2025年プロトタイプ
ZNS (Zoned Namespaces)
ホスト管理のSSD書き込み
データセンター向け
8.1 ZNS SSD(Zoned Namespaces)
従来のSSD vs ZNS SSD:
従来のSSD:
ホスト → LBA → FTL(SSD内部)→ 物理ブロック
- FTLが複雑(大量のDRAM必要)
- GCによる性能低下
- オーバープロビジョニングで容量損失
ZNS SSD:
ホスト → Zone(シーケンシャル書き込み領域)→ 物理ブロックZone 0: [書き込み済み] [書き込み済み] [WP→] [空き] Zone 1: [書き込み済み] [WP→] [空き] [空き] Zone 2: [空き] [空き] [空き] [空き]
WP = Write Pointer(書き込みポインタ)
- ゾーン内はシーケンシャル書き込みのみ
- FTLが大幅簡略化(DRAM削減)
- GC不要(ホストがゾーンのリセットを管理)
- オーバープロビジョニング不要
→ コスト削減、性能安定化
対応ソフトウェア:
- Linux(blk-zoned)
- f2fs(ZNSネイティブサポート)
- RocksDB(Zenith プラグイン)
- Ceph(BlueStore ZNS対応)
9. ストレージベンチマーク
9.1 fio によるベンチマーク
# fio (Flexible I/O Tester) のインストール
sudo apt install fio # Ubuntu/Debian
brew install fio # macOS
# 順次読み取りベンチマーク
fio --name=seq_read --filename=/tmp/fio_test \
--rw=read --bs=1M --size=1G --numjobs=1 \
--iodepth=32 --ioengine=libaio --direct=1 \
--runtime=30 --group_reporting
# 順次書き込みベンチマーク
fio --name=seq_write --filename=/tmp/fio_test \
--rw=write --bs=1M --size=1G --numjobs=1 \
--iodepth=32 --ioengine=libaio --direct=1 \
--runtime=30 --group_reporting
# ランダム読み取りベンチマーク(4KB、IOPS重視)
fio --name=rand_read --filename=/tmp/fio_test \
--rw=randread --bs=4k --size=1G --numjobs=4 \
--iodepth=64 --ioengine=libaio --direct=1 \
--runtime=30 --group_reporting
# ランダム書き込みベンチマーク
fio --name=rand_write --filename=/tmp/fio_test \
--rw=randwrite --bs=4k --size=1G --numjobs=4 \
--iodepth=64 --ioengine=libaio --direct=1 \
--runtime=30 --group_reporting
# 混合ワークロード(読み70%:書き30%)
fio --name=mixed --filename=/tmp/fio_test \
--rw=randrw --rwmixread=70 --bs=4k --size=1G \
--numjobs=4 --iodepth=32 --ioengine=libaio \
--direct=1 --runtime=30 --group_reporting
# レイテンシヒストグラム付き
fio --name=latency --filename=/tmp/fio_test \
--rw=randread --bs=4k --size=1G --numjobs=1 \
--iodepth=1 --ioengine=libaio --direct=1 \
--runtime=30 --lat_percentiles=1 \
--group_reporting
9.2 ベンチマーク結果の読み方
fio 出力の解読:
seq_read: (groupid=0, jobs=1): err= 0: pid=1234
read: IOPS=3456, BW=3456MiB/s (3623MB/s)
~~~~ ~~~~~~~~
IOPS数 実効帯域幅
clat (usec): min=15, max=892, avg=28.23, stdev=12.41
~~~~ ~~~~~~~~
最小レイテンシ 平均レイテンシ
clat percentiles (usec):
| 1.00th=[ 18], 5.00th=[ 20], 10.00th=[ 21]
| 50.00th=[ 26], 90.00th=[ 38], 95.00th=[ 45]
| 99.00th=[ 82], 99.50th=[ 112], 99.90th=[ 245]
| 99.95th=[ 338], 99.99th=[ 668]
→ P99 = 82μs: 99%のリクエストが82μs以内に完了
→ テールレイテンシ(P99.9+)に注目
重要な指標:
- BW(帯域幅): 順次I/Oの性能
- IOPS: ランダムI/Oの性能
- clat(完了レイテンシ): 個々のI/Oの応答時間
- P99/P99.9: テールレイテンシ(SLA設計に重要)
10. 実践演習
演習1: I/O性能の計算(基礎)
7200RPMのHDDで、以下の操作にかかる時間を計算せよ:
ランダムに1つの4KBブロックを読み取る
連続した1GBのファイルを読み取る
ランダムに1000個の4KBブロックを読み取る
演習2: ストレージ選定(応用)
以下のワークロードに最適なストレージとRAIDレベルを選定し、理由を述べよ:
PostgreSQLデータベース(読み取り多、低レイテンシ必須)
動画配信サービスの元データ保管(大容量、シーケンシャル読み取り)
Webアプリのログ収集(書き込み多、順次追記)
演習3: ベンチマーク(発展)
fio または dd コマンドを使って自分のマシンのストレージ性能を測定せよ:
順次読み取り/書き込みの帯域幅
ランダム読み取り/書き込みのIOPS
測定結果を理論値と比較
演習4: RAID計算(応用)
以下の条件でRAIDの性能と容量を計算せよ:
ディスク: 4TB SSD × 8台(各ディスク: 100K IOPS、500MB/s順次)
ワークロード: 読み60%、書き40%
各RAIDレベル(0, 1, 5, 6, 10)について:
有効容量
理論上の読み取り/書き込みIOPS
理論上の順次読み取り帯域幅
耐障害ディスク数
演習5: バックアップ戦略の設計(発展)
以下のシステムのバックアップ戦略を設計せよ:
PostgreSQL: 500GBのデータベース、RPO=1時間、RTO=30分
ユーザーアップロード画像: 10TB、RPO=24時間、RTO=4時間
アクセスログ: 1日50GB生成、90日保持
設計項目:
バックアップ方式(フル/増分/差分)
スケジュール
保管先
復旧手順の概要
月間コスト見積もり(AWS前提)
トラブルシューティング
よくあるエラーと解決策
エラー
原因
解決策
初期化エラー
設定ファイルの不備
設定ファイルのパスと形式を確認
タイムアウト
ネットワーク遅延/リソース不足
タイムアウト値の調整、リトライ処理の追加
メモリ不足
データ量の増大
バッチ処理の導入、ページネーションの実装
権限エラー
アクセス権限の不足
実行ユーザーの権限確認、設定の見直し
データ不整合
並行処理の競合
ロック機構の導入、トランザクション管理
デバッグの手順
エラーメッセージの確認 : スタックトレースを読み、発生箇所を特定する
再現手順の確立 : 最小限のコードでエラーを再現する
仮説の立案 : 考えられる原因をリストアップする
段階的な検証 : ログ出力やデバッガを使って仮説を検証する
修正と回帰テスト : 修正後、関連する箇所のテストも実行する
# デバッグ用ユーティリティ
import logging
import traceback
from functools import wraps
# ロガーの設定
logging. basicConfig (
level = logging. DEBUG ,
format = ' %(asctime)s [ %(levelname)s ] %(name)s : %(message)s '
)
logger = logging. getLogger ( __name__ )
def debug_decorator ( func ):
"""関数の入出力をログ出力するデコレータ"""
@wraps ( func )
def wrapper (* args , ** kwargs ):
logger. debug ( f "呼び出し: { func. __name__ } (args= { args } , kwargs= { kwargs } )" )
try :
result = func (*args, **kwargs)
logger. debug ( f "戻り値: { func. __name__ } -> { result } " )
return result
except Exception as e:
logger. error ( f "例外発生: { func. __name__ } : { e } " )
logger. error (traceback. format_exc ())
raise
return wrapper
@debug_decorator
def process_data ( items ):
"""データ処理(デバッグ対象)"""
if not items:
raise ValueError( "空のデータ" )
return [item * 2 for item in items]
パフォーマンス問題の診断
パフォーマンス問題が発生した場合の診断手順:
ボトルネックの特定 : プロファイリングツールで計測
メモリ使用量の確認 : メモリリークの有無をチェック
I/O待ちの確認 : ディスクやネットワークI/Oの状況を確認
同時接続数の確認 : コネクションプールの状態を確認
問題の種類
診断ツール
対策
CPU負荷
cProfile, py-spy
アルゴリズム改善、並列化
メモリリーク
tracemalloc, objgraph
参照の適切な解放
I/Oボトルネック
strace, iostat
非同期I/O、キャッシュ
DB遅延
EXPLAIN, slow query log
インデックス、クエリ最適化
設計判断ガイド
選択基準マトリクス
技術選択を行う際の判断基準を以下にまとめます。
判断基準
重視する場合
妥協できる場合
パフォーマンス
リアルタイム処理、大規模データ
管理画面、バッチ処理
保守性
長期運用、チーム開発
プロトタイプ、短期プロジェクト
スケーラビリティ
成長が見込まれるサービス
社内ツール、固定ユーザー
セキュリティ
個人情報、金融データ
公開データ、社内利用
開発速度
MVP、市場投入スピード
品質重視、ミッションクリティカル
アーキテクチャパターンの選択
アーキテクチャ選択フロー ① チーム規模は? ├─ 小規模(1-5人)→ モノリス └─ 大規模(10人+)→ ②へ ② デプロイ頻度は? ├─ 週1回以下 → モノリス + モジュール分割 └─ 毎日/複数回 → ③へ ③ チーム間の独立性は? ├─ 高い → マイクロサービス └─ 中程度 → モジュラーモノリス
トレードオフの分析
技術的な判断には必ずトレードオフが伴います。以下の観点で分析を行いましょう:
1. 短期 vs 長期のコスト
短期的に速い方法が長期的には技術的負債になることがある
逆に、過剰な設計は短期的なコストが高く、プロジェクトの遅延を招く
2. 一貫性 vs 柔軟性
統一された技術スタックは学習コストが低い
多様な技術の採用は適材適所が可能だが、運用コストが増加
3. 抽象化のレベル
高い抽象化は再利用性が高いが、デバッグが困難になる場合がある
低い抽象化は直感的だが、コードの重複が発生しやすい
# 設計判断の記録テンプレート
class ArchitectureDecisionRecord :
"""ADR (Architecture Decision Record) の作成"""
def __init__ ( self , title : str ):
self .title = title
self .context = ""
self .decision = ""
self .consequences = []
self .alternatives = []
def set_context ( self , context : str ):
"""背景と課題の記述"""
self .context = context
return self
def set_decision ( self , decision : str ):
"""決定内容の記述"""
self .decision = decision
return self
def add_consequence ( self , consequence : str , positive : bool = True ):
"""結果の追加"""
self .consequences. append ({
'description' : consequence,
'type' : 'positive' if positive else 'negative'
})
return self
def add_alternative ( self , name : str , reason_rejected : str ):
"""却下した代替案の追加"""
self .alternatives. append ({
'name' : name,
'reason_rejected' : reason_rejected
})
return self
def to_markdown ( self ) -> str :
"""Markdown形式で出力"""
md = f "# ADR: { self .title } \n\n "
md += f "## 背景 \n { self .context } \n\n "
md += f "## 決定 \n { self .decision } \n\n "
md += "## 結果 \n "
for c in self .consequences:
icon = "✅" if c[ 'type' ] == 'positive' else "⚠️"
md += f "- { icon } { c[ 'description' ] } \n "
md += " \n ## 却下した代替案 \n "
for a in self .alternatives:
md += f "- ** { a[ 'name' ] } **: { a[ 'reason_rejected' ] } \n "
return md
実務での適用シナリオ
シナリオ1: スタートアップでのMVP開発
状況: 限られたリソースで素早くプロダクトをリリースする必要がある
アプローチ:
シンプルなアーキテクチャを選択
必要最小限の機能に集中
自動テストはクリティカルパスのみ
モニタリングは早期から導入
学んだ教訓:
完璧を求めすぎない(YAGNI原則)
ユーザーフィードバックを早期に取得
技術的負債は意識的に管理する
シナリオ2: レガシーシステムのモダナイゼーション
状況: 10年以上運用されているシステムを段階的に刷新する
アプローチ:
Strangler Fig パターンで段階的に移行
既存のテストがない場合はCharacterization Testを先に作成
APIゲートウェイで新旧システムを共存
データ移行は段階的に実施
フェーズ
作業内容
期間目安
リスク
1. 調査
現状分析、依存関係の把握
2-4週間
低
2. 基盤
CI/CD構築、テスト環境
4-6週間
低
3. 移行開始
周辺機能から順次移行
3-6ヶ月
中
4. コア移行
中核機能の移行
6-12ヶ月
高
5. 完了
旧システム廃止
2-4週間
中
シナリオ3: 大規模チームでの開発
状況: 50人以上のエンジニアが同一プロダクトを開発する
アプローチ:
ドメイン駆動設計で境界を明確化
チームごとにオーナーシップを設定
共通ライブラリはInner Source方式で管理
APIファーストで設計し、チーム間の依存を最小化
# チーム間のAPI契約定義
from dataclasses import dataclass
from typing import List, Optional
from enum import Enum
class Priority ( Enum ):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
CRITICAL = "critical"
@dataclass
class APIContract :
"""チーム間のAPI契約"""
endpoint: str
method: str
owner_team: str
consumers: List[ str ]
sla_ms: int # レスポンスタイムSLA
priority: Priority
def validate_sla ( self , actual_ms : int ) -> bool :
"""SLA準拠の確認"""
return actual_ms <= self .sla_ms
def to_openapi ( self ) -> dict :
"""OpenAPI形式で出力"""
return {
'path' : self .endpoint,
'method' : self .method,
'x-owner' : self .owner_team,
'x-consumers' : self .consumers,
'x-sla-ms' : self .sla_ms
}
# 使用例
contracts = [
APIContract (
endpoint = "/api/v1/users" ,
method = "GET" ,
owner_team = "user-team" ,
consumers = [ "order-team" , "notification-team" ],
sla_ms = 200 ,
priority = Priority. HIGH
),
APIContract (
endpoint = "/api/v1/orders" ,
method = "POST" ,
owner_team = "order-team" ,
consumers = [ "payment-team" , "inventory-team" ],
sla_ms = 500 ,
priority = Priority. CRITICAL
)
]
シナリオ4: パフォーマンスクリティカルなシステム
状況: ミリ秒単位のレスポンスが求められるシステム
最適化ポイント:
キャッシュ戦略(L1: インメモリ、L2: Redis、L3: CDN)
非同期処理の活用
コネクションプーリング
クエリ最適化とインデックス設計
最適化手法
効果
実装コスト
適用場面
インメモリキャッシュ
高
低
頻繁にアクセスされるデータ
CDN
高
低
静的コンテンツ
非同期処理
中
中
I/O待ちが多い処理
DB最適化
高
高
クエリが遅い場合
コード最適化
低-中
高
CPU律速の場合
チーム開発での活用
コードレビューのチェックリスト
このトピックに関連するコードレビューで確認すべきポイント:
ナレッジ共有のベストプラクティス
方法
頻度
対象
効果
ペアプログラミング
随時
複雑なタスク
即時のフィードバック
テックトーク
週1回
チーム全体
知識の水平展開
ADR (設計記録)
都度
将来のメンバー
意思決定の透明性
振り返り
2週間ごと
チーム全体
継続的改善
モブプログラミング
月1回
重要な設計
合意形成
技術的負債の管理
優先度マトリクス:
影響度 高
││
影響度 低
発生頻度 低 発生頻度 高
セキュリティの考慮事項
一般的な脆弱性と対策
脆弱性
リスクレベル
対策
検出方法
インジェクション攻撃
高
入力値のバリデーション・パラメータ化クエリ
SAST/DAST
認証の不備
高
多要素認証・セッション管理の強化
ペネトレーションテスト
機密データの露出
高
暗号化・アクセス制御
セキュリティ監査
設定の不備
中
セキュリティヘッダー・最小権限の原則
構成スキャン
ログの不足
中
構造化ログ・監査証跡
ログ分析
セキュアコーディングのベストプラクティス
# セキュアコーディング例
import hashlib
import secrets
import hmac
from typing import Optional
class SecurityUtils :
"""セキュリティユーティリティ"""
@ staticmethod
def generate_token ( length : int = 32 ) -> str :
"""暗号学的に安全なトークン生成"""
return secrets. token_urlsafe (length)
@ staticmethod
def hash_password ( password : str , salt : Optional[ str ] = None ) -> tuple :
"""パスワードのハッシュ化"""
if salt is None :
salt = secrets. token_hex ( 16 )
hashed = hashlib. pbkdf2_hmac (
'sha256' ,
password. encode ( 'utf-8' ),
salt. encode ( 'utf-8' ),
iterations = 100000
)
return hashed. hex (), salt
@ staticmethod
def verify_password ( password : str , hashed : str , salt : str ) -> bool :
"""パスワードの検証"""
new_hash, _ = SecurityUtils. hash_password (password, salt)
return hmac. compare_digest (new_hash, hashed)
@ staticmethod
def sanitize_input ( value : str ) -> str :
"""入力値のサニタイズ"""
dangerous_chars = [ '<' , '>' , '"' , "'" , '&' , ' \\ ' ]
result = value
for char in dangerous_chars:
result = result. replace (char, '' )
return result. strip ()
# 使用例
token = SecurityUtils. generate_token ()
hashed, salt = SecurityUtils. hash_password ( "my_password" )
is_valid = SecurityUtils. verify_password ( "my_password" , hashed, salt)
セキュリティチェックリスト
マイグレーションガイド
バージョンアップ時の注意点
バージョン
主な変更点
移行作業
影響範囲
v1.x → v2.x
API設計の刷新
エンドポイント変更
全クライアント
v2.x → v3.x
認証方式の変更
トークン形式更新
認証関連
v3.x → v4.x
データモデル変更
マイグレーションスクリプト実行
DB関連
段階的移行の手順
# マイグレーションスクリプトのテンプレート
import json
import logging
from pathlib import Path
from datetime import datetime
from typing import List, Dict, Callable
logger = logging. getLogger ( __name__ )
class MigrationRunner :
"""段階的マイグレーション実行エンジン"""
def __init__ ( self , migration_dir : str ):
self .migration_dir = Path (migration_dir)
self .migrations: List[Dict] = []
self .completed: List[ str ] = []
def register ( self , version : str , description : str ,
up : Callable, down : Callable):
"""マイグレーションの登録"""
self .migrations. append ({
'version' : version,
'description' : description,
'up' : up,
'down' : down,
'registered_at' : datetime. now (). isoformat ()
})
def run_up ( self , target_version : str = None ):
"""マイグレーションの実行(アップグレード)"""
for migration in self .migrations:
if migration[ 'version' ] in self .completed:
continue
logger. info ( f "実行中: { migration[ 'version' ] } - "
f " { migration[ 'description' ] } " )
try :
migration[ 'up' ]()
self .completed. append (migration[ 'version' ])
logger. info ( f "完了: { migration[ 'version' ] } " )
except Exception as e:
logger. error ( f "失敗: { migration[ 'version' ] } : { e } " )
raise
if target_version and migration[ 'version' ] == target_version:
break
def run_down ( self , target_version : str ):
"""マイグレーションのロールバック"""
for migration in reversed ( self .migrations):
if migration[ 'version' ] not in self .completed:
continue
if migration[ 'version' ] == target_version:
break
logger. info ( f "ロールバック: { migration[ 'version' ] } " )
migration[ 'down' ]()
self .completed. remove (migration[ 'version' ])
def status ( self ) -> Dict:
"""マイグレーション状態の確認"""
return {
'total' : len ( self .migrations),
'completed' : len ( self .completed),
'pending' : len ( self .migrations) - len ( self .completed),
'versions' : {
m[ 'version' ]: 'completed'
if m[ 'version' ] in self .completed else 'pending'
for m in self .migrations
}
}
ロールバック計画
移行作業には必ずロールバック計画を準備してください:
データのバックアップ : 移行前に完全バックアップを取得
テスト環境での検証 : 本番と同等の環境で事前検証
段階的なロールアウト : カナリアリリースで段階的に展開
監視の強化 : 移行中はメトリクスの監視間隔を短縮
判断基準の明確化 : ロールバックを判断する基準を事前に定義
FAQ
Q1: SSDの寿命はどのくらいですか?
A : TBW(Total Bytes Written)で表される。一般的なコンシューマSSD:
500GB SSD: 〜300 TBW(1日100GB書き込みで約8年)
一般的な使用では寿命前にPC自体を買い替える
サーバー用SSDはさらに高耐久(〜10x PBW)
Q2: データベースはHDDとSSDどちらに置くべきですか?
A : ランダムI/Oが多いDBはSSDが圧倒的に有利 :
HDD: 100 IOPS → SSD: 100,000+ IOPS(1000倍)
特にインデックス検索、ランダムなJOIN操作で差が顕著
コールドデータ(アーカイブ)はHDD/S3で十分
Q3: ZFSとext4の選び方は?
A :
ext4 : シンプル、安定、Linux標準。一般的なWebサーバーに最適
ZFS : データ整合性が最重要な場面(NAS、バックアップ、DB)。メモリ使用量が多い(1TBあたり1GBのRAM推奨)
Q4: RAID 5はなぜデータベースに不向きですか?
A : RAID 5の書き込みペナルティが原因:
1回の書き込み = 2読み + 2書き = 4 I/O
データベースはランダム書き込みが多い
RAID 10なら1回の書き込み = 2 I/O(ミラーのみ)
さらに大容量ディスクではリビルド時間が数十時間に及び、リビルド中の二重障害リスクが高い
Q5: NVMe SSDのキューが65,535もあるのはなぜですか?
A : マルチコアCPUとの並列処理のため:
各CPUコアが専用のキューを持てる
ロック競合なしで同時にI/O要求を発行
サーバーでは64コア以上のCPUが普通なので、十分なキュー数が必要
実際には数百キューで運用することが多い
Q6: SSDのオーバープロビジョニングとは?
A : SSDの実NAND容量の一部をユーザーに見せず、内部管理に使う領域:
不良ブロックの代替
GC用の作業領域
パフォーマンスの安定化
エンタープライズSSDでは28%程度(1TB表記で実NAND 1.28TB)
コンシューマSSDでは7%程度
Q7: SMR HDDを知らずに購入してしまった場合の対処法は?
A : SMR HDDはシーケンシャル書き込みは問題ないが、ランダム書き込みが極端に遅い:
NAS/RAIDには不向き(リビルドが数日かかる場合も)
用途をバックアップ・アーカイブに限定する
購入前にメーカーのスペックシートでCMR/SMRを確認
Seagate Barracuda, WD Blueの一部がSMR
まとめ
概念
ポイント
HDD
機械式、ランダムI/O遅い(〜100 IOPS)、大容量・安価
SSD
NAND、ランダムI/O速い(〜100K IOPS)、書き込み回数制限あり
NVMe
PCIe直結、AHCI→NVMeで並列度65,535倍
FS
ジャーナリング(ext4)かCOW(ZFS/Btrfs)で整合性確保
RAID
0=速度、1=安全、5=バランス、10=性能+安全
ZNS
ホスト管理のゾーン書き込みでSSD効率向上
クラウド
ティアリングでコスト最適化(ホット→コールド)
次に読むべきガイド
参考文献
Arpaci-Dusseau, R. H. & Arpaci-Dusseau, A. C. "Operating Systems: Three Easy Pieces." Chapter on Hard Disk Drives and Flash-based SSDs.
Cornwell, M. "Anatomy of a Solid-State Drive." ACM Queue, 2012.
Agrawal, N. et al. "Design Tradeoffs for SSD Performance." USENIX ATC, 2008.
Bonwick, J. & Moore, B. "ZFS: The Last Word in File Systems." Sun Microsystems, 2004.
Love, R. "Linux Kernel Development." 3rd Edition, Addison-Wesley, 2010.
Bjorling, M. et al. "ZNS: Avoiding the Block Interface Tax for Flash-based SSDs." USENIX ATC, 2021.
NVM Express Specification. "NVM Express Base Specification." Revision 2.0.
Desnoyers, P. "Analytic Models of SSD Write Performance." ACM TOS, 2014.
AWS Documentation. "Amazon EBS Volume Types." https://docs.aws.amazon.com/ebs/
Leventhal, A. "A File System All Its Own (ZFS)." ACM Queue, 2013.