PlanetScale让768台服务器像一台一样运行
通过数据库分片将数据与查询分布到多个主节点,并配合智能体路由器与网络负载均衡器,使768台服务器对应用呈现单一数据库视图,从而解决了写入瓶颈、数据容量限制及备份复杂度问题。
数据库几乎总是最难扩展的基础设施组件。单个数据库服务器无法满足这样的需求,所以必须通过数据库分片,将查询和数据分散到许多服务器上。
数据库分片是扩展Postgres或MySQL数据库、处理超过几TB数据的最佳方法。接下来,看看如何从小型单节点数据库,发展到分布在四个分片上的几TB数据库,再到分布在768个服务器上、存储1PB数据的数据库。
成长的烦恼
要理解为什么分片是扩展关系数据库的必要组成部分,需要先了解一些可扩展性较差的方法的瓶颈在哪里。 先考虑一个简单的应用程序架构。 你用过的大多数应用,要么现在就是这样运行的,要么至少在其生命早期是这样。客户端设备上的软件,通过互联网连接到应用程序服务器。这个服务器位于数据中心,负责处理身份验证、页面加载以及所有服务器端逻辑。所有持久数据,比如用户账户、帖子、设置和消息,都存储在数据库服务器里,并从那里检索(这里的“数据库服务器”通常是Postgres或MySQL,但文章重点在Postgres)。 即使使用大型数据库服务器(几十个CPU核心、几百GB内存),瓶颈也会很快出现。通常,要么是高查询量导致的CPU限制,要么是大量读写导致的I/O限制(IOPS)。 通用可扩展性定律很好地总结了这一点: 简而言之,USL指出,资源争用会导致可扩展性随着资源增加而呈次线性增长;在某个点上,不一致性甚至会导致性能下降。Postgres也是如此,和任何试图在更大服务器上跨线程或进程扩展的软件系统一样。 至少在短期内,一种解决方法是利用只读副本。 在这个配置中,原始服务器作为主服务器,再加上一些副本,如上所示。 主节点会向每个副本发送连续的消息流,确保它们及时了解主节点上的数据变化。写入操作(INSERT、UPDATE、DELETE)只能发生在主数据库上。如果允许任何服务器写入,最终可能会出现数据冲突。解决这个问题需要复杂且缓慢的共识算法——虽然可行,但在大多数情况下,对性能最优并不理想。 不过,应用服务器可以向副本发送读取查询(SELECT)。由于大多数应用读取的比例远高于写入,这提供了更多的可扩展性(副本对高可用性和数据持久性也很必要,即使查询流量不需要它们)。 数据库可以通过添加副本来扩展,以处理更多流量。一个极端的例子是OpenAI,它在单个主节点上使用了50个副本。 但垂直扩展服务器(增加CPU/内存)和添加副本,只能让你走到一定地步。有些瓶颈是没法这样解决的:1)写入仅限于一台服务器
如果写入量足够高,任何额外的只读副本都无法缓解问题。在Postgres确认写入已提交之前,它必须在预写日志(WAL)中记录这个更改,并把日志刷新到持久存储。WAL是主节点上所有连接之间的共享资源,这本质上就成了整个数据库的单一写入瓶颈,哪怕你有几十个副本。2)副本不会增加数据容量
副本是主数据的完整拷贝,包括所有索引。添加副本,只是提供了更多执行读取的位置,并没有分布数据。3)备份
备份是数据持久性和RPO/RTO保障的重要部分。由于节点与存储之间通信的带宽限制,把大型单体数据库备份到对象存储,可能需要几小时甚至几天。对很多依赖频繁、可验证备份的组织来说,这个时间长得让人无法接受。 处理这个问题最有效的方法,就是分片。分片,带“d”
分片通过把数据和查询分布到许多不同的主节点上,完美解决了这三个瓶颈。对于数据来说,单个节点能存储的数据量有限,写入吞吐量也有限,分片正好解决了这个问题。对于查询来说,网络互连和CPU一次只能处理这么多查询,分片也分担了压力。 分片对超过几TB数据的所有规模都有用。比如,对于2TB的数据,可以选择一个带四个分片的设置,每个分片存储500GB,处理总查询流量的四分之一。当需要存储PB级数据(一百万GB)时,就需要更多分片了。这种情况下,可以用256个分片,每个分片有一个主节点加两个副本,每个负责存储约4TB。这需要256乘以3,也就是768台服务器! 如果没有一个好的系统,这会大大增加应用后端的复杂性。这么多事情同时发生,系统要怎么……- 决定哪些数据发到哪个服务器?
- 决定哪些查询发到哪个服务器?
- 处理需要同时与多个分片交互的查询?
- 在这个分散的数据库里做备份?
- 监控整个系统的健康状况?
- 响应失败的服务器?
智能体层
这里几个关键部分中,最重要的就是智能体层。 智能体是位于两个服务之间的中间件服务器。在我们的例子里,这两个服务是应用服务器和数据库服务器。 智能体经常和Postgres数据库一起使用。即使没有分片,它们对连接池和请求排队也很有用。对于常规(未分片)Postgres,PgBouncer是一种流行的智能体,能在较少的直接Postgres连接上复用1000个应用连接。 PgBouncer的目标很简单:接受来自大量客户端的大量连接,通过它与Postgres持续维护的较小连接池来路由这些连接。查询队列在流量激增和数据库故障转移期间特别有用,当新的主节点上线时,请求就能恢复。如果想了解更多,有关于PgBouncer的完整博客。 对Postgres进行分片,需要更复杂的智能体。最大的区别在于,除了多路复用和缓冲外,智能体还必须了解数据如何在服务器间分布,并把SQL查询路由到正确的分片。所以,常被称为路由器。 插入数据时,路由器必须知道数据的分布方式。这叫分片策略。 一种常见的方法,是根据id列的哈希值对传入行进行分片。插入这样一行数据到数据库时: 四个分片,每个被分配一个负责存储的ID范围,路由器把插入操作发送到正确的分片。插入先发送到路由器,在路由器里计算每个ID的哈希值,然后转发到正确的分片。 说到读取,有些查询很简单,路由器直接把它们转发到单个分片。 这种情况下,路由器需要做的,就是维护用户ID在哪些服务器中的内部映射,然后转发查询。根据上面的例子,这会发到第一个(最上面)分片。 有些情况就复杂多了。 这些范围ID的用户分布在多个分片中。路由器必须了解数据拓扑,制定一个计划,把查询分发到可能包含匹配结果的所有分片,把结果聚合回路由器,再把完整结果集发送给客户端。 最终,这意味着路由器本身必须内置完整的查询解析器和路由规划器。 路由器必须能在一个系统中执行查询解析、规划、连接池和缓冲。复杂的软件,要做到好可不简单。它是怎么知道的?
每个数据库都独一无二,有自己的架构、表和查询模式。那么,路由器怎么知道哪些数据和查询该去哪? 在Neki和Vitess里,这些通过代表系统数据拓扑的JSON文件来指定。Vitess的VSchema和Neki的数据拓扑,给工程师提供了极大的灵活性,能精确描述表和查询应该怎么分布。这里是一个为用户表指定分片方案的简化示例: 这个元数据存储在路由器里,告诉路由器使用user_hash分片索引,在id列上对用户表进行分片。这个user_hash分片索引,用的是路由器的内置值哈希。对于每个传入行,它会对ID进行哈希运算,然后用这个结果把它发送到正确的分片去存储。 由于这一切都是通过文本和JSON传给路由器的,AI智能体在这个配置和优化环节就特别适合。多个智能体,一个数据库
在跨越768台服务器的256个分片、每秒数百万次查询的规模下,没办法通过单个智能体来路由所有流量。需要很多个,可能是10个,也许是100个,具体取决于流量情况。 依然希望应用把它视为单个服务器。这就是网络负载均衡器(NLB)发挥作用的地方。 NLB的工作很简单:允许通过单个主机/IP进行连接,把每个连接分配到多个目标之一。这样,流量就在路由器之间实现了分配。一旦分配,连接在其生命周期内会一直保留在同一智能体上。 有些情况下,不需要NLB。去掉NLB会稍微增加应用服务器连接逻辑的复杂性,因为必须知道每个路由器的主机,但消除了网络跃点,能把往返延迟降到最低。完整图片
现在,所有部件都就位了,让存储1000TB数据的768台服务器,在应用里显示为一个整体数据库。- 应用服务器被告知“连接到位于mydb.pscale.com的数据库”
- 执行DNS查找,返回NLB的IP地址:123.152.100.4
- 应用请求连接到123.152.100.4的数据库
- 这首先通过NLB路由连接,然后路由到N个智能体之一
- 应用开始发送数据库查询,请求经过应用 -> NLB(可选) -> 智能体 -> 分片。复杂的路由逻辑对应用来说完全透明(为简化起见,NLB在下面没有显示)
其他一切呢?
只触及了Neki和Vitess等分片系统提供的所有功能的表面。还有很多有趣的细节:分片数据的最佳方法是什么?分片数据库怎么处理故障?分片数量怎么改?如何同时跨256个分片做备份? 敬请期待更多内容。 快乐分片。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
SQL数据库视图简化开发人员编码的实用方法
视图适合封装固定逻辑(如固定时间窗口、静态状态过滤)和固定JOIN关系,不宜用于需动态传入参数(如用户ID、日期范围)的查询。视图性能取决于底层索引,而非视图本身。ALTERVIEW仅更新元数据,会短暂阻塞新查询启动,应避开高峰期操作。
MySQL decimal使用常见问题及解决方法
MySQL中的DECIMAL类型用于精确数值计算,通过DECIMAL(M,D)定义精度与标度。常见问题包括精度设置不当导致溢出、计算时精度溢出、插入格式错误等。优化建议:合理设置M和D,可用BIGINT存储分单位,关键列建索引,保持版本更新。
MySQL大字段TEXT建立索引导致的性能下降解决方案
TEXT字段无法直接建立常规B+树索引,前缀索引不支持左模糊查询,全文索引受词长、中文分词和更新延迟限制。高效替代方案是使用MD5摘要索引和垂直拆分,将TEXT字段分离到独立表,主表采用DYNAMIC行格式,避免溢出页IO问题。
金仓数据库迁移避坑指南:从未被质疑的左连接隐患
迁移至金仓KES时,LEFTJOIN若在WHERE中过滤右表非空列,将会触发外连接消除,导致数据结果减少。正确做法是将过滤条件置于ON子句中。金仓KES与主流数据库行为一致,务必通过EXPLAIN仔细检查执行计划,以确保连接语义正确。
PostgreSQL与MySQL数据库日志机制深度对比
PostgreSQL仅使用一套WAL日志,就同时实现了MySQL的redo、binlog和undo的全部功能,而MySQL因插件式架构需要三套日志并依赖两阶段提交保证一致性。其多版本并发控制通过追加写实现,无需单独的undo日志,但需要定期执行VACUUM操作清理死元组,防止表膨胀。
- 热门数据榜
相关攻略
2026-07-18 22:24
2026-07-18 22:22
2026-07-18 22:22
2026-07-18 22:22
2026-07-18 22:22
2026-07-18 22:05
2026-07-18 22:05
2026-07-18 22:05
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程

