局部性与乐观
冯·诺依曼架构中,指令和数据均存储在内存中,彻底打开了计算机“通用”的大门。这个结构中,“线性数组”内存天生携带了一个涡轮:局部性。
局部性分类
空间局部性
空间局部性是最容易理解的局部性:如果一段内存被使用,那么之后,离他最近的内存也最容易被使用,无论是数据还是指令都是这样。举一个浅显易懂的例子:
循环处理一个 Array,当处理完了 [2]
之后,下一个访问的就是 [3]
,他们在内存里是相邻的。
时间局部性
如果一个变量所在的内存被访问过,那么接下来这一段内存很可能被再次访问,例子也非常简单:
$a = [];
if ( !$b ) {
$a[] = $b;
}
在一个 function
内,一个内存地址很可能被访问、修改多次。
乐观
“乐观”作为一种思考问题的方式广泛存在于计算机中,从硬件设计、内存管理、应用软件到数据库均广泛运用了这种思考方式,并给我们带来了十分可观的性能收益。
乐观的 CPU
第一篇文章中的三级缓存和第二篇文章中的分支预测与流水线,均是乐观思想的代表。
乐观的虚拟内存
虚拟内存依据计算机内存的局部性,将磁盘作为内存的本体,将内存作为磁盘的缓存,用很小的性能代价带来了数十倍并发进程数,是乐观思想的集大成者。
乐观的缓存
Java 经典面试题 LRU 缓存实现,也是乐观思想的一种表达。
同样,鸟哥的 yac 也是这一思想的强烈体现。
设计 Yac 的经验假设:
- 对于一个应用来说, 同名的 Cache 键, 对应的 Value 大小几乎相当。
- 不同的键名的个数是有限的。
- Cache 的读次数, 远远大于写的次数。
- Cache 不是数据库, 即使 Cache 失效也不会带来致命错误。
Yac 的限制:
- key 的长度最大不能超过 48 个字符. (我想这个应该是能满足大家的需求的, 如果你非要用长 Key, 可以 MD5 以后再存)
- Value 的最大长度不能超过 64M, 压缩后的长度不能超过 1M。
- 当内存不够的时候, Yac 会有比较明显的踢出率, 所以如果要使用 Yac, 那么尽量多给点内存吧。
乐观锁
乐观锁在并发控制和数据库设计里都拥有重要地位,其本质就是在特定的需求下,假定不会冲突,冲突之后再浪费较长时间处理,比直接每次请求都浪费较短时间检测,总体的性能高。乐观锁在算法领域有着非常丰富而成熟的应用。
乐观的分布式计算
分布式计算的核心思想就是乐观,由 95% 可靠的 PC 机组成的分布式系统,起可靠性也不会达到 99.99%,但是绝大多数场景下,99% 的可靠性就够了,毕竟拿 PC 机做分布式比小型机便宜得多嘛。下一篇文章我会详细介绍分布式计算的性能之殇,此处不再赘述。
乐观的代价
乐观给了我们很多的好处,总结起来就是一句话:以微小的性能损失换来大幅的性能提升。但是,人在河边走,哪有不湿鞋。每一个 2015 年 6 月入 A 股的散户,都觉得大盘还能再翻一番,岂不知一周之后,就是股灾了。
乐观的代价来自于“微小的性能损失”,就跟房贷市场中“微小的风险”一样,当大环境小幅波动的时候,他确实能承担压力,稳住系统,但是怕就怕突然雪崩:
- 虚拟内存中的内存的局部性突然大幅失效,磁盘读写速度成了内存读写速度,系统卡死。
- 分布式数据库的六台机器中的 master 挂了,系统在一秒内选举出了新的 master,你以为系统会稳定运行?master 挂掉的原因就是压力过大,这样就会导致新的 master 瞬间又被打挂,然后一台一台地继续,服务彻底失效。
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.