避免分库分表,绿普惠的分布式数据库选型与实践

zhangxiuyong
发布于 2023-10-31 14:45
浏览
0收藏

一项数据显示,今天大气中的二氧化碳水平比过去 65 万年高了 27%。主要原因来自于工业化需求下的煤炭燃烧、汽车尾气。随着人类活动造成的温室效应加剧,环保越来越成为主流意识。


作为碳普惠解决方案服务商,绿普惠科技(北京)有限公司(以下简称绿普惠)致力于实现“数字化推动消费端减碳”,采用现代企业运行机制作支撑,整合社会各方资源,广泛动员公众参与碳减排活动。


举个例子,在 2020 年 7 月 2 日,北京 2022 年冬奥会和冬残奥委员会上线“低碳冬奥”微信小程序。2022 年 1 月 19 日,生态环境部宣传教育中心与中华环保联合会共同发起了“践行绿色生活 共赴冰雪之约”碳普惠行动,希望在冬奥会这一契机下,通过引导、激励等方式激发公众参与碳减排的热情,践行绿色低碳生活方式。截至 2022 年 2 月底,“低碳冬奥”小程序参与人数达到 270 万,累计减排次数达到 9000 多万次,累计碳减排约 1.9 万吨二氧化碳当量。

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

在这样的减排活动中,如何记录数据和检验结果呢?其中的关键就在于减碳计量底层平台——“绿普惠云-碳减排数字账本”。

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

数字账本平台主要包括三个模块:租户查询系统、碳减排量交易系统和运营端报表系统。


  • 租户查询系统:租户可以通过 API 进行减排量指定维度和场景查询操作,查询系统将返回相应的减排数据。


  • 碳减排量交易系统:交易核心减排量处理,可以支持大数据量低延迟,满足事务 ACID 要求。


  • 运营端报表系统:用于统计分析和生成报表,可以处理大量大事务和复杂查询。


由于业务数据量庞大,目前我们的存量数据表行数达到上亿行,还有每天上千万条的增量数据。面对庞大的数据量,我们采用了一种常见的数据处理方案——MySQL 分库分表。即通过将一个大的数据库拆分成多个小的数据库,或将一个大的数据表拆分成多个小的数据表来减轻单一数据库或数据表的负载压力,提高系统的性能和可用性。但是,其存在的痛点也让人束手无策。

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

痛点 1:数据一致性难以保证。分库分表会导致数据分布在不同的数据库或数据表中,数据的一致性难以保证。当多个数据表或数据库之间的数据关联较为复杂时,维护数据的一致性会增加复杂度。

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

痛点2:查询性能下降。分库分表会导致查询的性能下降,因为查询需要对多个数据库或数据表进行查询,增加了查询的时间和成本。非分区键查询需要借助其它的中间件或索引表进行查询。


痛点3:业务变更难度大。分库分表会增加系统的复杂度,当业务变更时,需要对所有分片进行修改和调整,增加了业务变更的难度和风险。


痛点4:数据迁移成本高。分库分表的场景下,数据的迁移成本很高,迁移过程中会涉及数据的拆分、合并和迁移等环节,增加了数据迁移的难度和成本。


痛点5:运维难度高。分库分表会增加系统的运维难度,需要对多个数据库或数据表进行管理和维护,增加了系统的故障排查和维护难度。尤其是自建 MySQL 集群。


痛点6:分库分表后的历史问题数据追溯困难。在分库分表的场景下,历史问题数据追溯问题是一个普遍存在的问题,由于数据被分散存储在多个数据库或数据表中,导致历史数据的追溯变得困难。


另外,我们使用 MySQL 分库分表的方案时,不仅需要依赖第三方工具,而且数据读写都比较复杂。

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

因此,我们决定舍弃 MySQL 分库分表方案,使用分布式数据库。经过初步筛选,在一众分布式数据库中,OceanBase 可以支持 HTAP 混合负载,且在 TPC-C 和 TPC-H 的评测中均取得了好成绩,故而展开了进一步的调研和测试。

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

在深入调研过程中,我们了解到 OceanBase 已经应用在诸多行业,覆盖行业头部企业和一些中小型企业。对于绿普惠而言,OceanBase 的原生分布式、HTAP混合负载、并行执行优秀、存储成本低、数据迁移方便等特点非常吸引我们。


(一)原生分布式


OceanBase 是原生的分布式数据库,可以保证多个数据副本之间的一致性,利用基于 Paxos 分布式一致性协议保证了在任一时刻,只有当多数派副本达成一致时,才能推选一个 Leader,通过保证主副本的唯一性来对外提供数据服务。相比分库分表方案,大大降低了我们的运维难度和业务变更难度。利用 OceanBase 的多地多副本架构,以及高效的 Paxos 一致性协议工程实现,还支持数据副本分别存储在同城和异地,实现异地容灾。

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

(二)HTAP 混合负载


OceanBase 可以同时支持 OLTP 业务与 OLAP 业务,故而被称为 HTAP 数据库。但这不单是一句口号,背后涉及四个关键技术。


1. 读写分离


数据库的读写分离策略是一种将数据库的查询操作和写入操作分离的方案,目的是降低读写操作的相互影响并提升资源利用率。在 HTAP 数据库中,读写分离的应用场景非常普及。OceanBase 数据库天然支持读写分离的功能,即通过 OBProxy 代理服务和修改 OBServer 的配置即可实现业务的读写分离策略。


OceanBase 数据库在读取数据时,提供了两种一致性级别:强一致性和弱一致性。强一致性是指请求路由给主副本读取最新数据;弱一致性是指请求优先路由给备副本,不要求读取最新数据。通过应用侧为执行的 SQL 添加 SQL Hint 来显性开启弱一致性读就可以实现基于注释的读写分离功能,同时也衍生出种各种各样的读写分离策略,比如备优先读、只读 zone、只读副本,我们可以根据实际情况,对读写分离策略进行灵活的配置。


2. 大查询队列


对于数据库来说,相比于单条复杂大查询,让大量的 DML 和短查询尽快返回更有意义。为了避免一条大查询阻塞大量简单请求而导致系统吞吐量暴跌,当大查询和短请求同时争抢 CPU 时,OceanBase 会限制大查询的 CPU 使用。当一个线程执行的 SQL 查询耗时太长,这条查询就会被判定为大查询,一旦判定为大查询,就会进入大查询队列,然后执行大查询的线程会等在一个 Pthread Condition 上,为其它的租户工作线程让出 CPU 资源。

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

配置大查询的参数为 large_query_threshold,执行时间超过这个参数设置的阈值,则认为是大查询。


属性

描述

默认值

5s

取值范围

[1ms, +)


如果系统中同时运行着大查询和小查询,OceanBase 会将一部分 CPU 资源分配给大查询,并通过配置参数 large_query_worker_percentage(默认值为 30%)来限制执行大查询最多可以使用的租户活跃工作线程数。


属性

描述

默认值

30

取值范围

[0, 100]


OceanBase 数据库通过限制大查询能使用的租户活跃工作线程数来约束大查询最多能够使用的 CPU 资源,以此来保证系统还会有足够的 CPU 资源来执行 OLTP(例如交易型的小事务)负载,通过这样的方式来保证对响应时间比较敏感的 OLTP 负载能够得到足够多的 CPU 资源尽快地被执行。


3. 资源隔离


资源隔离并不是一个新概念,传统方式下不共享物理资源,可以理解为物理资源隔离方案。这种方案下不同租户或同一租户内 OLAP 和 OLTP 使用不同的副本,只读副本服务 OLAP,全功能副本服务 OLTP,两种业务不共享物理资源。如果不考虑成本,物理资源隔离无疑是更好的选择。


但现实中,大部分企业都会考虑硬件成本及其资源利用率。一方面,数据库硬件的购买和维护成本高昂,而所有硬件都需要定期换新;另一方面,数据库硬件在进行单项业务处理时,平均占用率水平较低。如果不能充分利用硬件资源,无疑会造成巨大的资源浪费。


而要充分利用硬件资源,不同租户或同一租户内 OLAP 和 OLTP 共享物理资源的逻辑资源隔离方案,自然脱颖而出。实际上,物理资源隔离和逻辑资源隔离不是二选一,而是互为补充的关系。理想的资源隔离方案是在完全物理隔离和逻辑隔离中找到平衡点,OceanBase 会给用户更多自由,帮助我们在面对各类场景下都可以做出最合适的选择。

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

4. SQL 执行


SQL 的执行引擎需要处理很多情况,为什么要对这些情况进行细分呢?是因为 OceanBase 希望在每种情况下都能自适应地做到最优。从最大的层面上来说,每一条 SQL 的执行都有两种模式:串行执行或并行执行,可以通过在 SQL 中增加 hint /*+ parallel(N) */ 来决定是否走并行执行以及并行度是多少。

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

📍 模式一:串行执行


如果这张表或者这个分区是位于本机的,这条路线和单机 SQL 的处理是没有任何区别的。如果所访问的是另外一台节点上的数据,有两种做法:一种是当数据量比较小时,会把数据从远程拉取到本机(远程数据获取服务);当数据量比较大时,会自适应地选择远程执行,把这条 SQL 发送到数据所在节点上,将整条 SQL 代理给这个远程节点,执行结束之后再从远程节点返回结果。如果单条 SQL 要访问的数据位于很多个节点上,会把计算压到每个节点上,并且为了能够达到串行执行(在单机情况下开销最小)的效果,还会提供分布式执行能力,即把计算压给每个节点,让它在本机做处理,最后做汇总,并行度只有 1,不会因为分布式执行而增加资源额外的消耗。


对于串行的执行,一般开销最小。这种执行计划,在单机做串行的扫描,既没有上下文切换,也没有远程数据的访问,是非常高效的。


📍 模式二:并行执行


并行执行同时支持 DML 写入操作的并行执行和查询的并行执行,对并行查询分还会再去自适应地选择是本机并行执行还是分布式并行执行。


对于当前很多小规模业务来说,串行执行的处理方式足够。但如果需要访问大量数据,可以在 OceanBase 单机内引入并行能力,目前,这个能力很多开源的单机数据库还不支持,但只要有足够多的 CPU,可以通过并行的方式使得单条 SQL 处理时间线性缩短,只要有一个高性能多核服务器增加并行就可以了。


针对同样形式的分布式执行计划,可以让它在多机上分布式去做并行,这样可以支撑更大的规模,突破单机 CPU 的数目,去做更大规模的并行,比如从几百核到几千核的能力。 

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

OceanBase 的并行执行框架可以自适应地处理单机内并行和分布式并行。这里所有并行处理的 Worker 既可以是本机上多个线程,也可以是位于很多个节点上的线程。分布式执行框架里有一层自适应数据的传输层,对于单机内的并行,传输层会自动把线程之间的数据交互转换成内存拷贝。这样把不同的两种场景完全由数据传输层抽象掉了,实际上并行执行引擎对于单机内的并行和分布式并行,在调度层的实现上是没有区别的。

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

那么,什么时候适合并行执行,通过充分利用多个 CPU 和 I/O 资源,达到降低 SQL 执行时间的目的呢?当满足下列条件时,使用并行执行会优于串行执行:


  • 访问的数据量大
  • SQL 并发低
  • 要求低延迟
  • 有充足的硬件资源


(三)存储成本


作为一款 HTAP 数据库产品, OceanBase 使用基于 LSM-Tree 架构的存储引擎,同时支持 OLTP 与 OLAP 负载,这种存储架构提供了优秀的数据压缩能力。在 OceanBase 中,增量数据会写入 Clog 和 Memtable 中,OceanBase 的 Memtable 是内存中的 B+ Tree 索引,提供高效的事务处理能力。Memtable 会定期通过 Compaction 生成硬盘持久化数据 SSTable,多层 SSTable会采用 Leveled Compaction 策略进行增量数据重整。SSTable 中数据块的存储分为两层,其中 2M 定长的数据块(宏块)作为 SSTable 写入 I/O 的最小单元,存储在宏块中的变长数据块(微块)作为数据块压缩和读 I/O 的最小单元。

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

在这样的存储架构下, OceanBase 的数据压缩集中发生在 Compaction 过程中 SSTable 的写入时,数据的在线更新与压缩得到了解耦。批量落盘的特性使其采用更激进的压缩策略。OceanBase 从 2.0 版本开始引入了行列混存的微块存储格式( PAX ),充分利用了同一列数据的局部性和类型特征,在微块内部对一组行以列存的方式存储,并针对数据特征按列进行编码。变长的数据块和连续批量压缩的数据也可以让 OceanBase 通过同一个 SSTable 中已经完成压缩的数据块的先验知识,对下一个数据块的压缩进行指导,在数据块中压缩尽量多的数据行,并选择更优的编码算法。

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

与部分在 schema 上指定数据编码的数据库实现不同, OceanBase 选择了用户不感知的数据自适应编码,在给用户带来更小负担的同时降低了存储成本,从历史库角度而言,用户也不需要针对历史库数据做出过多压缩与编码相关的配置调整。OceanBase 之所以能够在事务性能和压缩率之间取得更好的平衡,都得益于 LSM-Tree 的存储架构。


当然, LSM-Tree 架构不是解决数据库压缩所有问题的万金油,如何通过数据压缩降低成本、提升性能是业界一直在讨论的话题。对 B+Tree类的存储引擎进行更高效的压缩也有很多探索,比如基于可计算存储硬件的工作,利用存储硬件内部的透明压缩能力对 B+ Tree类存储引擎的数据压缩进行优化,使其写放大达到了接近 LSM-Tree 架构存储引擎的效果。但 LSM-Tree 中内存数据页更新与数据块落盘解耦,和 sstable 数据紧凑排布的特点,使得 LSM-Tree 相对 B+ Tree类存储引擎,仍然更适合在对查询、更新带来更少负面影响的前提下实现更高效的数据压缩。


(四)OMS 数据迁移


OceanBase 提供的数据迁移工具 OMS(OceanBase Migration Service)支持 MySQL 等关系型数据库与 OceanBase 双向自动迁移和数据校验,可以在大幅提升迁移效率的同时,进一步降低数据不一致的风险。OMS 还提供丰富的数据订阅 CDC 能力,支持数据流到 Kafka、MQ 等消息队列的同步。

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

在传统的数据库迁移方案中,为了保障迁移任务的稳定性和数据的一致性,通常通过停机迁移的方式进行数据迁移。停机期间需要暂时停止写入数据至源端数据库,待迁移完成并确认数据一致性后,再切换业务数据库。但停机迁移的耗时和业务数据量、网络状况相关,在业务量巨大的情况下,数据库的停机迁移可能耗时数天,对业务影响较大。


OMS 提供的不停服数据迁移功能,不影响迁移过程中源数据库持续对外提供服务,能够最小化数据迁移对业务的影响。在完成结构迁移、全量数据迁移和增量数据迁移后,源数据库的全量和增量数据均已实时同步至目标数据库中,数据校验通过后,业务可以从源端切换至目标端。

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

我们通过 OceanBase 替换 MySQL 分库分表的方案如下:


  • 通过 OMS 将异构数据库分库分表同步至 OceanBase 原生分区表(多表汇聚同步)。
  • 迁移至 OceanBase 后多个实例融合为一个实例,摆脱中间件,大幅提升存储可扩展性。
  • OceanBase 的 HTAP 模式,满足了业务上分析查询的业务得以前置,无需等待 T+1 数据,直接于在线库实现实时决策等分析需求。

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

基于该方案,我们在测试环境中部署了三个 OceanBase 3.1.4 版本的集群节点,并对运维监控工具、分区功能、分区表读写性能等方面逐一展开了测试。


(一)OceanBase 集群运维监控


我们使用了 OceanBase 的运维工具 OCP 来实现集群的运维管理和监控告警,利用 OCP 的告警功能,配置企业微信告警渠道,实现告警信息的实时推送到企业微信,保证了开发能够第一时间获取到 OceanBase 集群重要的告警信息。

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

(二)分区功能测试


我们的关键业务表是减排行为表,在 OceanBase 中,我们给这张表做了二级分区,一级分区键为租户 id,二级分区键为手机号 sha256 加密字符串,表的定义类似于:

CREATE TABLE t1 (tenant_id int, phone_number varchar(64)) 
    PARTITION BY LIST(tenant_id)
        SUBPARTITION BY HASH(phone_number) SUBPARTITIONS 100
    (PARTITION p0 VALUES IN(1),
     PARTITION p1 VALUES IN(2),
     PARTITION p2 VALUES IN(3)
    );

OceanBase 提供的分区功能非常强大,详细分区表可以点击文末“阅读原文”查看官方文档。


(三)分区表性能测试


使用 OceanBase 3.1.4 社区版本可以创建分区表或者非分区表。对于非分区表,在数据量巨大的情况下性能肯定不好,所以我们没有对其进行压测。对于分区表,在数据量大的情况下,才能充分发挥其性能,所以我们给分区表提前写入了三亿条数据,并且以递增线程数的方式去进行压测,每次压测执行三分钟。然后分析结果中的吞吐量,当吞吐量无法继续增加时,认为此时的线程数是系统能承受的最大并发数。


我们的压测脚本分为两部分:第一部分是增删改查,测试插入、查询、修改,相当于 read write 性能;第二部分是事务,测试插入、修改,相当于是 write only 性能。测试环境是三台 32c 128g 的机器,测试的版本是较早的 OceanBase 3.1.4 社区版。测试结果如下表所示:

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

注:OceanBase 3.1.4 社区版的 sysbench 详细性能测试报告详见性能测试官方文档。


(四)测试过程中遇到的一些问题


在测试过程中,我们发现当 OceanBase 3.14 社区版本在二级分区表数据量过大时,创建索引失败。不过该问题已经在 OceanBase 3.15 版本被解决。


另外,OceanBase 的 MySQL 模式租户下,有 global 索引的分区表不支持 insert ignore,执行时直接报了 not supported。我们猜测不支持的原因是全局索引插入成功之后,如果主表插入失败,这时不仅要回滚主表的改动,还需要回滚全局索引的改动。这个回滚数据的过程的实现复杂度非常高,OceanBase 暂时还没有支持该功能。

obclient [test]> create table t1(c1 int) partition by hash(c1);
Query OK, 0 rows affected (0.260 sec)

obclient [test]> create index idx on t1(c1) global;
Query OK, 0 rows affected (1.224 sec)

obclient [test]> INSERT IGNORE INTO t1 values(1);
ERROR 1235 (0A000): ignore with global index not supported

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

在选择使用原生分布式 OceanBase 替代 MySQL 分库分表方案后,收益符合预期,主要包括几点:


  • 降低运维难度:相比分库分表方案,大大降低了我们的运维难度和业务变更难度。而且完全兼容 MySQL 的语法,强大的 CDC 能力支持,方便多种类型的下游进行数据消费。
  • 灵活的动态扩容:单集群最大可超过上千节点,数据容量可以超过 PB 级。
  • 强大的数据更新能力:基于关系型数据库的更新能力,副本间毫秒级极低延迟。
  • HTAP 一体化:一套引擎处理 OLTP 和基本的 OLAP 场景,同时基于资源组隔离技术,提供 OLTP/OLAP 业务资源隔离的可靠方案,免去复杂的实时数仓建设。

避免分库分表,绿普惠的分布式数据库选型与实践-鸿蒙开发者社区

  • 分布式并行计算引擎:强大的 SQL 优化器和执行器,支持向量化计算和海量数据的并行计算分析。


经过探索测试,我们验证了 OceanBase 在性能、成本等方面的优势,符合当前业务发展的需求,且 HTAP 混合负载能力与我们的实际业务场景非常契合,后续必定会有更加深入的合作。


文章转载自公众号:OceanBase

分类
标签
已于2023-10-31 14:45:29修改
收藏
回复
举报
回复
    相关推荐