OpenAI 如何将 PostgreSQL 扩展到支撑 8 亿名用户
2026年2月7日
OpenAI 最近发表了《Scaling PostgreSQL to power 800 million ChatGPT users》一文。这篇文章讲 OpenAI 的核心产品 ChatGPT 背后所使用的数据库系统 PostgreSQL。
在文章当中,他们分享如何扩展 PostgreSQL 来支撑 ChatGPT 超过 8 亿的用户,这是个非常惊人的数字。在这支影片当中,我们会跟大家来聊聊 ChatGPT 它实际跟 PostgreSQL 之间的关系,以及在 ChatGPT 的流量逐渐大起来后,遇到哪些扩展上面的问题。最后当然也会来聊在文章当中分享的关键精华,是 OpenAI 的团队如何解决这些遇到的问题。
OpenAI 与 Postgres
首先,ChatGPT 与 Postgres 之间有些什么样的关系呢?相信多数人在使用 ChatGPT 这个工具的时候,是要使用它核心的生成式 AI 的功能,但事实上作为一个应用产品,除了提供这个核心的生成式 AI 的功能之外,它其实也会需要存各式各样的数据,这是为什么 ChatGPT 它会需要 Postgres 的原因。
举例来讲,当今天用户注册 ChatGPT,它会需要存用户相关的数据,这样下一次用户重新登入或者使用的时候,产品才能够去调出用户相关的数据。这些数据可能也包含用户有的设定,例如说我们在使用 ChatGPT 的时候会去设定系统提示词 System Prompt。相信多数的用户不会想要这次设完系统提示词,下一次再回来之后这个系统提示词就要重新再设一次。那假设要做到这样的话,ChatGPT 势必背后需要有一个数据库来存系统提示词。
除此之外,大家在用 ChatGPT 的时候相信也会希望能够留存过去的聊天历史记录,而这个时候也会需要有一个数据库来去存这些记录。在文章中有提到 ChatGPT 这个产品其实有用各式不同的数据库,例如说有用 Redis 或者有用其他的 NoSQL 数据库,但是他们最核心使用的数据库是 Postgres。
而随着 ChatGPT 的用户人数越来越多,到了 2026 年这篇文章发表的时候,短短三年多 ChatGPT 的使用人数已经超过了 8 亿。在文章中有提到因为这个用户的人数大量的增加,他们对于 Postgres 的用量的需求也增加了超过 10 倍。而当今天使用量增加的时候,就很可能会遇到原本的机器已经不够应付当前的需求这种非常奢华的困扰。
在这种状况下,通常会有两种做法来解决。第一个是所谓的向上扩展,或者大家很常听到的垂直扩展。原本的机器不够应付,我们就把机器升级成一个规格更好更顶的机器。不过相信大家可能会问,我们要把规格提高总是会有一个上限,不可能无限地去增加机器的规格。所以这时候会有另一种做法叫向外扩展,或者大家很常听到的水平扩展。这个做法是今天假设我原本的机器已经不够应付了,我们可以去增加更多台机器。
事实上 OpenAI 的团队他们两个做法都用上了。虽然在这篇文章当中没有写,但是同一个作者之前在另一个相关的演讲中有提到,OpenAI 的团队基本上是用 Azure 上最顶规的机器,所以算是向上扩展已经做到了一个极致。除了去使用最顶规的机器之外,他们同时也做了向外扩展。
具体来讲有做两件事,第一件事情是分片 (Sharding),另一件事情是复写 (Replication)。
所谓的分片 Sharding 是去把数据库拆成不同的分片 (不同的 Shard),我们会分别使用不同的机器实例。假设今天对于数据库的写入的请求 A 与 C 的请求,我可以写到第一个分片;对于 B 跟 D 的请求,我可以去写到第二个分片当中。
所以假设今天我们使用的机器每秒能够去处理 1000 个写的请求,当我们去切成多个不同的数据库实例的时候,就能够同时去支应更多的写入的请求。
除了分片之外,复写 (Replication) 也是一个很常会使用到的向外扩展的方式。所谓的复写是我们有一个主要的数据库 (在实务上可能会有多个,不过简化来理解的话有一个主要的数据库),然后其他的从属的数据库,是把主要的数据库复制过去一份。假设有查询相关的请求,就不需要发向主数据库,而是可以由已经复制好相关数据的从数据库来去处理。
在有了以上的基础的概念之后,往下我们就来谈一下在文章当中 OpenAI 的团队实际分享 ChatGPT 的流量大起来后,他们遇到哪些扩展的挑战。
ChatGPT 流量大起来后遇到的扩展挑战
在 OpenAI 他们的整体的架构来讲,他们是只有一个主数据库负责所有写入的请求,与此同时他们有将近 50 个不同的复本、不同的从数据库来处理读取相关的请求。之所以会这样设计,有一个很核心的关键是 ChatGPT 以及 OpenAI 有的这些 API 在遇到的读写比例来看是读取偏重,对于读的需求比较大一点。在这种状况下,采用单一个主数据库,在全世界不同的区域有不同的复本,就能够非常好地去应对大量的读取相关的请求。
但这个时候就有一个问题来了,虽然说对于 ChatGPT 的使用场景来说读取的需求比较大,但是因为他们全球还是有超过 8 亿个用户,所以即使写的比例没有读的比例那么多,量总体来讲还是非常大的。在这种状况下,Postgres 本身的设计上面对于要处理比较大量的写入请求效率会比较低一点。
在文章当中作者有提到另一篇是由 CMU 的数据库教授 Andy Pavlo 跟作者协作的另一篇文章,来谈 Postgres 的 Multiversion Concurrency Control MVCC 这个设计导致了这种大量写入请求效率比较低的状况。在这边我们就不展开来谈,推荐读者可以去实际读这篇文章了解细节。
当今天 Postgres 在处理大量写入请求效率比较低的同时,OpenAI 的整体的架构当中又只有一个负责处理写入请求的主数据库,这个时候假如主数据库过载就很容易导致事故。这边我们放了在文章当中实际有分享出来的一张图,在这张图当中就有谈到可能会因为快取没有命中,或者说有一些查询比较昂贵,或者 ChatGPT 有某个新功能上线有大量的用户使用的时候会有增加非常大量的写入的请求。
这些不同的状况可能会导致负责处理写入请求的主数据库有过载的状况,而当这个负责处理写入请求的主数据库过载就可能会导致一些请求变得比较慢,或者甚至会超时。这时候可能就会有更多人重试,所以发送了更多的写入请求,造成一个恶性的循环。原本因为已经有太多写入请求导致过载,这时候来了更多的写入请求就导致整个主数据库崩溃掉,因而造成事故。
不过这个时候相信大家可能会问,我们前面有谈到 OpenAI 的团队在做向外扩展的时候有使用分片,而且分片是一个能够有效去扩展写入请求的方式,那么为什么他们不在这个主数据库去做分片呢?
这边最主要有两点。第一点是,如我们前面有谈的,事实上 OpenAI 的团队在处理写入请求的时候是有做分片的,但是不是做在这个 Postgres 的主数据库上面,待会我们会详细地谈他们怎么做。但是这还是没有回答到为什么不在这个主数据库做分片,因为最关键的点是 ChatGPT 这个产品以及相关的 API 的成长速度实在太快了。所以当一下规模到了这么大的程度,要去做分片会是非常耗时的,因为一次要做分片可能会动到好几百个不同的应用端的接口。所以假设要非常安全、非常完整的去执行主数据库的分片,可能会需要花好几个月,甚至一两年的时间才能做到。
所以在文章中有提到,他们其实是有考虑为主数据库做分片,但是不是现在立即做,因为现在也没有办法马上做完。假如短期没有办法完成这件事,核心的关注点就会是在不做主数据库分片的状况之下,要如何去承接越来越大的请求,要如何去做好扩展这件事。
降低对主数据库的请求
接着让我们一起来看看 OpenAI 的团队是如何解决这些问题的。我们先来看到第一个挑战。还记得前面有谈到 OpenAI 的 Postgres 的架构是由单一的主要数据库作为写入使用。由于要去分片这个主数据库会需要花非常多的时间,所以他们在短期并没有考虑去做分片。因此这个单一的主数据库本身是会有一个扩展的瓶颈,因为它不管规格怎么升、CPU 再升到某一个程度,还是会有硬件的极限所在。这个时候,假设有一个大量的高峰的写入,就很可能导致这个主节点过载,影响到 ChatGPT 跟 OpenAI 的其他 API 的服务。
大家可以稍微暂停一下影片思考一下,假设是你遇到了这样现实的技术的限制,你会如何来解决这个问题?
在文章当中,OpenAI 的团队分享了三个主要的点。假设今天请求的量变大,主数据库可能会撑不住,那么我们可以做的第一个做法就是去减少请求量。而具体的做法,就如前面有谈到的,这个主数据库作为写入,而其他读取相关的请求是会通过复本复写的方式分到其他的从属数据库。所以今天我们可以把所有读取相关的请求尽可能的由复本的数据库处理,不要让读取相关的请求进到主数据库,这样就能大量的减少主数据库会需要处理的请求。
而第二个他们做的事情是,虽然这个 Postgres 主数据库本身要做分片会需要花好几个月,甚至数年的时间,所以他们短期不考虑,但是可能会有一些新的写入需求是能够做分片的。那这个时候,这些新的写入需求就不要进到这个主数据库,而是进到别的数据库。具体来说,OpenAI 他们使用微软的 Cosmos DB 来处理这些能够做分片的写入。这边大家可能比较容易搞混,所以特别强调:他们的主数据库 Postgres 的这个主数据库本身没有做分片,能够做分片的写入是搬到另一个数据库 Cosmos DB 去处理。
除了前面这两点,OpenAI 的团队还有做的一件事情是延迟写入 Lazy Write。所谓的延迟写入是指尽量避免在某一个尖峰的当下把所有的写入都塞进去,因为假设真的去做分析的话,可能某一些部分的写入并不是真的需要这么即时的写入。那这时候可以先把它们放一旁,先处理那些真正需要去即时写入的请求,然后等到这些请求都处理完、高峰逐渐地缓下来之后,再去处理那些即时性需求没有那么高的写入。通过这些方法,就能够让主数据库要去处理的请求不会这么多,也不会这么密集。
查询优化
接着我们来谈第二个他们遇到的实务上的问题。在他们的 Postgres 系统当中,会有一些成本比较高的查询,而这些查询当流量大起来的时候,就会大量的消耗 CPU,进而去拖慢 ChatGPT 跟 API 的请求。遇到这种状况,你在实务上可能会怎么处理呢?
相信大家应该都会想到,既然查询可能会有所谓的慢查询或者昂贵的查询,那我们就来做查询的优化解决这件事。具体来说,他们有提到几个他们优化的过程中去特别着重的点。第一个点是减少慢查询,第二个是去特别检视查询的语句,最后呢,是去清理一些闲置的查询。
首先第一个减少慢查询这件事,在文章当中有特别强调要尽可能的去避免一些不应该出现在 OLTP 系统会出现的查询。现在业界通常会把数据库的系统去区分 OLTP 跟另一个 OLAP 这两个不同类型的系统。OLTP 的系统的特性就是会专注在处理交易型的任务,所以去处理那些单次范围比较小的写入跟查询。而另一种可能是要去做分析相关的,则会使用 OLAP 来处理。而这个 OLAP 就是会去处理这种需要大范围的数据的查询跟聚合或者筛选等等的操作。
在实务上,如果数据的系统逐渐大起来的话,没有去区分这两种系统,很可能会造成的问题是,今天应用程序端的后端工程师可能会需要去跟数据分析师还有数据科学家说:「可不可以请你们稍微暂停一下你们手边的工作?因为你们去做分析而使用的那些查询正在拖慢我们的系统。」刚刚上面描述的这种情境,就是没有把处理事务型交易型的系统跟处理分析型的系统拆开会导致的结果。假设今天整体的流量比较小,这倒是还好,不太真的会有这样的问题发生。但是数据系统一大起来,就很可能会有这样的状况出现。
在这篇文章当中有提到,他们实际去检视 Postgres 系统会处理的查询,竟然发现有一些查询是会同时去 join 12 张不同的表,这种不应该出现在 OLTP 系统中该有的查询。所以他们就辨别出这些查询,然后把这些大范围复杂的查询给处理掉。
第二个,文章中特别有提到不要过度的依赖 ORM。所谓的 ORM 就是一个可以让开发者可以去写类似于应用端的逻辑,然后通过 ORM 的工具去转成 SQL 的语句。但是往往有时候 ORM 在使用的时候,他们去转出来的 SQL 语句并不是优化的。又或者说,像我们过去有写过一篇文章在谈所谓的 N+1 问题,也是很常在使用 ORM 的时候会出现的。所以在文章中作者有特别提到,使用 ORM 的同时也需要真的去检视 ORM 背后产出的 SQL 的语句,不要直接全盘的接受,因为转换出来的结果很有可能是能够进一步去优化的。
最后,OpenAI 团队在做查询优化的具体方法当中,也包含去清理闲置的查询。而他们的做法是使用 Postgres 有的这个 Idle in Transaction Session Timeout,然后去扫除那些已经闲置或者阻塞在那边很久的查询,然后把它们自动的清理掉。通过上面的这三种方式,就让整体的查询变得是更佳的,也对于数据库的系统的负担会比较小一点。
避免单点故障
接着第三个他们遇到的实务问题是,在他们的架构之下,因为是单一主数据库负责写入,然后有接近 50 个从属的数据库负责读取相关的请求。在这个状况下,假设他们的复本数据库挂掉,还有其他的复本数据库可以用,所以只要把流量导去那边就可以。但是假设主数据库挂掉的话,因为只有单一个主数据库,那这个时候该怎么办呢?
一样推荐大家可以稍微暂停一下,想一想你会怎么做。
OpenAI 团队具体的做法是,有这个主数据库的同时,有另一个热备份 Hot Standby 在旁边。他们开启了微软 Azure 上面的高可用模式。换句话说,除了主数据库本身之外,有另一个并没有立即在使用的数据库,但是它会同步所有主数据库有的这些数据。所以当今天主数据库假设一倒,这个热备份的数据库就能够马上顶上去,然后让整体的服务仍是可用的。
但这件事情概念上讲起来好像很简单,但是实务上其实有非常多需要去克服的点。因为第一个,光是去能够辨别主数据库真的挂掉这件事,就是一个相当有技术挑战的事。以及主数据库假设真的倒了,这个热备份去替代的同时,也不单单只是去替代它,因为所有的复本数据库就会需要重新连线到这个原本是热备份的数据库。而在这整个流程当中,有非常多可能会出错的地方。
不过这边 OpenAI 的团队有特别把功劳归功于微软的 Azure 团队。他们在文章中有提到,这一切能够真的很顺的做到,是 Azure 团队他们花了非常多的功夫去处理。不过回过头来,假设你也是要使用云端服务商所提供的数据库服务做这种热备份,也不是完全没有成本的。还记得我们前面有谈到 OpenAI 他们基本上在主数据库上把向上扩展做到了极致,用了 Azure 最顶规可以使用的机器。所以换句话说,他们同时必须要再租另一台同样最顶规的机器来作为热备份。那这个其实不是一个便宜的金额,所以也不是完全没有成本的。
负载隔离
再往下第四点,在实务上的时候,他们经常有遇到一些请求可能会去吃掉比较多 Postgres 的资源,导致其他的业务因此变慢。举例来说,有些新功能上线的时候,在测试环境可能因为流量不够大,所以没有办法发现是效率不佳的查询。那这时候,这些新的功能上线,同时有大量的用户使用去消耗 Postgres 的 CPU,就很可能会导致其他重要的功能因此变慢。
遇到这种状况,大家觉得可以怎么去处理呢?
OpenAI 团队具体的做法是把负载隔离。他们通过把从属数据库分出不同的实例,然后把某些特定的从属数据库实例会分配给那些高优先度的相关的请求。这样的做法就会让假设今天真的某一个比较慢的查询在新功能上线的时候被曝露出来,不会影响到那些优先度高的请求。
因为这些优先度高的请求,他们有自己专属的数据库实例来处理。所以假设这些比较慢、比较没有效率的查询上线了,会影响的也只会是那些优先度比较低的相关的请求。通过这种隔离的方式,就能够确保最重要的东西,即使在系统中有其他部分出问题了,也不会被影响到。