文档版本 v3.7-DRAFT 处于 草稿 状态。如需获取最新的稳定版文档,请参阅 v3.6。
存储内存使用基准测试
etcd 存储的两个组件会消耗物理内存。etcd 进程分配了一个内存索引以加速键查找。进程的页面缓存由操作系统管理,用于存储最近访问的磁盘数据以便快速重用。
内存索引使用B 树数据结构保存所有键,并附带指向磁盘数据(值)的指针。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
| |
+-----+
| ... |
| |
------+
页面缓存内存由操作系统管理,本文档不作详细说明。
测试环境
etcd 版本
GCE n1-standard-2 机器类型
- 7.5 GB 内存
- 2 个 CPU
内存索引的内存使用情况
在这个测试中,我们仅对内存索引的内存使用情况进行基准测试。目的是找到上述提到的c1和c2,并了解存储的内存消耗硬限制。
我们通过 Go 的 runtime.ReadMemStats 计算内存使用情况。我们计算创建索引前后总分配字节数的差异。虽然这不能完美反映内存索引本身的内存使用情况,但可以展示大致的消耗模式。
| N | 版本 | 键大小 | 内存使用情况 |
|---|---|---|---|
| 100K | 1 | 64 字节 | 22MB |
| 100K | 5 | 64 字节 | 39MB |
| 1M | 1 | 64 字节 | 218MB |
| 1M | 5 | 64 字节 | 432MB |
| 100K | 1 | 256 字节 | 41MB |
| 100K | 5 | 256 字节 | 65MB |
| 1M | 1 | 256 字节 | 409MB |
| 1M | 5 | 256 字节 | 506MB |
根据结果,我们可以计算出c1=120 字节,c2=30 字节。我们只需要两组数据来计算c1和c2,因为它们是公式中唯一的未知变量。c1=120 字节和c2=30 字节是我们计算的四组c1和c2的平均值。对于小的键值对,键元数据开销仍然相对较大(50%)。然而,这比旧存储有了显著改进,旧存储至少有 1000%的开销。
总体内存使用情况
总体内存使用情况反映了 etcd 在存储时消耗的 RSS。值的大小对 etcd 的总体内存使用影响很小,因为我们把值保留在磁盘上,只有热值保留在内存中,由操作系统的页面缓存管理。
| N | 版本 | 键大小 | 值大小 | 内存使用情况 |
|---|---|---|---|---|
| 100K | 1 | 64 字节 | 256 字节 | 40MB |
| 100K | 5 | 64 字节 | 256 字节 | 89MB |
| 1M | 1 | 64 字节 | 256 字节 | 470MB |
| 1M | 5 | 64 字节 | 256 字节 | 880MB |
| 100K | 1 | 64 字节 | 1KB | 102MB |
| 100K | 5 | 64 字节 | 1KB | 164MB |
| 1M | 1 | 64 字节 | 1KB | 587MB |
| 1M | 5 | 64 字节 | 1KB | 836MB |
根据结果,我们知道值的大小对内存消耗的影响并不显著。由于操作系统页面缓存中持有的数据增加,内存消耗有轻微的增长。