# ストレージのメモリー使用量ベンチマーク

> etcdストレージ（インメモリーインデックスとページキャッシュ）の性能測定

---

LLMSインデックス: [llms.txt](/ja/llms.txt)

---

<!---todo: link storage to storage design doc-->
etcdのストレージでは、2つの構成要素が物理メモリーを消費します。etcdプロセスは、キーの検索を高速化するために*インメモリーインデックス*を割り当てます。また、オペレーティングシステムが管理するプロセスの*ページキャッシュ*には、最近ディスクから読み込んだデータが保存され、すばやく再利用できます。

インメモリーインデックスは、ディスク上のデータ（値）へのポインターとともに、すべてのキーを[B木][btree]のデータ構造で保持します。B木の各キーには、値の異なるバージョンを指す複数のポインターが含まれる場合があります。そのため、インメモリーインデックスの理論上のメモリー消費量は、次の式で近似できます。

`N * (c1 + avg_key_size) + N * (avg_versions_of_key) * (c2 + size_of_pointer)`

ここで、`c1`はキーのメタデータのオーバーヘッド、`c2`はバージョンのメタデータのオーバーヘッドです。

次の図は、インメモリーインデックスのB木の詳細な構造を示します。

```


                                In mem index

                               +------------+
                               | key || ... |
  +--------------+             |     ||     |
  |              |             +------------+
  |              |             | v1  || ... |
  |   disk    <----------------|     ||     | Tree Node
  |              |             +------------+
  |              |             | v2  || ... |
  |           <----------------+     ||     |
  |              |             +------------+
  +--------------+       +-----+    |   |   |
                         |     |    |   |   |
                         |     +------------+
                         |
                         |
                         ^
                      ------+
                      | ... |
                      |     |
                      +-----+
                      | ... | Tree Node
                      |     |
                      +-----+
                      | ... |
                      |     |
                      ------+
```

[ページキャッシュのメモリー][pagecache]はオペレーティングシステムが管理するため、このドキュメントでは詳しく扱いません。

## テスト環境 {#testing-environment}

etcdのバージョン
- git head https://github.com/etcd-io/etcd/commit/776e9fb7be7eee5e6b58ab977c8887b4fe4d48db

GCEのn1-standard-2マシンタイプ

- メモリー：7.5 GB
- CPU：2基

## インメモリーインデックスのメモリー使用量 {#in-memory-index-memory-usage}

このテストでは、インメモリーインデックスのメモリー使用量のみを測定します。目的は、前述の`c1`と`c2`を求め、ストレージのメモリー消費量の厳密な限界を把握することです。

Goのruntime.ReadMemStatsを使い、インデックス作成前後の総割り当てバイト数の差から、メモリー消費量を算出します。インメモリーインデックス自体の使用量を完全に反映するわけではありませんが、おおよその消費傾向を把握できます。

| N    | バージョン数 | キーサイズ | メモリー使用量 |
|------|----------|----------|--------------|
| 100K | 1        | 64bytes  | 22MB         |
| 100K | 5        | 64bytes  | 39MB         |
| 1M   | 1        | 64bytes  | 218MB        |
| 1M   | 5        | 64bytes  | 432MB        |
| 100K | 1        | 256bytes | 41MB         |
| 100K | 5        | 256bytes | 65MB         |
| 1M   | 1        | 256bytes | 409MB        |
| 1M   | 5        | 256bytes | 506MB        |


結果から、`c1=120bytes`、`c2=30bytes`と計算できます。式の未知数はこの2つだけなので、`c1`と`c2`の算出には2組のデータだけが必要です。`c1=120bytes`と`c2=30bytes`は、計算した4組の`c1`と`c2`の平均値です。小さなキー・バリューペアに対しては、キーのメタデータのオーバーヘッドは依然として無視できない大きさ（50%）です。しかし、少なくとも1000%のオーバーヘッドがあった旧ストアからは大幅に改善しています。

## 全体のメモリー使用量 {#overall-memory-usage}

全体のメモリー使用量は、ストレージを含めたetcdのRSS消費量を測定したものです。値はディスクに保存し、頻繁に使う値だけをOSのページキャッシュで管理するメモリーに保持するため、値のサイズがetcd全体のメモリー使用量に与える影響はごく小さいはずです。

| N    | バージョン数 | キーサイズ | 値のサイズ | メモリー使用量 |
|------|----------|----------|------------|--------------|
| 100K | 1        | 64bytes  | 256bytes   | 40MB         |
| 100K | 5        | 64bytes  | 256bytes   | 89MB         |
| 1M   | 1        | 64bytes  | 256bytes   | 470MB        |
| 1M   | 5        | 64bytes  | 256bytes   | 880MB        |
| 100K | 1        | 64bytes  | 1KB        | 102MB        |
| 100K | 5        | 64bytes  | 1KB        | 164MB        |
| 1M   | 1        | 64bytes  | 1KB        | 587MB        |
| 1M   | 5        | 64bytes  | 1KB        | 836MB        |

結果から、値のサイズはメモリー消費量に大きな影響を与えないことがわかります。OSのページキャッシュに保持されるデータが増えるため、わずかな増加は見られます。

[btree]: https://en.wikipedia.org/wiki/B-tree
[pagecache]: https://en.wikipedia.org/wiki/Page_cache
