《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 mvoloskov.hashnode.dev/scalable-architecture-without-magic-and-how-to-build-it-if-youre-not-google 「hashnode」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

本文为实现可扩展架构提出了几个原则:使用合适的工具。不要把写入优先和读取优先数据库弄混了。什么东西都配置多份。要实现多份配置,就必须让它们保持无状态。不要让后端完成数据库的工作,那样总是更慢。

可扩展性被认为是一个很难解决的问题。人们总是把它看成是一种神奇的东西,是用神秘而特殊的工具完成的,只有身价百万的大块头才能使用。这当然不是真的。其实,那并没有什么神奇之处——那也不过是用普通编程语言编写的普通代码。

首先,要针对工作选择合适工具。你已经看过基准测试了,你知道有些语言在某些方面表现得更好。有些数据库的读取速度更快,而有些数据库的写入速度更快。即使你已经为任务选择了合适的技术栈,一台服务器也是不够的。这就是有趣的地方。当然,你可以直接从不同的 AWS 服务级别中进行选择。但是,如果想知道其中的原理,你就应该知道如何在裸金属上实现可扩展的设置。

基本原则

选择恰当的工具

不同的编程语言适用于不同的任务。

例如,Python 有非常丰富的语法糖,非常适合处理数据,而且代码简短而富有表现力。但为了实现这一点,它需要运行在解释器上,在默认情况下,这比编译后在裸金属上运行的 Go 或 C 是要慢的。

NodeJS 的外部工具可能是最丰富的,但它是单线程的。要在多核机器上运行 NodeJS,必须使用像 PM2 这样的东西,但这样的话,就必须保持代码是无状态的。

数据库也是一样。SQL 提供了图灵完备性来查询和处理数据,但这是有代价的——没有缓存,SQL 几乎总是比 NoSQL 慢。

除此之外,数据库通常是读取优先或写入优先的。这就意味着,它们中的一些在写入数据时速度更快,而另一些在大量读取时性能更佳。

例如,对于需要大量写入、偶尔读取的分析及其他任务,你可能想要选择“写入优先”的数据库,如 Cassandra。

对于显示新闻这样的读取优先任务,最好使用像 MongoDB 这样的东西。

如果两者都需要,就安装两个数据库!这不是不行。这不会造成什么破坏。事情就应该这样做。

多服务器

当一台计算机不够用的时候,可以用两台。当两台不够用的时候,可以买三台,以此类推。

但也有一个陷阱:从 1 到 2 比从 2 到 3 或从 10 到 20 要难得多。

要使用多台计算机,后端应该是无状态的。这意味着你必须将所有数据都存储到数据库中,而后端不保存任何数据。这就是函数式语言在后端如此流行的原因,这也是 Scala 被发明的原因。函数代码默认是无状态的。

无论如何,不同服务器的行为应该完全相同。如果你有大量的有状态服务器,那么根据定义,对相同的输入,它们很容易返回不同的数据作为响应,因为有两个事实来源:数据库和服务器状态。相信我,你不会想让这种事情发生的。

尽快实现无状态。最好从一开始就选择无状态。如果你在使用 NodeJS 和 PM2,如果你想让 PM2 帮你增加运行时以实现负载均衡,那你就必须让代码保持无状态。

负载均衡器会将请求重新路由到最空闲的服务器。显然,对于相同的请求,服务器应该提供完全相同的响应。这就是我们转向无状态的原因。对 NodeJS 来说,PM2 是一个很好的负载均衡选项。如果你用的不是 Node,就选择 Nginx。

会话?把它们保存在 Redis 中,并让所有服务器都可以访问。

缓存和速率限制

想象一下,每 100 毫秒针对每个用户做同样的计算。这将使服务器很容易受到 Slashdot 效应的影响——基本上只是用户访问数据就会导致 DDOS。

增加缓存中间件。只有第一个用户将触发数据查询,其他所有用户将直接从 RAM 接收完全相同的数据。

这也有缺点——默认情况下,数据会过期。通常,缓存中间件允许设置缓存重置时间,数据最终会刷新。

考虑用户和他们的需求,配置相应的缓存。永远不要缓存用户输入。只有服务器输出应该被缓存。

Varnish 是一个很好的 HTTP 响应缓存选项,所以它可以用于任何后端。

即使有了缓存,每 10 毫秒就会出现不同的请求,也可能会导致服务器宕机,因为服务器会为它们计算不同的响应。这就是为什么你需要一个速率限制器——如果距离上次请求的时间不够长,正在进行的请求将被拒绝。这将使你的服务器保持活跃。

划分职责

如果你正在使用 SQL 数据库,并且仍然使用后端计算外键,那么你没有充分利用数据库的能力。只需设置记录之间的关系并允许数据库为你计算外键——查询规划器总是比后端更快。

后端应该有不同的职责:哈希、从数据和模板构建网页、管理会话等等。

对于任何与数据管理或数据模型相关的内容,将其作为存储过程或查询移到数据库中。

大数据量

即使是使用数据库集群,最大容量也受限于服务器的主板。你不能只是把无限多的硬盘放在那里。如果想要无限增长,除了使用分布式数据库之外,没有其他选择。它将数据存储在不同的服务器上,最大容量接近所有服务器容量的总和。如果存储空间不足,只需添加另一台服务器即可。

通过主从复制,你可以将 DB 加倍并实现负载均衡,但容量不会无限增长。

可能存在的瓶颈

  • 单线程、有状态、不可扩展的服务器。为了实现负载均衡及运行多台服务器,代码必须是无状态的。
  • 服务器做数据库的工作。将任何与数据相关的工作移到数据库中。
  • 单数据库实例。实现数据库负载均衡,请选用集群。
  • 把读取优先和写入优先搞混了。分析常见任务,有针对性的使用不同类型的数据库。
  • 距离客户端太远。请使用 CDN。

设置举例

小猫

图片

图片

这是你一个晚上就可以在 LAMP 技术栈上构建的基本设置。它是有状态的——它在内存中存储会话和其他杂七杂八的东西。你猜对了,它根本无法扩展。但是,它仍然非常适合小型周末项目。

  • 数据:GB 级
  • 用户:几千
  • 瓶颈:可用性。单服务器,很容易受 Slashdot 效应影响
  • 工具:常规的 LAMP 技术栈

大猫

图片

我们添加了缓存。虽然速度提升了,但由于架构是有状态的,所仍然不可扩展。当你的周末项目用户增加时,你应该这样做。

  • 数据:GB 级
  • 用户:几万
  • 瓶颈:有状态服务器。即使有了缓存,服务器仍是不可扩展的
  • 工具:MongoDB、Express 作为速率限制器和内存缓存

猎豹

图片

图片

这是可扩展的!你可以拥有任意数量的服务器。现在,你可以处理所有可能导致“大猫”宕机的请求,但数据库仍然是运行单个实例,必须处理所有请求。尽管如此,它还是非常适合小型项目、电子商店或类似的东西。

  • 数据:TB 级
  • 用户:十几万
  • 瓶颈:单数据库。使用函数式语言,服务器是可扩展的。但是单个 DB 可能无法处理大量的请求
  • 工具:Go、Redis 缓存、MongoDB

老虎

图片

图片

这个架构速度很快,而且可扩展。看它有多漂亮。DB 和后端都做了负载均衡。这里的瓶颈是,当你运行单个服务器或数据中心时,海外用户可能会面临高延迟,因为他们距离很远。但是,这种设置仍然可以应对许多用户,非常适合新闻网站。

  • 数据:数百 TB
  • 用户:上百万
  • 瓶颈:距离。服务器速度很快,但如果用户距离很远,速度也可能会慢
  • 工具:Go、Redis + Cassandra + MongoDB

狮子

图片

图片

这是一个 CDN——一种完全不同的东西。你在世界各地有多台服务器,它们可以像主服务器一样为请求提供服务。这不像缓存,它们是全功能的。

来自不同大洲的用户通过 DNS 进行隔离。

尽管服务器速度很快,但你仍然受限于一台服务器的容量。你的数据库是主数据库的副本,因此你受限于主数据库的容量。

这非常适合托管提供商、大型电子商务之类的东西。

  • 数据:数百 TB
  • 用户:上千万
  • 瓶颈:大数据量。使用主从复制,无法处理大数据量,你受限于一台 DB 服务器的容量
  • 工具:同上,但 MongoDB 是集群

齿虎

图片

图片

这是终极形式。有了 Riak 这样的图形数据库,容量将不再受限。当存储资源不足时,你只需购买一个新的存储服务器并将其添加进去。

非常适合创建像谷歌或 Facebook 那样的应用。

  • 数据:无限
  • 用户:全球用户
  • 瓶颈:价格。其成本就像太空项目
  • 工具:Go、Riak

总结

我们回顾了几乎每类项目的一些最常见的设置。不一定非要使用上述设置——根据自己的需要进行设计。只要记住,每个工具都有它的用途,务必选择适合你的工作的合适工具。

保证可扩展,保证无状态!

文章目录
  1. 1. 基本原则
    1. 1.1. 选择恰当的工具
    2. 1.2. 多服务器
    3. 1.3. 缓存和速率限制
    4. 1.4. 划分职责
    5. 1.5. 大数据量
    6. 1.6. 可能存在的瓶颈
  2. 2. 设置举例
    1. 2.1. 小猫
    2. 2.2. 大猫
    3. 2.3. 猎豹
    4. 2.4. 老虎
    5. 2.5. 狮子
    6. 2.6. 齿虎
  3. 3. 总结