One self-hosted console to run your entire business — commerce, ERP, HRM, CRM & manufacturing

第 3 部分:26 分钟内更小、更便宜、高可用的数据库,以及为什么 AI 获得自己的 PostgreSQL

我们在 26 分钟窗口中将一个大 MySQL node 移到有 standby 的更便宜 Standard 集群,将读分割到 standby,并为 AI 提供自己的 pgvector PostgreSQL。真实考试晚上显示数据库从不是瓶颈。

Author

Anichur Rahaman

2 天前12 min read5 views
第 3 部分:26 分钟内更小、更便宜、高可用的数据库,以及为什么 AI 获得自己的 PostgreSQL

在 10 月 5 日晚上 22:33,我们把两个 load balancer 指向一个空标签。打开网站的人看到了维护页面。在后面,每个学生、答案和结果都在被复制到一个新数据库,我们与业务同意的窗口是 26 分钟。

没人抱怨数据库慢。问题在它的形状。它是一个大 MySQL node,没有 standby,所以那台机器故障的日子就是整个平台故障的日子。它也更大,更昂贵,比需要的工作。

本文是关于 NovaCommerce 的数据层的,那个销售课程和运行定时在线考试的平台。它覆盖 26 分钟的移动、我们忘记的客户端、我们如何分割读写、为什么 AI 得到自己的 PostgreSQL,以及 2026 年 10 月 7 日真实考试晚上关于所有这些说什么。它跟随 第 2 部分,其中应用层学会了扩展。

这是五部分案例研究 "从单服务器到考试日就绪" 的第 3 部分。NovaCommerce 是虚构名称;架构、数字和错误都是真实的。

错误类型的大

旧数据库是一个托管 MySQL "Advanced" node,有 8 vCPU 和 32 GB RAM。它很大,就像单个巨大的桥。令人印象深刻,也是唯一穿过的方式。

早期在项目中我们写下了高可用性必须对我们意味着什么。一行说:数据库在 node 故障后存活。一个 node 在任何尺寸都无法达到那行。尺寸和可用性是不同的问题,旧设置只回答了第一个。

数据大约 11 GB。所以我们移到托管 MySQL "Standard" 8.4,有 4 vCPU 和 16 GB 每 node,和两个 node:一个 primary,和如果 primary 故障就接管的 standby。在新集群上缓冲池是 7 GB,max connections 是 1,601,存储 autoscale 是打开的。状态:Implemented,10 月 5 日。

之前之后
计划Advanced,单 nodeStandard 8.4,两个 node(primary + standby)
尺寸8 vCPU / 32 GB4 vCPU / 16 GB 每 node
如果一个 node 故障数据库下线Standby 接管
每月成本更高更低;primary + standby 大约列表价格 $389

便宜且高可用性同时是稀有,所以我们拿了它。这里是整个数据层如今看的样子。文章的其余部分走过它。

数据层图:后端 node 写到 MySQL primary 并在 standby 和 primary 间展开读,worker 仅使用 primary,PostgreSQL 与 pgvector、Valkey 和 Spaces 是单独的服务
写去到 primary,读在 standby 和 primary 间共享,AI、缓存和文件各活在它们自己的服务上。

26 分钟的 cutover,逐步

窗口是计划的并与业务同意的。这是我们在 10 月 5 日跟随的顺序。

  1. 22:33。两个 load balancer 指向空标签。学生看到维护页面。
  2. 队列排水和调度器停止,所以没有 job 可能在复制中间写。
  3. 旧数据库上零写 30 秒。那是门:复制仅在旧一侧静默后开始。
  4. 复制用 mysqldump 在 4 平行流。它拿了 10 分钟。
  5. 计数检查:341 表和 18,727,244 行在旧新之间完全匹配。
  6. 应用被对新数据库测试。然后一个新黄金快照、两个池的 rollout 和一个新 worker。
  7. 22:59。Load balancer 回来,26 分钟在我们开始后。
10 月 5 日的 cutover 时间线:22:33 的 load balancer 到空标签、队列排水、30 秒安静门、10 分钟复制、匹配计数、测试、22:59 回家、23:24 找到被遗忘的遗留面板
窗口内的七个计划步骤,和一个在它关闭后 25 分钟的惊喜。

我们如何证明复制是正确的

匹配行计数是一个弱测试,因为两个表可能拥有相同数量的行和不同内容。所以我们检查了比计数更多,我们保持检查在网站回来后。

检查结果
表和行,旧 vs 新341 表,18,727,244 行,完全匹配
每个表的内容所有表上的完整内容检查和,在窗口后
最大的结果表按列对比:2.76 百万行相同
应用用户的权限CREATE TABLE 被拒,如它应该
前 4 分钟实时约 2,900 请求,0 5xx,110 通知 job,0 失败

我们忘记的客户端

在 23:24,网站回来后 25 分钟,我们发现了我们没有计划的东西。一个遗留管理面板,运行在一个单独的旧服务器上,仍在写到旧数据库。

我们关闭了我们记得的所有东西:web node、worker、调度器。我们没关闭我们忘记存在的东西。想象搬家。邮局转发你的邮件,但一个仍有旧地址的朋友保持在那里邮寄信件。

到那时 48 行已经登上旧数据库。我们用条件式 upsert 把它们合并到新的:插入行,或仅当旧副本是新的才更新。44 行被合并。4 行新数据库已经保有更新版本,我们保持了那些。然后我们指向遗留面板到新数据库并改变旧集群的应用密码,所以什么都无法写到它。状态:Implemented。

密码改变一样重要如合并。被遗忘的客户端然后大声失败而不是安静地填满没人读的数据库。旧集群保持冻结 48 小时作为我们的回去方式,在那之后被删除。

课程是一个清单项目,不是故事:

  • 在 cutover 前,列出旧数据库的每个外部客户端。读旧集群的信任来源,并为每个条目问:谁拥有这个?
  • 在与应用相同的窗口中改变每个客户端。
  • 在切换后,改变旧密码,所以一个你错过的客户端大声失败。
  • 保持旧集群冻结一阵子作为回滚。

从 standby 的读:读/写分离

为什么不是读副本

"读很重" 的教科书答案是一个只读副本 node。我们 考虑 它。在这个平台一个只读 node 必须至少和 primary 一样大,所以它会再花大约一样多。同时我们已经为等待故障的 standby 付款。

所以我们 实现 了更便宜的东西:standby 也是一个读者,通过它的副本主机名达到。读在 standby 和 primary 间共享,每一个为另一个覆盖。同一硬件,账单上没新线。

选项额外成本状态注意
Primary 上的一切无基准最简单,但 primary 做每个读
专用只读副本 node约和 primary 一样多Considered必须至少和 primary 一样大
Standby 与 primary 共享读无Implemented,10 月 6 日读可能滞后一点;sticky 读覆盖那个

规则,用简洁词汇

我们在 10 月 6 日 00:13 打开分离。草图形式,Laravel 数据库配置说这个:

read   hosts = [standby, primary]
write  host  = primary
sticky = true
connect timeout = 2 s
  • 写去到 primary。总是。
  • 读去到 standby,primary 被列为第二个读主机。如果一个不应答,另一个做。
  • Sticky。在一个写之后,同一请求保持从 primary 读,所以学生看到自己的答案。一个小中间件保持下一个请求也在 primary 上。想象在白板上写一个注记:你回到白板读它,不是到可能仍在打印的复印件。
  • 2 秒 connect timeout。一个缓慢 standby 快速回滚到 primary,没学生等在它上面。
  • Worker 永不使用 standby。它保持在 primary,因为 job 需要新数据。

它真的分离吗?

我们在一个活 node 检查而不是信任配置。我们打开 8 个新连接,两次。第一运行在两个服务器间分离 6 和 2,第二运行分离 4 和 4。Primary 报告 read_only=0 和 standby read_only=1,所以两个被使用,我们知道哪个是哪个。

一个陷阱

生产负载从权威类映射加载类。一个全新的类,比如新中间件,不在映射中不作为应用关心的存在,请求返回 500。作为部署的部分把它添加到类映射。

固定尺寸、窄权限、按标签访问

周每周调整大小:考虑。一个想法是在考试日之前调整数据库并在之后调整回下。业务选择了固定的 4 vCPU / 16 GB。下面的考试晚上数字支持那个选择。

最小权限:实现。应用的数据库用户有 SELECT、INSERT、UPDATE 和 DELETE,没有 DDL。它可以改变行,它必须,但它无法创建、修改或掉落一个表。我们在 cutover 期间测试它:CREATE TABLE 被拒。

按标签访问:实现。每个数据库接纳后端标签、worker 和办公和跳转地址。一个新 autoscale 后端 node 连接没手工步骤。

那离开一件算术。每个后端 node 运行 80 个 php-fpm worker,每个可能持有一个 MySQL 连接。总值必须保持在 1,601 允许下。

后端 nodephp-fpm worker 每 node最坏情况连接MySQL 限制
2801601,601
4803201,601
6804801,601
10(池最大)808001,601

即使在池最大我们使用约一半限制,留下房间为 worker 和管理会话。

数据层中的 Valkey

一个托管 Valkey,有 standby,保有缓存、会话和队列,运行 noeviction 策略。第 4 部分深入。这里仅属于数据层的东西。

在 10 月 6 日 02:28,一个后端负载测试返回了 2,854 个应用 500。每个是 "Operation timed out" 当连接到 Valkey 时,5 秒 connect timeout。每个请求打开了一个新 TLS 连接,大约每个请求 Valkey 的 5.4 ms CPU,针对大约 MySQL 的 3.3 ms。在 4 GB,Valkey 无法快速接受连接。

Implemented:我们在原地调整了它到 8 GB 与 2 node。数据保留,主机不变。重新测试从 25 直到 500 requests/s,开始 2 个后端 node 池扩展出:0 应用错误,0 后端 5xx。在考试晚上它使用约 12.5% 它的内存。它花更多钱,它移除了一个真实故障。

为什么 AI 得到自己的 PostgreSQL

NovaCommerce 有 AI 学习特性:自适应学习、弱点分析和预测问题。它们在 embedding 上工作,那些描述问题意思的长数字列表。找到最相似的叫做向量相似性搜索。

我们保持那些 embedding 在一个单独的托管 PostgreSQL 17 与 pgvector 延伸,在 2 vCPU 和 4 GB。不在 MySQL 中。三个原因:

  • 一个不同的查询形状。向量搜索意思大向量,逼近最近邻索引和 CPU 重查询。考试流量是短读写。
  • 没有与考试写的竞争。一个重相似性查询必须永不从学生保存答案把 CPU 拿走。两个服务器意思两个预算。
  • 正确的工具。MySQL 对这工作没有一流向量索引。
MySQL 和 PostgreSQL 与 pgvector 的并排对比,跨越工作负载、查询形状、缩放杠杆和每一个当它努力时发生什么
两个有不同形状和不同失败成本的工作负载,所以两个有不同尺寸的数据库。

我们恢复的缩减

PostgreSQL node 很小,我们尝试让它更小:1 vCPU 和 2 GB。Tested,然后 reverted。我们把它放回 2 vCPU 和 4 GB 因为在考试期间到达的写。一个小节省不值得一个在重要的一个小时努力的 node。为考试小时调大小,不是为安静日子。

对通用版本这忠告,比如选择索引类型和保持过滤向量搜索准确,看我们的领域指南 负载下的数据层。这案例研究坚持我们做了什么。

备份和恢复

一个 standby 保护对抗死机器。它不保护对抗错误:如果某人删除了一个表,standby 片刻后删除它。那是什么备份是。我们使用两个,他们应答不同问题。

什么出了问题什么保护我们状态
一个 MySQL node 故障Standby 接管(提供商故障转移)Implemented
数据丢失或损坏托管数据库的每日备份(提供商)Implemented
Cutover 出了问题旧集群保持冻结 48 小时,然后删除Implemented
Web node 丢失或 rollout 失败Web node 的黄金快照;最后 3 个好镜像保留Implemented
Worker 丢失Worker 的一个快照;它仍是单点故障快照 implemented,standby worker planned

数据库不是瓶颈

我们没移动数据库因为它慢。我们移动它为了可用性和成本。测量决定了什么 不 花在上面:在 10 月 7 日真实考试晚上,有两个考试背对背,数据库是系统的安静部分。

测量,10 月 7 日考试晚上值
MySQL CPU,最大 / 平均24.5% / 13.4%
MySQL 运行查询,最大5
MySQL 锁等待0
Valkey 内存12.5%
后端峰值约 69 requests/s
后端 node CPU,2 分钟平均,最大47%(一个 node 碰到 86% 一分钟)

瓶颈是每 node 后端 CPU,数据库有约 6x 余地。我们的容量模型说 MySQL 变成限制近 450 requests/s,针对那晚峰值 69。那模型来自一个多项选择考试。有 PDF 上传的书面考试加载 worker 更多必须单独测量。

用金钱术语,三个数据存储花约 $689/月在列表价格:MySQL 约 $389,Valkey 约 $240 和 PostgreSQL $60。那是约后端池在 2 node 粗略 $990 月账单的 70%,那是为什么我们仅在测量后增长一个存储。

我们学到了什么

  • 一个大 node 不是高可用性。可用性需要第二个能接管的 node,一个更小的对能在价格上击败一个巨大的机器。
  • Cutover 需要一个门在复制前(零写)、计数在它期间,和检查和在后。
  • 在 cutover 前列出旧数据库的每个客户端,然后在之后改变旧密码所以一个错过的客户端大声失败。
  • 在你购买副本之前使用 standby 作为读者。添加 sticky 读和短 connect timeout,保持 job 在 primary。
  • 给应用用户它需要的权限和没其他。没 DDL。
  • 给 AI 自己的 PostgreSQL,为考试小时调尺寸。
  • 在你花之前测量。数据库有 6x 余地;工作在后端。

数据库现在冷静,所以下一个问题是关于在后台运行的一切:单个 worker、队列、日志和监控。第 4 部分覆盖那些:Valkey、worker、日志和可靠性。

About the Author

Anichur Rahaman

Continue Reading