速度が出るパリティな記憶域プール/記憶域スペースを作った話

## 大前提：記憶域プール/記憶域スペース #とは

私なりの理解で言うと、Windows8以降に備わっているソフトウェアRAID「の様なもの」だと思ってください。
なお、以下はWindows10（22H2）またはWindowsServer2019(1803)までの知識で実践した内容になります。~~Windows11？知らない仔ですね……~~

**補足(2024年11月23日修正)**
2024年11月17日頃、本記事で作成した記憶域スペースは**1枚のSSDと2台のHDDにセクタエラーが生じたことを検知したため、運用を終了しました。**

### 記憶域プール：

記憶域スペース（後述）に使用するストレージを登録したグループ（プール）です。

### 記憶域スペース：

記憶域プールに登録されたストレージ達から「任意の使い方に基づいた並列性・回復性を持たせた仮想ディスク」を切り出してWindowsに提供する機能です。

#### 並列性（NumberOfColumns）
並列性は「記憶域スペースで利用するストレージの内、何台にデータを分散して保存するか」という設定を指します。

#### 回復性（FaultDomainRedundancy）
回復性は「記憶域スペースで利用するストレージの内、何台までの障害に耐久する冗長性を持たせているか」という設定を指します。

## 普通に記憶域スペースを作ると速度が出ない

敢えて言葉を選ばずに言うと、**Windowsのコントロールパネルから作る記憶域スペースはカス**です。
Windows8/WindowsServer2012が登場して以来既に10年が経過して居ますが、一向に改善されていないというか、**GUIで並列性と回復性を細かく設定させてくれません。~~Windowsの取り柄はGUIなのに~~**

:::note warn
**シンプル（ストライピング）を選んだ筈なのにJBOD相当になっているとか**
:::
:::note warn
**4台でシンプル（ストライピング）を組んだ筈なのに2台分弱の速度しか出ないとか**
:::
:::note warn
**パリティを選ぶと容量が「使用する全ストレージの合計容量の（台数-1）/台数」ではなく「使用する全ストレージの合計容量の2/3」になるとか**
:::
:::note warn
**パリティを選ぶと極端に書き込み速度が低下する（下掲）とか**
![スクリーンショット 2024-02-18 17.34.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1861875/30601361-6802-aed9-5050-b862591228e3.png)
:::
**「PCあんま詳しくないけど兎に角、記憶域プール/記憶域スペースを使って大容量記憶域を構成したい」** 向きにとっては簡単なダイアログで構成できますが、**「PC詳しい方で記憶域プール/記憶域スペースを使って「高パフォーマンスな」大容量記憶域を構成したい」** という向きにとっては、GUIでより詳細に設定を詰めるということが出来ません。
~~(´・ω・｀)＜「より詳細な設定」とかGUIで作ってくれたら良いのに~~

では、どうすれば良いか。

## 高パフォーマンスな記憶域スペースを作りたいならPowerShellを使いましょう

もう見出しそのままですが、**高パフォーマンスな記憶域スペースを作りたいなら、CUI（PowerShell）を使う** のが高パフォーマンスな記憶域スペースを作るための回答になります。~~おいおいWindowsの取り柄はGUIだろCUIとか辛いじゃねえか~~

という訳で、実際に高パフォーマンスな記憶域スペース（パリティ）を作ってみました。

## 高パフォーマンスな記憶域スペース（パリティ）を作る：ハードウェア編

**逸般の誤家庭** であればPCIe Bifurcationを使って拡張スロットに何本もNVMe SSDを挿して、オールフラッシュストレージを構成して速度を出す、といったことも出来るでしょうが、**筆者は一般のご家庭** ですので、今回はそこら辺に転がっていた「M.2 SATAの512GB SSD×4本」と「SATAの6TB HDD×6本」を「PCIe2.0×2接続->SATA3.0×5に変換するJMB585が載ったHBA」で高パフォーマンスな記憶域スペース（パリティ）を作ってみたいと思います。
~~一般のご家庭には10本もストレージがその辺に転がってる訳ないだろというツッコミは無視します~~

### 先ずは記憶域プールに追加するためにディスクを初期化します

今回使用するストレージはいずれも、過去に検証等で**記憶域スペースに投入した後にリタイヤさせたことがあったり** 、**TrueNAS COREのZFS（RAID-Z）に投入したことがあったり** した古いハードウェアばかりですので、以前のデータが残っていたり構成情報が残っていたりして**そのままでは記憶域プールに放り込むことが出来ません。**
という訳で先ずはディスクを記憶域プールに放り込める様にします。
管理者権限でPowerShellを起動します（以下はWindowsServer2019(1803)の場合)。
```PowerShell
C:¥Users¥Administrator> Get-PhysicalDisk
```
すると下記の様な表示になります（シリアルナンバーはマスクしてあります）。
![スクリーンショット 2024-02-19 7.04.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1861875/f83bc4a0-d4d4-b2a3-9f4b-3dad3c357b52.png)

### デバイス名とデバイスの数、種類の確認
デバイス名とデバイスの数を確認して、
**・記憶域プールに放り込みたいデバイスが全て揃っていること**
**・「MediaType」がそのデバイスの種別通り（HDDならHDD、SSDならSSD）になっていること**
**・「HealthStatus」が「Healthy」になっていること**
を確認してください。**「HealthStatus」は特に。**
ここで「HealthStatus」が「UnHealthy」になっている場合はそのディスクは使用できませんので、別のディスクと交換が必要になります。

### ディスクが記憶域プールに取り込めるか確認
次に、「CanPool」の項目を見ます。上掲のスクリーンショットでは記憶域プールに放り込みたいデバイスが全て「False」になっていますので、これを「True」になるように操作します。
```PowerShell
C:¥Users¥Administrator> Get-PhysicalDisk -SerialNumber "(操作したいディスクのシリアルナンバー)" | Reset-PhysicalDisk
```
これを放り込みたいデバイスの分だけ繰り返します。

### ディスクを記憶域プールに取り込む
次に、「CanPool」が「True」になったデバイスを全て変数「$PhysicalDisks」に投入し、続けて一括りの記憶域プール（この場合は仮に「36TB」とします）に放り込みます。
```PowerShell
C:¥Users¥Administrator> $PhysicalDisks = (Get-PhysicalDisk -CanPool $True)
C:¥Users¥Administrator> New-StoragePool -FriendlyName "36TB" -StorageSubsystemFriendlyName "Windows Storage*" -PhysicalDisks $PhysicalDisks
```
無事にコマンドが終了したら、「Get-StoragePool」コマンドの実行結果が次の様な表示になる筈です。
![スクリーンショット 2024-02-19 7.30.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1861875/41b1ee51-bef2-e4f4-15d6-2df1bf9a6687.png)

### SSDはライトバックキャッシュに指定する
次に、「MediaType」が「SSD」のディスクはライトバックキャッシュに指定して書き込み速度の高速化を図りたいので、「Get-PhysicalDisk」を実行して「Usage」が「Auto-Select」になっていないディスクは「Journal」に変更します。今回はデバイス名が全て同じSSDを使っていますので、次の様なコマンドになります。
```PowerShell
C:¥Users¥Administrator> Set-PhysicalDisk -FriendlyName "WT M.2-512GB" -Usage Journal
```
更に次のコマンドを投入します。
```PowerShell
C:¥Users¥Administrator> Set-StoragePool -FriendlyName "36TB" -IsPowerProtected $True
```

### 記憶域プールに投入されたディスクを使って記憶域スペースを作る
最後に、「記憶域プール「36TB」に投入された使用可能なディスクの全容量を使って、冗長性が「パリティ」かつ並列性が「HDDの台数分（※ここでは6台）」に設定された、「ライトバックキャッシュが230GB（※Windowsから認識されている記憶容量の半分以下の数字である必要があるため、ここでは230GBとしていますが、好きな数字に置き換えてもらって構いません）」の記憶域スペース「パリティwithキャッシュ」を作成する」コマンドを投入します。
```PowerShell
C:¥Users¥Administrator> New-VirtualDisk -StoragePoolFriendlyName "36TB" -FriendlyName "パリティwithキャッシュ" -ResiliencySettingName Parity -UseMaximumSize -ProvisioningType Fixed -NumberOfColumns 6 -WriteCacheSize 230GB
```
以上のコマンドが無事完了すると、「タスクマネージャー」や「ディスクの管理」から物理ディスクの表示が消失し、代わりに「Microsoft Storage Space Device」という表記のデバイスが出現します。
また、PowerShellでGet-VirtualDiskすることでも確認ができます。
![スクリーンショット 2024-02-19 8.21.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1861875/9734da95-bdfa-9c31-1310-76d4db1b614c.png)
「FootprintOnPool」は記憶域プールに所属しているディスクの記憶容量の合計、「Size」はその内実際にユーザーが使い得る記憶容量の合計（※FootprintOnPool÷記憶域プールに所属しているHDDの数×（記憶域プールに所属しているHDDの数-FaultDomainRedundancyの値））です。
後は「ディスクの管理」やDiskpartを使って、ReFSなりNTFSなり好きなフォーマットで**アロケーションユニットサイズを最大値にして（※ここ重要）** フォーマットして適当なドライブレターをアサインするだけです（個人的にReFSには良い思い出がないので、NTFSをお勧めします……）。

## 実測値
では、早速実際的なベンチマークとして、この記憶域スペースで作成したドライブを共有ドライブとし、これをネットワークドライブとしてマウントした　**「バックアップが必要なファイルが約34万件・容量15.6TB」** あるファイルサーバーから、FreeFileSyncというバックアップソフトで2.5GbE越しに転送した場合のディスクの書き込み速度を、タスクマネージャーから確認してみましょう。
![スクリーンショット 2024-02-19 7.57.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1861875/73209d21-0b1c-9b53-8e04-0baef311694f.png)
上掲はファイルサーバーから約45500件・7.46TB転送し、約273500件・8.26TB残っている状態の時の書き込み速度です。計算上はSSDのキャッシュはとっくに使い切っている筈です。
グラフを見ると、概ね100MB〜240MB/s出ているのが分かるかと思います（グラフが一瞬0に振れているのはファイルの書き込みが終わって次のファイルを書き込み始める瞬間です）。
GUIから普通に（？）パリティの記憶域スペースを作った場合、書き込み速度は大体30MB〜65MB/s程度になるのを思うと、圧倒的に速いです。
**ちなみにCrystalDiskMark（ちょっとこのサーバーに入っていたバージョンは古かった）でサイズを8GBにして実行すると、全く速度が奮いませんでした（再掲）。**
![スクリーンショット 2024-02-18 17.34.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1861875/5a1697a2-b8eb-4a06-8570-ba6f90269ac2.png)

## まとめ

:::note info
**PowerShellを使って記憶域プール/記憶域スペースを構成することで、高パフォーマンスかつ冗長性を持ち、台数に対する提供容量比が（双方向ミラーリングより）高い仮想ディスクを作成することが出来る。**
:::
:::note warn
**使用したSSDの性能が低いのか、それともベンチマークソフトの動作と実際に起こり得る動作（ファイルの書き込み）に差があるのか、ベンチマークソフトと実際のファイル転送によって起きる書き込み動作とで、書き込み速度に大きな乖離がある気がする。**
:::
:::note warn
**PowerShell上ではGet-PhysicalDiskした際にHealthStatusが「Healthy」なディスクでも、実際にはS.M.A.R.T.エラー（例えばセクタエラー等）が記録されていて注意が必要なディスクである場合がある（何を以てWindows的にはHealthyという認識にしているんだろう🧐？）。**
:::