低延迟系统的 11 个最佳实践

英文原文:11 Best Practices for Low Latency Systems

自从Google发布额外的一个500ms延迟将减小20%的流量以及亚马逊发现额外的100ms延迟会使销售量降低1%已经8年了。此后,开发者们一直奋战在延迟曲线的底部,甚至前端开发者们都在压缩JavaScriptCSS以及HTML来争取分毫时间。如下是各类低延迟系统设计时需牢记在心的最佳实践的一个概览。大多数这些建议考虑的是逻辑上极端,能够权衡使用。(感谢在Quora上问这个问题的匿名用户,这让我把个人想法写了下来)。css

选择正确的语言

脚本语言不要使用,尽管它们愈来愈快,当你处理关键事务像拿掉进程的最后几毫秒时间时,你处理不掉解释型语言的开销。此外,你会想要一个强有力的记忆模型来进行无锁编程,因此你应该看Java、Scala、C++11或Go。 html

把一切放在内存里

I/O会是延迟主因,因此确保你的全部数据在内存中。这一般意味着管理内存中的数据结构以及维护现有记录,这样你在重启机器或进程后可以重建以前的状态。维持记录的选择包括BitcaskKratiLevelDBBDB-JE。或者你也能够本地运行一个像redisMongoDB(memory >> data)这样的内存型数据库。但须要注意的是,在它们后台同步数据到硬盘crash时你仍旧可能丢失一些数据。前端

确保数据和处理程序的位置

网络跳数比磁盘寻道要快,但即便这样经过网络也会增长不少开销。理想状况下,数据应当彻底在主机的内存中。像AWS云中几乎提供了1/4TB的内存,物理服务器提供多个TB如今也很常见。若是你须要运行在多个主机上,你应当确保数据和请求被适当的划分,使得在服务请求时全部必要的数据都在本地。 html5

保持系统未充分使用java

低延迟老是须要有资源来处理新的请求。不要试图运行到你的软硬件资源的极限。总要有一些峰值储备用于突发状况。git

保证内容切换最小化github

内容切换是你正在运行的计算工做超过你拥有的资源的一个信号。你须要限制你的线程数使之与你系统的内核数相匹配,确保每一个线程与它的主线程相关联。web

确保读操做的连续性redis

各类形式的存储,无沦是轮转式的,仍是基于闪存的或内存的,顺序使用的时候,它们的性能都会好一些。当进行内存的连续读操做时,你将会触发RAM级和CPU缓存级的预读处理。若是预读操做顺利的完成,那么下一步所需的数据在使用前都已在L1级的缓存中。促进这一处理的简便方法是:大量的使用原始数据类型的或结构体数组。不惜一切代价避免使用基于链表或者对象数组的随动指针。 算法

批量处理写入操做

这个听起来有背常理,可是你能够经过批量处理写操做得到明显的性能提高。然而,总有一些错觉:这就意味着在写入操做前系统须要等待任意的时间。相反地,线程在作输入/输出操做时会紧凑地循环。每次写操做都会在上一次操做完成后对到达的数据批量的处理。这种机制确保了系统快速的响应和良好的适应性。

优化缓存

在各个位置的优化中,内存的快速访问成了瓶颈。把线程与它们的主线性相关联有助于下降CPU缓存污染;连续性输入/输出处理,一样有利于缓存中的预加载。除此以外,你可使用基本数据类型来下降内存的占用量,这样就能够有更多的数据加载到高速缓存中。另外你可参阅高速缓存参数无关算法,它经过递归的分解数据直到数据与缓存大小匹配,而后进行所需的处理。

尽量多的使用非阻塞模式

使用非阻塞模式并使用不受约束的数据结构和算法。每次你在使用锁时都要深刻到栈的操做系统层去处理锁,这是件使人头痛的事。一般若是你知道本身正在作什么,你得理解JVM、C++或者Go的内存模型才能够去应付锁的相关处理。

尽量多的使用异步

任何处理特别是不须要建立响应输入/输出处理应当在关键路径以外处理。

尽量多的并行处理

任何处理特别是能够并行操做的输入/输出处理应当并行的处理。例如你的高可用性策略包括把在磁盘中写入事务日志和把事务发送到二级服务器,这些动做都查能够并行处理的。

参考资料:

全部内容均来自于LMAX的Disruptor项目,您能够仔细研读或关注Martin Tompson的分享。

其它的博客:

相关文章
相关标签/搜索