今年2月,我们跨过了YugaByteDB的三年开发阶段,到目前为止,这是一段激动人心的旅程,但也有不少技术挑战。有时我们必须重新开始,甚至通过学术研究进行筛选,以找到比我们手头更好的解决方案。在本文中,我们将概述构建开源、云原生、高性能分布式SQL数据库的过程。我们必须在.好的,让我们从最简单到最具挑战性的问题开始:1.架构:AmazonAurora还是GoogleSpanner?我们早期做出的决定之一是找到一个数据库,我们可以将其用作YugaByteDB架构的灵感来源。我们密切关注两个系统,AmazonAurora和GoogleSpanner。AmazonAurora是一个提供高可用性的SQL数据库。它与流行的RDBMS数据库(如MySQL和PostgreSQL)兼容,可以轻松上手并运行各种应用程序。AmazonAurora也是AWS历史上增长最快的服务之一。AmazonAurora服务与MySQL和PostgreSQL兼容,是AWS历史上增长最快的服务。AmazonAurora具有可扩展的数据存储层,但没有查询层。以下是我们发现的AmazonAurora的一些主要可扩展性限制:写入不可水平扩展。扩展写入吞吐量的唯一方法是垂直扩展处理所有写入的节点(称为主节点)。这种扩展方案仅适用于此,因此数据库可以处理的写入IOPS数量存在固有限制。写入不是全局一致的。许多现代云原生应用程序本质上是全球性的,需要跨多个区域部署底层数据库。但是,Aurora只支持多主部署,如果发生冲突,最后一个写入者(具有最新时间戳)获胜。这可能会导致不一致。通过使用牺牲一致性的从属副本来扩展读取。为了扩展读取,应用程序需要连接到从节点进行读取。当使用这些从属节点实现读取时,应用程序面临降级的一致性语义和单独的连接端点。这使得应用程序架构非常复杂。或者,GoogleSpanner是一个水平可扩展的SQL数据库,专为大规模可扩展和地理分布的应用程序而构建。CloudSpanner是唯一为云构建的企业级、全球分布式和高度一致的数据库服务,旨在将关系数据库结构的优势与非关系水平扩展相结合。这意味着Spanner可以无缝扩展读写,支持需要全局一致性的地理分布式应用程序,并在不牺牲正确性的情况下从多个节点执行读取。但是,它放弃了RDBMS数据库期望为开发人员提供的许多熟悉的功能集。例如,GoogleSpanner文档中突出显示了不支持外键约束或触发器这一事实。我们决定采用混合方法。YugaByteDB的核心存储架构受到GoogleSpanner的启发,它专为水平可扩展性和地理分布的应用程序而构建。YugaByteDB保留了一个类似于AmazonAurora的兼容PostgreSQL的查询层,它可以支持丰富的功能集并支持最广泛的用例。2.SQL协议:PostgreSQL还是MySQL?我们希望对广泛采用的SQL方言进行标准化。我们还希望它是开源的,并有一个围绕数据库的成熟生态系统。权衡的自然选择是PostgreSQL和MySQL?我们选择PostgreSQL(而不是MySQL)的原因如下:PostgreSQL有更宽松的许可证,更符合YugaByteDB的开源精神。与任何其他SQL数据库相比,PostgreSQL在过去几年中的流行度一直在飙升,这绝对不受影响!在DB-Engines排名网站目前排名前10的五个SQL数据库中,只有PostgreSQL自2014年以来越来越受欢迎,而其他数据库则已趋于平稳或正在失去理智。此外,对于许多应用程序,PostgreSQL是Oracle的绝佳替代品。组织正在被PostgreSQL所吸引,因为它是开源的、供应商中立的(MySQL归Oracle所有)、有参与的开发人员社区、繁荣的供应商生态系统、强大的功能集和成熟的代码库,一直在战斗-稳固超过20年的严格使用。3.分布式事务:GoogleSpanner还是Percolator?我们查看了GoogleSpanner和Percolator,以了解我们应该如何设计分布式事务。总而言之,GooglePercolator提供高吞吐量但使用单个时间戳。这种方法本质上是不可扩展的,并且仅适用于面向实时分析(称为HTAP)的应用程序而非OLTP应用程序的单个数据中心。另一方面,GoogleSpanner的去中心化时间跟踪方法对于地理分布的OLTP和单数据中心HTAP应用程序都是一个很好的解决方案。GoogleSpanner是在GooglePercolator之后构建的,用于替换广告后端中手动分片的MySQL部署,以实现水平可扩展性和地理分布式用例。然而,GoogleSpanner的构建难度要高一个数量级,因为它具有真正的分布式特性并且需要时钟偏差跟踪。有关此主题的更多详细信息,您可以阅读有关Percolator与Spanner权衡的更多信息。我们决定采用GoogleSpanner方法,因为它可以:更好的水平可扩展性高可用性和更好的多区域部署性能。我们坚信,大多数现代云应用程序都需要这两种功能。事实上,GDPR等合规要求以及在总共100个地区提供公共云已经使这成为现实。4.Raft适用于地理分布的工作负载吗?Raft和Paxos是著名的分布式共识算法,已经被正式证明是安全的,Spanner使用Paxos,但是我们选择Raft的原因是:对于开发人员和运维团队来说,Raft比Paxos更容易理解。它提供了动态更改成员资格的能力,这很关键(例如:在不影响性能的情况下更改机器类型)。(banq注:Raft和Paxos的主要区别是Raft候选可以是任意一个服务器节点,不需要指定一个候选,否则如果这些候选都down了怎么办?就像某些TCC中的事务协调器一样分布式事务。单点风险)但是,为了确保线性化读取,Raft要求每个接收读取查询的客户端在实际服务读取查询之前首先将心跳消息传播到Raft组中的大多数节点。在某些情况下,这会严重降低读取性能。这种情况的一个例子是地理分布式部署,其中往返会显着增加延迟,并且在发生临时网络分区等事件的情况下,会增加失败查询的数量。为了避免Raft的高延迟,我们实现了独特的租用机制,这将使我们能够在不往返的情况下实现最大的服务,同时保留Raft的线性化特性。此外,我们使用单调时钟而不是实时时钟来容忍时钟偏差。5.我们可以构建软件定义的原子钟吗?作为分布式数据库,YugaByteDB支持跨多个节点的多键ACID事务(快照和可序列化隔离级别),即使存在故障。这就需要一个可以跨节点同步时间的时钟。GoogleSpanner使用TrueTime,这是一个具有严格错误界限的高度可用的全球同步时钟示例。然而,许多部署没有这样的时钟。物理时钟(或挂钟)不能在节点之间完美同步。因此,它们无法跨节点对事件进行排序(建立因果关系)。Lamport时钟和矢量时钟等逻辑时钟不跟踪物理时间,除非有中央时间戳权威,这成为可扩展性瓶颈。我们的建议:混合逻辑时钟(HLC)通过将使用NTP粗略同步的物理时钟与跟踪因果关系的Lamport时钟相结合来解决这个问题。YugaByteDB使用HLC作为具有用户指定的最大上时钟偏斜值的高可用性集群范围时钟。HLC值在Raft组中用作关联更新的手段,也用作MVCC读取点。结果是一个符合ACID的分布式数据库,正如Jepsen的测试所证明的那样。6.重写或重用PostgreSQL查询层?***但同样重要的是,我们需要决定是重写还是重用PostgreSQL查询层。我们最初的决定是YugaByte数据库查询层在设计时考虑了可扩展性。在这个查询层框架中已经通过用C++重写API服务器构建了两个API(YCQL和YEDIS),首先重写PostgreSQLAPI似乎更容易也更自然。我们的最终决定在我们意识到这不是一条理想的道路之前,我们沿着这条道路走了大约5个月。其他API比PostgreSQL成熟完整的数据库要简单的多。然后我们重做了整个事情,回到绘图板并使用PostgreSQL的查询层代码重新开始。虽然一开始这很痛苦,但回想起来这是一个更好的策略。这种方法也有其自身的挑战。我们的计划是先把PostgreSQL系统表迁移到DocDB(YugaByteDB的存储层),最初支持一些数据类型和一些简单的查询,随着时间的推移增加更多的数据类型和查询支持。不幸的是,这个计划并没有完全奏效。从psql执行看似简单的最终用户命令实际上需要支持大量SQL功能。例如,在内部列出所有表的\d命令执行以下查询:c.relnameas"Name",CASEc.relkindWHEN'r'THEN'table'WHEN'v'THEN'view'WHEN'THEN'materializedview'WHEN'i'THEN'index'WHEN'S'THEN'sequence'WHEN'THEN'special'WHEN'f'THEN'foreigntable'ENDas"Type",pg_catalog.pg_get_userbyid(c.relower)as"Owner"FROMpg_catalog.pg_classcLEFTJOINpg_catalog.pg_namespacenONn.oid=c.relnamespaceWHEREc.relkindIN('r','')ANDn.nspname<>'pg_catalog'ANDn.nspname<>'information_schema'ANDn.nspname!~'^pg_toast'ANDpg_catalog.pg_table_is_visible(c.oid)按1,2订购;WHERE支持IN、不等于、正则表达式匹配等操作符,满足上述查询需要支持以下特性:CASE子句连接,尤其是LEFTJOINORDERBY内置等。pg_table_is_visible()显然,这代表了一个各种各样的SQL功能,所以我们必须在创建单个用户表之前启用所有这些功能!我们发布的DistributedPostgreSQLonGoogleSpannerArchitecture-QueryLayer重点介绍了查询层的工作原理。结论即使对于专家用户来说,不得不在市场上可用的众多数据库之间进行选择一开始似乎也让人不知所措。这是因为为给定类型的应用程序选择数据库取决于这些数据库在其体系结构中所做的权衡。通过YugaByteDB,我们以一种新颖的方式结合了一组非常实用的架构决策,以创建一个独特的开源分布式SQL数据库。PostgreSQL强大的SQL能力现在任你使用,具有零数据丢失、水平写入可扩展性、低读取延迟以及在公共云或Kubernetes中本机运行的能力。
