1. 选择正确的语言
脚本语言不能使用,尽管它们可以运行得更快更快,当你寻找对几毫秒延迟都不能忍受时,就不能有解释语言的开销,你希望有一个强大的内存模型,能够无锁编程,可选语言有Java Scala和C 11或Go。
2. 将一切放在内存中
I/O会杀死你的延迟,确保你所有的数据都在内存中,这就意味着你自己要管理你的数据结构,以及维护一个持久日志,这样,你才能在机器重新启动后重建原来内存状态,持久日志的选择有: Bitcask, Krati, LevelDB 和 BDB-JE, 当然,你也可以运行一个本地持久化的内存数据库如 redis or MongoDB(memory >> data),请注意后台在将数据同步到磁盘时可能会导致一些数据崩溃,需要进行松散化(Loose).
3. 让数据和处理同位colocated
Network hops are faster than disk seeks(网络连接要快于磁盘寻轨) ,但即使如此,他们也会增加大量的开销。理想情况下,您的数据应该完全适合一台主机上内存。如果你需要多台主机上运行,你应该确保你的数据和请求得到正确的分区,满足特定的请求的所有必要的数据来都是在本地可用。
4. 让系统未充分利用
低延迟要求总是有资源能处理请求。不要试图让你的硬件/软件处于满负荷极限运行状态。留下一些头寸供使用。
5.让上下文切换最小化
当你使用有限的资源进行更复杂的计算工作时,CPU会忙于在有限资源之间不断切换。你要根据CPU核数限制线程数,以便使每个线程能为自己的核心工作。
6.保持读取的顺序性
所有形式的存储空间,无论是基于闪存或内存,按顺序使用性能会显著改善。当发出连续读取内存,将触发在内存级别的预取,如同在CPU缓存级别一样。如果处理得当,则下一个数据在你需要它之前将永远首先存在L1高速缓存中。这个简单之道能够帮助处理大量数组或原始类型的重量级别使用。进一步说,应该不惜一切代价避免使用链表或通过对象的数组。
7.让你的写操作批量化
这听起来似乎有悖常理,但你可以通过批量写入确实可以获得在性能上的显著改善。然而,有一种误解,认为这意味着该系统应在任意数量批写操作之前有一个暂停等待的时间。相反,一个线程要旋转spin紧密循环执行I/ O。上一批写操作完成后,将立即有一批数据写操作发生,这是一个非常快速和自适应系统。
8 .尊重你的缓存
在所有这些优化的地方,内存存取将迅速成为一个瓶颈。将线程pin住自己的核心有助于降低CPU缓存污染,顺序I / O也有助于预加载缓存。除此之外,你应该保持最大容量下使用的原始数据类型,以便更多的数据放入缓存。调整缓存算法保证所有数据在在高速缓存中。
9.尽可能非堵塞
与非阻塞 零等待的数据结构和算法成为朋友。每次当你用锁时,堆栈将深入到操作系统进行调解,每一次锁定是一个巨大的开销。通常情况下,如果你知道你在做什么,你可以通过了解JVM,C11或Go的内存模型绕过锁。
10.尽可能异步
任何处理,特别是I / O并不是对于构建响应是绝对必要的话,那么应该在关键执行路径以外异步实现。
11.尽可能并行
任何处理,特别是I / O如果可以并行发生,尽量并行进行。例如,如果您的高可用性策略包括交易记录到磁盘和发送交易到辅助服务器的操作,这些都可以并行发生。