ITADN
sirupsen/napkin-math
sirupsen/napkin-math · 文件 下载 ZIP
文件最后提交记录最后更新时间
README.md
以下内容由 AI 翻译,如有问题请点此提交 issue 反馈

餐巾纸数学

本项目的目标是收集软件、数字和技术,以便从第一性原理出发快速估算系统的预期性能。例如,读取 1 GB 内存需要多长时间?通过组合这些资源,你应该能够回答一些有趣的问题,例如:对于一个具有 100,000 RPS 的应用程序,你应该预期支付多少日志存储成本?

学习这项技能的最佳入门途径是通过我在 SRECON 上的演讲。

在计算机这一宏大领域中练习餐巾纸数学的最佳方式是解决你自己的问题。次佳方式是订阅这封通讯,你将每隔几周收到一个问题用于练习。随着你对这些技术的熟练程度提高,解决每个问题应该只需要几分钟。

用于练习的问题存档在这里。解决方案将在下一封通讯中公布。

数字

以下是为便于记忆而取整的数字,而非虚假的精确值。 本仓库当前可在单主机上刷新的行,已于 2026 年 3 月 8 日在最新的 GCP c4-standard-48-lssd 实例上重新测量并重新验证 (Intel Xeon 6985P-C,48 vCPU / 24 物理核心,180 GB RAM,Ubuntu 22.04.5 LTS)。

注 1: 部分吞吐量和延迟数值不一致,这是为了便于计算而有意为之。

注 2: 请对这些数值持保留态度。例如,对于 I/O,fio 是 最先进的工具。随着我不断学习以提高准确性以及硬件的进步,我会持续更新这些数值。

操作延迟吞吐量1 MiB1 GiB
顺序内存读写 (64 字节)0.5 ns
├ 单线程20 GiB/s50 μs50 ms
├ 多线程200 GiB/s5 μs5 ms
网络 同可用区10 GiB/s100 μs100 ms
├ VPC 内部10 GiB/s100 μs100 ms
├ VPC 外部3 GiB/s300 μs300 ms
哈希,非加密安全 (64 字节)10 ns5 GiB/s200 μs200 ms
随机内存读写 (64 字节)20 ns3 GiB/s300 μs300 ms
快速序列化 [8] [9]N/A1 GiB/s1 ms1s
快速反序列化 [8] [9]N/A1 GiB/s1 ms1s
系统调用300 nsN/AN/AN/A
哈希,加密安全 (64 字节)100 ns1 GiB/s1 ms1s
顺序 SSD 读取 (8 KiB)1 μs8 GiB/s100 μs100 ms
上下文切换 [1] [2]10 μsN/AN/AN/A
顺序 SSD 写入,-fsync (8KiB)2 μs3 GiB/s300 μs300 ms
TCP 回显服务器 (32 KiB)50 μs500 MiB/s2 ms2s
随机 SSD 读取 (8 KiB)100 μs70 MiB/s15 ms15s
解压缩 [11]N/A1 GiB/s1 ms1s
压缩 [11]N/A500 MiB/s2 ms2s
排序 (64 位整数)N/A500 MiB/s2 ms2s
代理: Envoy/ProxySQL/Nginx/HAProxy50 μs???
同一区域内的网络250 μs2 GiB/s500 μs500 ms
同可用区/VPC 内的高级网络250 μs25 GiB/s50 μs40 ms
顺序 SSD 写入, +fsync (8KiB)300 μs30 MiB/s30 ms30s
{MySQL, Memcached, Redis, ..} 查询500 μs???
序列化 [8] [9]N/A100 MiB/s10 ms10s
反序列化 [8] [9]N/A100 MiB/s10 ms10s
顺序 HDD 读取 (8 KiB)10 ms250 MiB/s2 ms2s
随机 HDD 读取 (8 KiB)10 ms0.7 MiB/s2 s30m
Blob 存储 GET, if-not-match 30430 ms
Blob 存储 GET, 1 连接 (128KiB)80 ms100 MiB/s10 ms10s
Blob 存储 GET, n 连接 (偏移量)80 msNW 限制
Blob Storage LIST100 ms
Blob Storage PUT, 1 conn (128KiB)200 ms100 MiB/s10 ms10s
Blob Storage PUT, n conn (multipart)200 msNW limit10 ms10s
区域间网络 [6]Varies25 MiB/s40 ms40s
北美中部 <-> 东部网络25 ms25 MiB/s40 ms40s
北美中部 <-> 西部网络40 ms25 MiB/s40 ms40s
北美东部 <-> 西部网络60 ms25 MiB/s40 ms40s
欧洲西部 <-> 北美东部网络80 ms25 MiB/s40 ms40s
欧洲西部 <-> 北美中部网络100 ms25 MiB/s40 ms40s
北美西部 <-> 新加坡网络180 ms25 MiB/s40 ms40s
欧洲西部 <-> 新加坡网络160 ms25 MiB/s40 ms40s

†: “快速序列化/反序列化”通常是一种简单的线协议, 仅转储字节,或是一个极其高效的环境。通常标准的 序列化,例如 JSON,属于较慢的类型。我们将两者都包含在此处, 因为序列化/反序列化是一个非常、非常广泛的主题,其性能特征 因数据和实现的不同而存在极大差异。

对于活跃的 Criterion 套件,运行 ./run --bench napkin_math 以获取 正确的优化级别和 Linux 调优。在调试模式下编译时, 你无法获得正确的数值。该包装器内部已经使用了 sudo。 在受限的云镜像上,在调用它之前 运行一次 sudo sysctl -w kernel.perf_event_paranoid=-1。你可以通过添加新的套件 并填补空白来帮助这个项目。

注意: 当前的基准测试路径是 benches/ 中的 Criterion.rs。 src/main.rs 仍然是较旧的临时测试框架,并且是那些尚未完全迁移和重新验证的基准测试的权威来源。 当前的 Criterion 套件现在包括 blob_storagememory_readmemory_randomhashsyscallsortserializationcompression、 以及 compressed_memory_read。当前的 SSD 数据行是从较旧的 测试框架中刷新的,其中 NAPKIN_BENCH_FILE 指向 RAID0 本地 SSD 挂载点。 compressed_memory_read Criterion 基准测试是一个 BitPacker 整数解包 微基准测试;不应使用它来重写上述通用的 [11] 压缩/解压缩数据行。新的 serializationcompression Criterion 组是特定于工作负载的,尚未接入 上述通用的 README 数据行。 新的 blob_storage Criterion 组是可选启用且需要凭据的:设置 NAPKIN_GCS_BUCKET 和/或 NAPKIN_S3_BUCKET。GCS 和 S3 路径现在 都使用 AWS S3 SDK。GCS 端与 GCS XML 互操作端点通信, 需要 NAPKIN_GCS_ACCESS_KEY 加上 NAPKIN_GCS_SECRET_KEY。S3 端 使用 NAPKIN_S3_PROFILE 中的本地 AWS 配置文件(默认 tpuf-test)加上 NAPKIN_S3_REGION(默认 us-west-2)。 并发的 get_offsetsput_multipart 路径明确地扇出到 多线程 Tokio 运行时,因此当范围数量/对象数量足够高时,它们可以接近主机 NIC 限制。2026 年 3 月 9 日,同区域 1 GiB 单流 GET 在 S3 上达到了约 95 MiB/sm6id.12xlargeus-west-2a 中),在 GCS XML 上达到了约 190-200 MiB/sc4-standard-48-lssdus-central1-c 中)。在相同的机器上,显式的 并发范围 GET 在 S3 上达到了约 2.0 GiB/s,在 GCS 上达到了约 4.9 GiB/s,而分块 PUT 在 S3 上达到了约 1.8-1.9 GiB/s,在 3.3 GiB/s 在 GCS 上。AWS 自身的 S3 指南建议在饱和 10 Gbps 实例时,为每个并发请求预留约 85-90 MB/s 的预算,这与实测的 S3 单流结果非常接近。上述旧的 500 MiB/s 单流 blob GET 行在两家提供商上均未能复现,因此已下调为保守的通用 100 MiB/s。当前的 blob 存储工作重新验证了吞吐量,远多于首字节延迟; 上述的 50 ms / 150 ms 延迟单元格在添加专门的小对象 / 首字节时间探针之前,仍应视为粗略的 启发式值。 src/bin/s3_latency.rs 中现在有一个专门的小对象延迟探针。 运行 ./script/blob-latency s3./script/blob-latency gcs 以扫描 getputif_none_matchput_if_match,跨越默认的 8 KiB .. 8 MiB 大小阶梯,除了 if_none_match,它现在默认为一行 128 KiB,因为其延迟在小尺寸扫描中基本保持平坦。 当你想要更小或 特定提供商的运行时,覆盖 NAPKIN_BLOB_LATENCY_OPSNAPKIN_BLOB_LATENCY_SIZESNAPKIN_BLOB_LATENCY_IF_NONE_MATCH_SIZES。延迟探针现在默认每行墙钟 预算为 300 秒,收集在该时间内能容纳的尽可能多的样本。 使用 NAPKIN_BLOB_LATENCY_ROW_SECONDS 进行调优;可选地,使用 NAPKIN_BLOB_LATENCY_SAMPLE_CAP(或旧的 NAPKIN_BLOB_LATENCY_SAMPLES 别名)进行限制,当你想要更短的计数限制实验时。 list 操作现在默认播种一个更大的命名空间(100k 个键),并通过 start_after 测量每个样本一个随机化的 1000-键页面, 而不是反复扫描相同的小固定前缀。使用 NAPKIN_BLOB_LATENCY_LIST_NAMESPACE_KEYSNAPKIN_BLOB_LATENCY_LIST_KEYSNAPKIN_BLOB_LATENCY_LIST_SEED_CONCURRENCY 调整该形状。如果你还想要旧的 整个命名空间遍历,请将 list_full_scan 添加到 NAPKIN_BLOB_LATENCY_OPS。 对于对齐的范围读取延迟,./script/blob-random-range-latency 测量 128 KiB 对齐的形状,而 ./script/blob-random-range-latency-8m 测量同一 128 x 1 GiB 对象池上 8 MiB 对齐的形状。 ./script/blob-random-range-latency-8m-multipart 通过多部分上传使用 8 MiB 个部分来播种这些 1 GiB 源 对象,然后测量针对这些多部分边界的 8 MiB 对齐 读取。 memory_read 现在在 Criterion 中输出显式的 No SIMDSIMD 变体, 但 README 有意将它们合并为一行单线程和一行 多线程,以便于记忆。

我意识到该套件存在一些低效之处。我打算提升我在这方面的技能, 以确保这些数字是你在生产环境中可能榨取出的性能上限。我认为其中任何一项 与真实值的偏差超过 2-3 倍的可能性极低,这对大多数用户来说不应构成问题。

成本数字

应在各云服务商之间保持一致的大致数字。

项目数量$ / 月1年承诺 $ /月抢占式 $ /月按小时抢占式 $
CPU1$15$10$2$0.005
GPU1$5000$3000$1500$2
内存1 GB$2$1$0.2$0.0005
存储
├ 仓库存储1 GB$0.02
├ 对象存储 (S3, GCS)1 GB$0.02
├ 本地 HDD1 GB$0.05
├ 临时 SSD1 GB$0.08$0.05$0.05$0.07
├ 区域 HDD1 GB$0.1
├ 本地 SSD1 GB$0.2
├ 区域 SSD1 GB$0.35
网络
├ 同可用区1 GB$0
├ Blob1 GB$0
├ Ingress1 GB$0
├ L4 LB1 GB$0.008
├ Inter-Zone1 GB$0.01
├ Inter-Region1 GB$0.02
├ Internet Egress †1 GB$0.1
CDN Egress1 GB$0.05
CDN Fill ‡1 GB$0.01
Warehouse Query1 GB$0.005
Logs/Traces ♣1 GB$0.5
Metrics1000$20
EKM Keys1$1

† 这指的是离开云提供商的网络流量,例如从 GCP 向 S3 发送数据,或从 AWS 向客户端发送 HTML 的出口网络流量。

‡ 每次缓存填充都会产生额外的费用,其成本接近 blob 存储的写入成本(见下文)。

7 这是少数日志提供商之间的标准定价,但例如 Datadog 定价 不同,对摄入的日志收取 $0.1,并额外收取 $1.5 用于 7 天保留。

此外,对于 blob 存储(S3/GCS/R2/...),你会按每次读/写操作收费(文件数量较少且较大时更便宜):

1M1000
读取$0.4$0.0004
写入$5$0.005
EKM 加密$3$0.003

压缩比

这些数据来源于几个来源。 [3] [4] [5] 请注意,压缩速度(但通常不是压缩比)会根据算法和压缩级别(以速度换取压缩率)相差一个数量级。

我通常粗略估计,压缩比每增加 x 倍,性能会下降 10 倍。例如,我们可以在 英文维基百科上获得 2 倍的压缩比,速度约为 200 MiB/s,3 倍时约为 20MiB/s,4 倍时为 1MB/s。

内容压缩比
HTML2-3x
英语2-4x
源代码2-4x
可执行文件2-3x
RPC5-10x
SSL-2% [10]

技巧

  • 不要过度复杂化。 如果你的计算基于超过 6 个假设,你很可能把它变得比应有的更复杂。
  • 保留单位。 它们是良好的校验手段。 Wolframalpha 在需要帮助转换例如 KiB 到 TiB 时 提供了出色的支持。
  • 使用指数进行计算。 许多粗略估算 仅使用系数和指数,例如 c * 10^e。你的目标是 在数量级上正确——那只是 ec 重要得多 少。只关注单位数系数和指数会让 在餐巾纸上计算容易得多(更不用说避免了写所有的零)。
  • 执行费米分解。 写下你可以猜测的内容,直到你 能够开始暗示答案。当你想知道日志存储的成本时, 你会想知道一行日志有多大,每秒有多少行, 那要花多少钱,等等。

资源