几年前的一篇文章了,关于程序访问存储器所需时间的文章。对于程序访问cache、内存、硬盘、网络等设备,只是大概知道访问哪些设备快,哪些设备慢;具体多块或多慢,没有明确概念。现代的设备访问速度已经超过几年前,但是了解这些数值仍然有意义。
首先明确一下时间单位之间的换算关系:
秒(s)、毫秒(ms)、微秒 (μs)、纳秒(ns)之间关系为:
1
s =
写硬盘操作“昂贵”
- 数据存储是事务类型:写操作要求访问硬盘
- 访问硬盘意味着磁盘寻道
- 经验法则:每次寻道耗时10ms
- 简单的数学计算: 1s / 10ms = 100 seeks /sec,即每秒最多100次寻道
- 具体依赖: 数据的大小和是否批量读取
读硬盘操作“便宜”
- 读操作不是事务类型
- 数据只需从硬盘读一次,之后很容易命中
- 后续的读直接从内存读取
- 经验法则: 从内存读1M数据需要250μs
- 简单数据计算: 1s / 250μs = 4GB/S,即每秒读4GB
- 对于1M的数据,每秒可以取4000次
各种数据
下面这组数据出自Jeff Dean在Google全体工程大会的报告。
- L1 cache的引用0.5ns
- Branch mispredict 5ns
- L2 cache的引用 7ns
- Mutex lock/unlock 100ns=0.1μs
- 引用主内存 100ns=0.1μs
- 使用Zippy压缩1kb数据 10,000 ns=10μs
- 1Gbps网卡,发送2kb数据 20,000ns=20μs
- 从内存连续读1M数据 250,000ns=250μs
- 一个数据中心内的round trip 500,000ns=500μs
- 磁盘寻道10,000,000ns=10ms
- 从网络连续读1M数据 10,000,000ns=10ms
- 发送包 CA->Netherlands->CA 150,000,000ns=150ms
经验
- 写操作比读操作慢40倍。
- 全局共享数据代价昂贵,这是分布式系统中基本的限制。在频繁写对象的操作中锁冲突降低了性能,使得事物变为序列操作,变慢。
- 构建写扩展
- 优化少量的写冲突
- 广度优化。使得写操作尽可能并行。
下面这张图比较形象展示了数值之间的对比关系:
参考
Numbers Everyone Should Know
Latency Numbers Every Programmer Should Know