Building D1:一个全球数据库

来源:Cloudflare
作者:Cloudflare
时间:2024-05-23
3212
构建Worker应用的开发人员专注于他们正在创建的内容,无需关注所需的基础设施,并从Cloudflare的全球网络中获益。

663D24A9-02D7-419D-ACE6-50EF73777BAA.png

构建Worker应用的开发人员专注于他们正在创建的内容,无需关注所需的基础设施,并从Cloudflare的全球网络中获益。从个人项目到关键业务工作负载,许多应用都需要持久数据。Workers提供各种根据开发人员的需求量身定制的数据库和存储选项,例如键值和对象存储。

关系数据库是当今许多应用程序的支柱。D1——Cloudflare的关系数据库——现已正式推出。从2022年底alpha版到2024年4月正式发布,我们一直专注于让开发人员能够通过熟悉的关系数据和SQL来构建生产工作负载。

什么是D1?

D1是Cloudflare内置的无服务器关系数据库。对于Worker应用程序,D1利用SQLite的SQL方言提供SQL的表达能力,并提供开发人员工具集成,包括对象关系映射器(ORM),例如Drizzle ORM。可通过Workers或HTTP API访问D1。

无服务器意味着无需配置,基于Time Travel的默认灾难恢复,以及基于使用量的定价。D1包括一个慷慨的免费层,允许开发人员试用D1,然后将这些试用升级到生产环境。

如何使数据全球化?

D1正式版注重可靠性和开发人员体验。现在我们计划扩展D1,以更好地支持全球分布式应用程序。

在Workers模式中,入站请求会在最接近的数据中心调用无服务器执行。Worker应用程序可根据用户请求进行扩展到全球。然而,应用数据依然存储在集中式数据库中,全球用户流量必须考虑到数据位置的访问往返。例如,现在的D1数据库位于单一位置。

Workers支持Smart Placement,以考虑频繁访问的数据位置。Smart Placement会调用更靠近中央后端服务(如数据库)的Worker,以降低延迟并提高应用程序性能。我们已经解决了全球应用程序中Workers的放置问题,但还需要解决数据放置问题。

那么问题来了,作为Cloudflare的内置数据库解决方案,D1如何才能更好地支持全球应用程序的数据放置?答案就是异步读复制。

什么是异步读复制?

在基于服务器的数据库管理系统(如Postgres、MySQL、SQL Server或Oracle)中,读副本是一个单独的数据库服务器,作为主数据库服务器的一个只读、几乎最新的副本。管理员创建读副本的方法是,从主服务器的快照启动一个新服务器,并配置主服务器以异步方式向副本服务器发送更新。由于更新是异步的,因此读取副本可能会滞后于主服务器的当前状态。主服务器和副本之间的差异称为副本延迟。读副本可以不止一个。

异步读复制是一种久经考验的数据库性能提高解决方案:

-通过在多个副本之间分配负载可以提高吞吐量。

-当副本靠近进行查询的用户时,就有可能降低查询延迟。

请注意,有些数据库系统也提供同步复制功能。在同步复制系统中,写入必须等到所有副本都确认写入后才能进行。同步复制系统的运行速度只能达到最慢复制的速度,当一个复制失败时,系统就会停止运行。如果我们要在全球规模上提高性能,就必须尽可能避免同步复制!

一致性模型&读副本

大多数数据库系统都提供读已提交、快照隔离或可序列化的一致性模型,具体取决于配置。例如,Postgres默认为读已提交模型,但可以配置为使用更强的模型。SQLite在WAL模型下提供快照隔离。快照隔离或可序列化等较强模型更易于编程,因为它们限制了允许的系统并发情景和程序员需要担心的并发竞态条件。

读副本是独立更新的,因此每个副本的内容在任何时刻都可能不同。如果所有查询都在同一台服务器上进行,无论是主服务器还是读取副本,那么查询结果都会根据底层数据库提供的任何一致性模型保持一致。如果您使用的是读副本,结果可能会有点过时。

如果一个基于服务器的数据库使用读副本,一个会话中的所有查询都使用同一个服务器是很重要的。如果在同一会话中切换不同的读副本,就会破坏应用程序提供的一致性模型,这可能会违反您对数据库运行方式的假设,并导致应用程序返回不正确的结果!

示例

例如,有两个副本A和B。副本A比主数据库滞后100毫秒,副本B比主数据库滞后2秒。假设用户希望

1.执行查询1

1a.根据查询1的结果进行计算

2.根据(1a)中的计算结果执行查询2

在t=10秒时,查询1进入副本A并返回。查询1可以看到主数据库在t=9.9秒时的样子。假设计算需要500毫秒,那么在t=10.5秒时,查询2访问副本B。请记住,副本B比主数据库滞后2秒,因此在t=10.5秒时,查询2看到的是数据库在t=8.5秒时的样子。就应用程序而言,查询2的结果看起来就像数据库在时间上倒退了!

7E7790FC-6D53-4398-8FA4-CE70F2CB59C0.jpeg

从形式上看,这就是读已提交一致性,因为你的查询只能看到已提交的数据,但没有其他保证,甚至不能保证你能读取自己写入的数据。虽然读已提交是一种有效的一致性模型,但很难推理读已提交模型所允许的所有可能竞态条件,因此很难正确的编写应用程序。

D1的一致性模型&读副本

默认情况下,D1使用SQLite所提供的快照隔离。

快照隔离是一种熟悉的一致性模型,大多数开发人员都认为这种模型易于使用。我们在D1中实现这种一致性模型的方法是,确保D1数据库只有一个活动副本,并将所有HTTP请求路由到该单一数据库。虽然确保D1数据库最多只有一个活动副本是一个棘手的分布式系统问题,但我们通过使用Durable Objects构建D1解决了这个问题。Durable Objects保证了全局唯一性,因此一旦我们依赖Durable Objects,路由HTTP请求就变得非常简单了:只需将它们发送到D1 Durable Object即可。

如果数据库有多个活动副本,这种方法就不管用了,因为没有100%可靠的方法来查看传入的HTTP请求,并将其100%地路由到相同的副本。不幸的是,正如我们在上一节的示例中看到的,如果我们不能在100%的时间内将相关请求路由到同一个副本,那么我们所能提供的最佳一致性模型就是读已提交。

鉴于不可能一致地路由到特定副本,另一种方法是将请求路由到任何副本,并确保所选副本根据对程序员"有意义"的一致性模型响应请求。如果我们愿意在请求中包含Lamport时间戳,就可以使用任何副本实现顺序一致性。顺序一致性模型具有“读取我自己的写入”、“写入跟随读取”以及写入全排序等重要属性。写入全排序意味着每个副本都会看到事务以相同的顺序提交,这正是我们在事务系统中希望看到的行为。顺序一致性有一个限制条件,那就是系统中的任何单个实体都可能任意过时,但这一限制条件对我们来说是一个特征,因为它允许我们在设计API时考虑副本滞后的问题。

我们的想法是,如果D1为应用程序的每次数据库查询提供一个Lamport时间戳,而这些应用程序告诉D1它们看到的最后一个Lamport时间戳,我们就可以让每个副本根据顺序一致性模型来决定如何让查询工作。

对副本实现顺序一致性,一种稳健且简单的方法是:

-将Lamport时间戳与对数据库的每一个请求相关联。单调递增的提交令牌就很好地解决了这个问题。

-将所有写入查询发送到主数据库,以确保写入全排序。

-向任意副本发送读取查询,但让副本滞后服务查询,直到副本从主数据库接收到晚于查询中Lamport时间戳的更新。

这种实现方式的优点是,在读取量大的工作负载总是访问同一个副本的常见用例中,速度很快,而且即使请求被路由到不同的副本,它也能正常工作。

抢先剧透:使用会话将读复制引入D1

为了将读复制引入D1,我们将使用一个新概念来扩展D1 API:会话。会话封装了代表应用的一个逻辑会话的所有查询。例如,一个会话可能代表来自特定Web浏览器的所有请求或来自移动应用程序的所有请求。如果使用会话,您的查询将使用对您的请求最有意义的D1数据库副本,无论是主数据库还是附近的副本。D1的会话实现将确保会话中所有查询的顺序一致性。

由于会话API改变了D1的一致性模型,开发人员必须选择使用新的API。现有的D1 API方法不变,仍将采用与以前相同的快照隔离一致性模型。不过,只有使用新的会话API进行的查询才会使用副本。

下面是D1会话API的示例:

0F55BDC7-A64A-4515-9C1C-ACA84BAD136A.jpeg

D1的会话实现使用提交令牌。提交令牌标识了已提交到数据库的特定查询。在会话中,D1使用提交令牌确保查询按顺序排列。在上面的示例中,D1会话确保“SELECT COUNT( )”查询发生在新顺序的“INSERT”之后,即使我们在等待之间切换副本也是如此。

关于如何在Workers fetch handler中启动会话,有几个选项。

db.withSession(<condition>)接受这些参数:

649F1683-EBAD-4EFE-B238-17C08FFFE38F.jpeg

通过“往返”会话的最后一个查询的提交令牌,并使用它来启动一个新会话,可以让一个会话跨多个请求。这使得每个用户代理,例如Web应用或移动应用,都能够确保用户看到的所有查询都是顺序一致的。

D1的读复制将是内置功能,不会产生额外的使用成本或存储成本,并且不需要配置副本。Cloudflare将监控应用程序的D1流量,并自动创建数据库副本,将用户流量分散到离用户更近的多个服务器上。与我们的无服务器模式相一致,D1开发人员无需担心副本的配置和管理。相反,开发人员应该专注于设计应用,以实现复制和数据一致性的权衡。

我们正积极开发全局读复制和实现上述方案(欢迎在我们的开发人员Discord服务器#d1频道中分享您的任何反馈)。在实现上述功能之前,D1正式版会包含几个令人兴奋的新功能。

了解D1正式版

自2023年10月D1开放测试版发布以来,我们一直专注于D1的可靠性、可扩展性以及开发人员对关键服务的体验要求。我们投资开发了多项新功能,使开发人员能够更快地使用D1构建和调试应用程序。

利用更大的数据库构建更大型的系统

我们听取了开发人员对更大数据库的需求。现在,D1支持高达10 GB的数据库,Workers Paid计划中支持5万个数据库。通过D1的横向扩展,应用程序可以建立每个业务实体独立数据库的模型。自测试版发布以来,新的D1数据库在给定时间内处理的请求量是D1 alpha数据库的40倍。

导入&导出批量数据

开发人员导入和导出数据有多种原因:

-不同数据库系统之间的数据库迁移测试

-用于本地开发或测试的数据副本

-针对合规性等定制要求进行手动备份

虽然以前可以针对D1执行SQL文件,但我们正在改进wrangler d1 execute–file=&lt;filename&gt;以确保大型导入是原子操作,不会让数据库处于中途状态。wrangler d1 execute现在默认为优先本地执行,以保护您的远程生产数据库。

要导入我们的Northwind Traders演示数据库,您可以下载模式&数据并执行SQL文件。

D06433CA-D8B3-4E09-97FF-2D800AC532EF.jpeg

D1数据库数据&模式、纯模式或纯数据可通过以下方式导出为SQL文件:

89695472-0403-4E2F-9B58-7AAB89CBB5D1.jpeg

调试查询性能

了解SQL查询性能和调试缓慢的查询是生产工作负载的关键步骤。我们添加了实验性的wrangler d1 insights来帮助开发人员分析查询性能指标,这些指标也可通过GraphQLAPI获取。

FC4AF968-2E0B-4CFE-A1A6-AA27FD3FABA9.jpeg

开发人员工具

各种社区开发者项目都支持D1。新增项目包括Prisma ORM,版本为5.12.0,现在支持Workers和D1。

有关后续

正式版现在提供的功能和我们的全局读复制设计只是满足开发人员的应用程序SQL数据库需求的开始。如果您还没有使用过D1,可以立即开始,访问D1的开发人员文档来激发一些想法,或者在我们的开发人员Discord服务器上加入#d1频道,与其他D1开发人员和我们的产品工程团队进行交流。

原文链接:点击前往 >
文章来源:Cloudflare
版权说明:本文内容来自于Cloudflare,本站不拥有所有权,不承担相关法律责任。文章内容系作者个人观点,不代表快出海对观点赞同或支持。如有侵权,请联系管理员(zzx@kchuhai.com)删除!
个人VIP
小程序
快出海小程序
公众号
快出海公众号
商务合作
商务合作
投稿采访
投稿采访
出海管家
出海管家