作者:Pinterest 公司高级软件工程师 Alberto Ordonez Pereira ;高级工程经理 Lianghong Xu
作为我们系列博文的第二篇,本文重点介绍了我们是如何挑选出最终替代 HBase 的新技术。
动机
自2013年成立之初,HBase 一直是 Pinterest 的核心存储系统,它曾大规模部署并支持了众多用例。然而,由于之前博客中提到的种种原因,HBase 开始表现出明显的不足,无法跟上不断演变的业务需求。因此,两年前,我们开始了寻找下一代存储技术的旅程,希望它能在未来多年内取代 HBase ,并推动关键业务用例超越现有的存储限制。
选择数据存储的方法
在决策过程中,虽然需要考虑众多因素,但我们在使用 HBase 过程中遇到的挑战,为我们选择下一个数据存储的标准提供了宝贵的指导。
可靠性。这一点至关重要,因为数据存储将为 Pinterest 提供在线流量。停电可能会严重影响 Pinterest 网站的整体可用性。需要考虑的主要方面:
- 单个节点或整个 AZ 的故障恢复能力。
- 容量变更、集群升级等维护操作的成熟度。
- 支持多区域部署,采用双活架构。
- 容灾,支持系统在灾难场景下恢复所需的操作。这包括集群/表/数据库级别的完全备份和恢复,以及时间点恢复( PITR )(或类似),为我们的客户提供不同的恢复点目标( RPOs )。
- 性能。系统应该在规模上实现一致和可预测的性能。
- 合理良好的性能与 Pinterest 的工作负载。虽然公共基准测试结果在纸上提供了有用的数据点,但我们需要用生产影子流量对系统进行战斗测试。
- 在尾部延迟和吞吐量方面的持续性能是关键。暂时故障、离线作业或维护操作不应对性能产生重大影响。
- 功能。系统应提供必要的内置功能,以方便应用程序开发。对我们来说,这些包括:
- 全局二级索引。许多应用程序需要二级索引来实现高效的数据访问。然而,现有的解决方案要么不能扩展(例如 MySQL ),要么需要开发人员做大量的工作来维护自定义索引(例如 HBase 、 KVStore ),要么不能保证索引的一致性(例如 Ixia )。分布式事务。
- 分布式事务中的 ACID 语义使开发人员可以很容易地推断其应用程序的行为。在不影响性能的情况下实现这一点非常重要。
- 在线模式更改。模式更改是一种持续的需求,应该以可靠、快速和一致的方式进行。
- 可调一致性。并不是所有的用例都需要强一致性,在性能与一致性的权衡上有一定的灵活性是可取的。
- 支持多租户。单一部署应该能够服务于多个用例,以将成本保持在合理的水平。能够避开吵闹的邻居是优质服务的基础。
- 快照和逻辑转储。离线分析需要能够将数据库/表的完整快照导出到对象存储(如S3)。
- CDC ( Change Data Capture )。对于许多接近实时的用例来说,CDC 是流数据库更改的基本要求。它还需要支持增量转储或保持复制集群同步(用于灾难恢复或多区域目的)。
- 数据压缩。快速有效的数据压缩是控制总体空间使用的必要条件。
- 行 TTL ( Time To Live )。对于只需要临时存储的用例,有助于保持数据增长。
- 安全。访问控制、静态和传输中的加密以及其他类似的特性是安全遵从性所必需的。
- 开源和社区支持。在 Pinterest ,我们提倡拥抱并为开源技术做出贡献。
- 活跃和繁荣的社区通常表明产品持续改进,行业使用量增加,易于吸引人才-所有这些都是成功长期采用的关键。
- 文档质量对自我学习至关重要,也是产品成熟度的一个指标。
- 宽松的许可证(例如, Apache 许可证 2.0 )在软件使用方面提供了更大的灵活性。
- 迁移工作。从 HBase 到新系统的迁移工作应该是可管理的,并且具有合理的投资回报。迁移工具支持(例如,批量数据摄取)将是初始概念验证开发和大规模生产迁移的必要条件。
考虑到所有这些因素,以下是我们所做的:
- 我们确定了与我们计划支持的工作负载相关的数据存储技术。
- 我们根据公开信息在纸上进行了矩阵分析,考虑了上述标准,这有助于我们在早期阶段排除一些选项。
- 我们选择了在第 2 步中通过初始筛选的三个最有前途的技术,并使用具有合成工作负载的公共基准测试对它们进行了评估。
- 我们在 Pinterest 内部使用影子流量测试数据存储,将生产工作负载流量镜像到新的候选数据存储。这个过程对系统的可靠性和性能特征提供了有价值的见解,帮助我们区分并在最佳候选产品中做出最终决定。最终,我们选择了 TiDB 。
TiDB采用之旅
在 2022 年,我们通过选择 10 多个数据存储技术开始评估,这些技术是我们工作负载的潜在候选人,包括 Rockstore (内部 KV 数据存储), ShardDB (内部分片 MySQL ), Vitess, voldb , Phoenix , Spanner , CosmosDB , Aurora , TiDB , YugabyteDB 和 DB-X (匿名)。
然后,我们使用上述方法进行矩阵分析,最终排除了大多数候选人。以下是我们排除的数据存储列表及其背后的原因:
- Rockstore :不支持二级索引和分布式事务。
- ShardDB :不支持全局二级索引或分布式事务(仅在分片级)。水平扩展具有挑战性,需要手动重新分片。
- Vitess :跨分片查询可能不会被优化。似乎会产生相对较高的维护成本。
- voldb :不提供存储真实源数据所需的数据持久性。
- Phoenix :构建在 HBase 之上,与 HBase 共享很多痛点。
- 扳手:在很多方面都很有吸引力,但不是开源的。在我们的规模下,从AWS到GCP的迁移成本可能高得令人望而却步。
- CosmosDB :(与上文类似)。
- Aurora :虽然提供了很好的读取可扩展性,但它在写入可扩展性方面的限制可能会成为我们一些关键业务用例的亮点。
剩下的三个选项是 TiDB 、YugabyteDB 和 DB-X 。它们都属于 NewSQL 数据库类别,结合了 NoSQL 数据存储的可扩展性和传统关系数据库管理系统( RDBMS )的 ACID 保证。在理论上,这三种数据存储看起来都充满希望,功能相似。然后,我们使用一些最小设置的 YCSB 基准测试进行了初步性能评估,所有数据存储都提供了可接受的性能。
虽然合成工作负载的结果提供了有用的数据点,但我们意识到,决定因素将是 Pinterest 生产工作负载下的稳定性和持续性能。
为了打破僵局,我们在 Pinterest 基础设施内为这三个系统各自建立了概念验证( POC ),并进行了影子流量评估,重点关注性能和可靠性。
我们使用了来自 Ixia 的影子流量,Ixia是我们基于 HBase 和内部搜索引擎( Manas )构建的近实时索引服务。 Ixia 支持多种用例,涵盖了各种查询模式、数据大小和每秒查询率( QPS )容量,我们认为这些用例很好地代表了我们的生产工作负载。具体来说,我们选择了一些具有大数据量( TB 级)、100k+ QPS 和相当数量索引的用例,以深入了解这些系统在更大规模上的表现。
我们使用相同的生产影子工作负载评估了三个最终候选系统。为了尽可能公平,我们直接与这些系统的支持团队合作,尽我们所能进行了调优/优化。根据我们的观察,YugabyteDB 和 DB-X 在我们的工作负载下难以提供持续的性能。示例问题包括个别节点偶尔的高 CPU 使用率,导致延迟增加和集群不可用,随着索引数量的增加,写入性能显著下降,以及查询优化器在查询分析中没有选择最佳索引。另一方面,TiDB 在经过几轮调优后能够承受负载,同时提供总体上良好的性能。因此,经过几个月的评估,TiDB 作为最有希望的候选者脱颖而出。
为了完善这个过程,我们对 TiDB 进行了一系列可靠性测试,包括节点重启、集群扩展、优雅/强制节点终止、可用区( AZ )关闭、在线数据操作语言( DML )操作、集群重新部署、集群轮换等。虽然我们遇到了一些问题(例如,在 TiKV 节点退役期间数据传输缓慢),但我们没有发现任何根本性的缺陷。
因此,我们最终决定继续采用 TiDB 。值得注意的是,决策过程是基于我们在评估时( 2022 年)对 Pinterest 特定工作负载的最佳理解。其他人完全有可能根据自己的要求得出不同的结论。
生产中的 TiDB
在本博客中,我们不会涉及 TiDB 特定的架构细节,因为这些细节可以在很多地方找到,特别是在官方文档中。建议在继续阅读之前熟悉 TiDB 的基本概念。
部署
我们使用内部部署系统 Teletraan 来运行 TiDB ,而绝大多数 TiDB 客户使用 Kubernetes 部署 TiDB ,并使用 TiDB 的内置工具( TiDB Operator )进行集群操作。这主要是因为我们在开始采用时,Pinterest 缺乏对 Kubernetes 的支持。这意味着我们必须复制 TiDB Operator 的功能,并开发我们自己的集群管理脚本,这并不理想,并在最初集成时造成了摩擦。虽然我们通过当前设置实现了显著的稳定性改进,但随着 Pinterest 对 Kubernetes / EKS 的基础设施支持逐渐成熟,我们计划将 TiDB 迁移到 EKS 上。
默认情况下,我们对所有 TiDB 部署使用三向复制。当需要时,我们使用额外的只读副本进行数据快照,以尽量减少对在线服务的影响。与我们有六个副本的 HBase 部署(两个集群,每个集群有三个副本)相比,在许多情况下, TiDB 允许我们将存储基础设施成本降低近一半。
目前, TiDB 部署在单个 AWS 区域中,每个区域有三个副本分别部署在不同的可用区( AZ )。我们使用放置组在三个 AZ 之间分布Raft组,以便能够在 AZ 故障中存活。三个关键 TiDB 组件( PD、SQL 和 TiKV )之间的所有通信都使用相互TLS加CNAME验证进行保护。唯一暴露给外部系统的层是 SQL 层,到目前为止,它是由 Envoy 代理的。在撰写本文时,我们正在探索不同的多区域设置,以及去除 Envoy 作为 SQL 层的代理(因为我们需要更好地控制我们如何管理和平衡连接)。
计算基础设施
我们目前将 TiDB 部署在配备英特尔处理器和本地 SSD 的实例类型上。尽管如此,我们正在探索迁移到 Graviton 实例类型以获得更好的性价比,以及迁移到 EBS 以实现更快的数据移动(进而在节点故障时缩短平均恢复时间 MTTR )。下面描述了我们在 AWS 上如何运行每个核心组件。
PD 层在 c7i 上运行,根据负载级别使用各种 vcpu 。扩展 PD 节点的两个主要因素是集群大小(区域越多,工作负载越多)和向 PD 发出区域位置请求的离线作业。
SQL 层主要运行在 m7a.2xlarge 上。考虑到 SQL 层是无状态的,扩展集群以增加更多的计算能力相对容易。
TiKV 层(有状态)基于工作负载特征在两种实例类型上运行。磁盘密集型工作负载通过配备 3.7TB NVMe SSD的i4i.4xlarge 实例来支持,而计算密集型工作负载则运行在 c6id.4xlarge 实例上。我们还为 TiKV 只读节点( raft -learner )使用 i4i 实例,因为它们通常是存储绑定的。
在线数据访问
TiDB 公开了一个 SQL 兼容的接口来访问数据和管理集群。然而,在 Pinterest ,我们通常不会直接向客户公开数据存储技术。相反,我们用一个抽象的数据访问层(通常是一个 Thrift 服务)来代理它们,以满足大多数客户端的需求。我们用来代理 TiDB (和其他技术)的服务称为结构化数据存储( SDS ),将在本博客系列的第三部分中详细介绍。
离线分析
虽然 TiDB 为分析目的提供了 TiFlash ,但我们目前没有使用它,因为它可能更适合用于聚合查询,而不是专门的分析查询。相反,我们使用 TiSpark 获取全表快照并将其导出到S3。这些快照被导出为 Hive 表的分区,然后由我们的客户端用于离线分析。
在 TiDB 离线管道的生产过程中,我们发现了一些挑战及其缓解措施:
客户端请求完整快照过于频繁。对于这种情况,我们通常建议通过 CDC 和 Iceberg 使用增量转储。
由于以下几个原因,TiSpark 使集群过载:
PD 过载:TiSPark 在拍摄快照时,需要向 PD 层询问每个区域的位置。在大型集群中,这可能是大量数据,这会导致 PD 节点 CPU 出现峰值。这可能会影响在线工作负载,因为 TiSPark 只与负责为在线查询提供 TSO 的 PD leader 通信。
TiKV 过载:数据最终来自存储层,存储层已经忙于在线处理。为了避免对在线查询处理产生很大的影响,对于需要这样做的用例,我们启动了 TiSPark 使用的 raft -learner 或只读节点,因此几乎隔离了离线处理的任何潜在影响(网络仍然是共享的)。
更改数据捕获
CDC 是 Pinterest 几乎所有存储服务的基本组件,支持重要功能,包括:
- 流数据库更改用于需要观察特定表或数据库产生的所有增量的应用程序。
- 集群复制,可用于高可用性,实现多区域部署等。
- 增量转储,可以通过冰山表的完整快照和 CDC delta 来实现。这消除了由于脱机作业而给集群带来的大量压力,特别是在客户端需要非常频繁地转储数据时。
根据我们的经验——这是我们使用 PingCAP 已有一段时间的经验—— TiCDC ( TiDB 的 CDC 框架)有一些吞吐量限制,这使得大型用例(需要 CDC 支持)的导入变得复杂。它目前的吞吐量上限为~ 700 MB/s,但为了消除这一限制, TiCDC 的完全重构架构可能即将出现。对于遇到这种情况的用例,我们可以通过使用标志表来规避它,标志表本质上是由时间戳和主表的外键组成的表。当主表更新时,标志表总是更新,并且在标志上定义 CDC ,因此输出已修改行的 id 。
在消息格式方面,虽然我们目前使用的是开放协议,因为它更有效的二进制格式和更低的模式管理开销,但我们正在积极尝试迁移到 Debezium ( Pinterest 的事实标准),以简化上游应用程序的开发。
灾难恢复
我们每天(或在某些情况下每小时)运行全集群备份,并通过使用 TiDB BR 工具导出到 S3。我们还启用了时间点恢复( PITR )功能,该功能将增量日志导出到 S3 ,以实现以秒/分钟为单位的 RPOs (恢复点目标)。
进行备份可能会影响集群的整体性能,因为大量数据要通过网络移动。为了避免这种情况,我们将备份速度限制为我们觉得合适的值( ratlimit =20;并发= 0;默认情况下)。备份速度根据实例数量和集群内的数据量不同而不同( 2Gb/s ~ 17gb /s )。对于完整的每日备份,我们保留 7-10 天,对于小时备份,我们保留 1-2 天。PITR持续启用,保留期为~3 天。
为了从灾难(完全不可逆转的集群故障)中恢复,我们运行备份恢复到一个空的备用集群。预先配置了集群,以便在停机期间最小化 MTTR 。尽管它增加了总体基础设施占用,但成本会随着集群数量的增加而平摊。使用恢复集群的一个复杂之处在于,并非所有的生产集群都以相同的配置运行,这可能需要在执行恢复之前对其进行更新。
到目前为止,我们使用不带 PITR 的完整集群恢复作为最直接、最快速的恢复机制。这是因为不幸的是,TiDB PITR 的当前实现速度很慢(数百 MB/s 的恢复速度),而完全恢复可以达到 10-20 GB/s 左右。虽然这种方法可能导致临时数据丢失,但这是一种必要的权衡。为了完成大规模恢复的PITR,将集群保持数小时甚至数天不可用是不可接受的。值得一提的是,在未来的 TiDB 版本中预计会有显著的性能改进,因此这可能会发生变化。在恢复集群可用性之后,仍将应用 PITR 来恢复 delta 。
胜利与学习
以我们的规模采用像 TiDB 这样的重大技术,并将众多遗留的 HBase 用例迁移到 TiDB 上,是一项巨大的任务。这标志着朝着更现代化的在线系统技术栈迈出了重要一步,尽管一路上存在挑战,但我们看到 Pinterest 在采用 TiDB 方面取得了巨大成功。今天, TiDB 托管了数百个生产数据集,支持广泛的业务关键用例,并且仍然越来越受欢迎。以下是我们在这段旅程中获得的一些关键胜利和教训。
胜利
- 开发速度提高:MySQL 兼容性,横向可扩展性和强一致性构成了TiDB在Pinterest的核心价值主张。这种强大的组合使存储客户能够更快地开发应用程序,而无需进行痛苦的权衡。它还简化了对应用程序行为的推理,从而提高了总体满意度并提高了开发人员的速度。
- 系统复杂性降低:TiDB 的内置功能允许我们弃用一些建立在 HBase 之上的内部系统(例如,用于分布式事务的 Sparrow 和用于二级索引的 Ixia )。这大大降低了系统复杂性和总体维护开销。
- 性能改进:当用例从 HBase 迁移到 TiDB 时,我们通常会看到非常令人印象深刻的(~ 2 - 10 倍) p99 延迟改进。更重要的是,TiDB倾向于提供更可预测的性能,在相同的工作负载下,峰值更少、更小。
- 降低成本:根据我们的经验,HBase 到 TiDB 的迁移通常会节省大约 50% 的基础设施成本,主要是将副本的数量从 6 个减少到 3 个。在某些情况下,我们还通过额外的计算效率改进(例如,通过查询下推)实现了更大的节省(高达 80% )。
学习
- 在选择数据库时,有很多因素需要考虑。初始过滤的分阶段方法帮助我们缩短了资源限制下的评估时间。虽然有些系统可能在纸面上或在合成基准测试中很有吸引力,但最终的决定归结为它们在实际工作负载下的表现。
- 虽然我们担心TiDB的可用性,因为在同一地区丢失两个副本时它可能不可用,但在过去的两年里,这对我们来说并不是一个真正的问题。我们遇到的绝大多数中断都是由于人为操作错误造成的,因为内部部署系统最初并不是为支持有状态系统而设计的,而且在管理部署配置时容易出错。这进一步促使我们迁移到使用基础设施即代码( IaC )的 EKS 。
- 以 Pinterest 的规模运营 TiDB 带来了一些 PingCAP 没有看到的独特挑战(上面提到了一些)。例子包括:
- TiCDC 不是真正的水平可扩展,并且达到吞吐量限制。
- 在系统资源利用率不高的情况下,备份和关机时数据移动较慢。
- 大型数据集的并行闪电数据摄取可能是繁琐和容易出错的。
- TiSpark 作业可能会使 PD 过载并导致性能下降。
幸运的是, PingCAP 正在与我们合作,为这些问题提供优化/缓解。
锁争用是造成性能问题的主要原因之一。我们需要特别注意最初的模式设计,并与客户团队合作,以尽量减少争用。这对 HBase 来说不是问题,它是无模式的,不支持带有锁定机制的分布式事务。
预告
到目前为止,在这个博客系列中,我们已经描述了我们决定淘汰 HBase 背后的原因,以及选择 TiDB 作为替代品的基本逻辑。如前所述,在 Pinterest ,HBase 和 TiDB 都不直接暴露给客户端使用。相反,它们是通过数据访问服务来访问的,这些服务既保护了数据存储也保护了客户端。在下一篇博客文章中,我们将深入探讨我们如何用一个名为结构化数据存储( SDS )的统一框架取代了 HBase 之上的多个服务层。SDS 支持各种数据模型,并支持不同数据存储的无缝集成。它不仅仅是一个在线查询服务框架,而是一个全面的解决方案,为 Pinterest 提供存储即服务平台。敬请期待更多细节。
致谢
HBase 的弃用、TiDB 的采用和 SDS 的生产,离不开存储和缓存团队工程师们的勤奋和创新工作,这些工程师包括 Alberto Ordonez Pereira, Ankita Girish Wagh, Gabriel Raphael Garcia Montoya, Ke Chen, Liqi Yi, Mark Liu, Sangeetha Pradeep and Vivian Huang。我们要感谢跨团队合作伙伴 James Fraser, Aneesh Nelavelly, Pankaj Choudhary, Zhanyong Wan, Wenjie Zhang 的密切合作,以及我们所有客户团队对迁移的支持。特别感谢我们的领导 Bo Liu, Chunyan Wang 和 David Chaiken 对这一倡议的指导和赞助。最后但并非最不重要的是,感谢 PingCAP 帮助将 TiDB 引入 Pinterest 的技术堆栈,从最初的原型设计到大规模生产。