提升可伸缩性的 8 项最佳实践

Wille Faler 曾提出 八项提升系统可伸缩性和性能的最佳实践,核心观点包括减少数据库操作、合理使用缓存、降低网络通信开销等。以下是这八项实践的详细解读。

1. 减少数据库操作

尽可能远离数据库。如无必要,不要打开数据库连接或者启动事务。数据库交互通常是系统性能的瓶颈,减少交互次数能显著提升效率。

2. 缓存带来的显著变化

缓存能极大地减轻数据库的负担,特别是当系统通过只读方式访问数据库时。缓存层级的一般优选顺序为:内存缓存优于磁盘缓存,而磁盘缓存又优于远程缓存关系型数据库

3. 尽可能缓存粗粒度对象

缓存粗粒度对象“可以省去遍历 N 个缓存单元的 CPU 开销和时间。而且,获得完整的对象关系图也省去了对象关系图的装配时间。”这意味着在缓存设计时,应优先考虑存储聚合后的数据而非细碎的单个字段。

4. 不要永久性保存瞬态信息

避免在数据库里面存储瞬态数据,比如登录的会话信息(Session)。

“状态怪物”是一只非常危险的怪兽。根据一般的规律,在持久性存储设施(数据库、磁盘等)里面只需要保存真实的、必要的、关键的,以及需要备录的业务数据,其他的都不在此列。

5. 位置、位置(Location, Location, Location)

把数据放在靠近需要使用它们的地方。相对于经过负载均衡器、Web 服务器、应用服务器和数据库多个环节,直接经过负载均衡器和 Web 服务器从 CDN 获取数据要快一些,开销也更小。就近原则是降低延迟的关键。

6. 约束对有限资源的并发访问

如果多个请求需要访问同样的资源,执行同样的计算,最好是只处理首个请求,让其他的请求等待计算完成后直接使用最终结果。让所有的线程去访问同一个资源只会减缓处理的速度。这种模式常用于防止缓存击穿或重复计算。

7. 分阶段地、异步地处理

根据处理过程的异步性,把该过程分散成单独的步骤,通过队列来隔离;每个步骤使用有限数量的工人线程进行处理:这样经常会给可伸缩性和性能同时带来奇迹般的变化。

通过引入消息队列和解耦步骤,系统可以更好地应对流量峰值。

8. 使网络延迟最小

尽可能使应用系统不去做远程访问,因为网络通信要明显慢于内存访问。本地调用永远快于远程过程调用(RPC)。

社区讨论与补充

针对上述实践,社区专家也提出了一些补充观点:

  • 关于减少数据库操作Steve M. Ciske 对减少数据库操作的做法表示了忧虑:

    对于减少数据库操作的做法,我持谨慎态度。我见多了人们走向另一个极端,把所有的东西都放在应用层。
  • 关于缓存层级Paweł Stradomski 认为远程内存缓存要快于本地磁盘缓存,Faler 也表示了同意:

    远程主机(通过网络连接)缓存可能会快于本地磁盘缓存。如果不考虑网络查找的时间,从磁盘顺序读取数据比从远程主机的内存里面读取数据要慢三倍。

延伸阅读

说明:本文引用的最佳实践最初发布于 2009 年。虽然核心架构原则(如缓存、异步、就近访问)至今仍具有指导意义,但具体的技术实现细节(如缓存工具、数据库类型、网络环境)可能已随技术发展而演变,请结合当前技术栈酌情参考。