背景介绍
在业务逐渐增长的 4 年多里,我公司的的数据库经历了从 单表数十 GB 到上百 GB 的过程。基于数据量的升级变迁,我们的数据库也经历了 2 次架构迭代,并在探索
-
三代数据库架构:
- 第一代数据库架构 —— 一主一从集中式部署的时代。
- 第二代数据库架构 —— 垂直分库,一主多从的时代。
- 第三代数据库架构 —— 云上一主一从一日志节点,基于域名&vip实现高可用的时代。
第三代数据库架构短板
OLTP 场景需求痛点
截止目前账务系统的核心表累计数据量已达到单表 8000万行以上,还在高速增长中。监管要求金融行业历史数据至少保留 5 年以上。这给数据库系统带来了不小的挑战:
-
海量的历史交易与账务数据堆积在 MySQL 数据库中,使数据库越发臃肿,维护困难(在线 DDL 变更、数据迁移、磁盘容量瓶颈、磁盘 IO 瓶颈等)。
- ccs_order_hst表现有8800万,56G数据,日均增长18万,ibd文件日均增长120MB,预计到年末将趋近80G。
-
用户对历史交易订单的查询(OLTP 场景)是必备功能,这些海量的历史数据会根据用户需求通过 微信公众号、APP 终端等渠道进行实时查询(内部、外部用户)。此场景决定了不能通过传统的离线大数据方案来满足需求。需要一种偏向于前台、中台的数据治理方案。
-
海量数据也会导致核心跑批时间延长,同时导致数据库单点性能瓶颈,应用可以加分片,但是数据库无法水平扩展。
传统分库分表解决方案痛点
- 分表跨实例后,产生分布式事务管理难题,一旦数据库服务器宕机,有事务不一致风险。
- 分表后,对 SQL 语句有一定限制,对业务方功能需求大打折扣。尤其对于实时报表统计类需求,限制非常之大。对join语句不友善。
- 分表后,需要维护的对象呈指数增长(MySQL 实例数、需要执行的 SQL 变更数量等)。
分布式数据库技术选型
基于第三代数据库架构的核心痛点,我们需要探索新的数据库技术方案来应对业务爆发式增长所带来的挑战,为业务提供更好的数据库服务支撑。
分布式数据库有如下显著特点:
- 无限水平扩展能力
- 在线 DDL 操作不锁表
- 分布式强一致性,确保金融数据 100% 安全
- 完整的分布式事务处理能力与 ACID 特性
选型出发点
-
是否开源,自主可控
- 在 GitHub的活跃度及社区贡献者方面,TiDB是国际化的全球开源级项目,是 NewSQL 行业中的代表性产品。
- Oceanbase作为一款在阿里孵化的一款分布式数据库产品,也于2021年6月1日在Gitee开源,并积极推进社区建设与在线培训
-
MySQL 协议兼容性
- Tidb与Oceanbase都与 MySQL 5.7 高度兼容,需要应用改造的地方少
-
市场占有率
- Tidb与Oceanbase 在国内分布式数据库市场占有率分列第一和第二
Tidb 与 Oceanbase 具体比较
1、产品发展历史
-
Tidb
- PingCAP 成立于 2015 年4月,是一家企业级开源分布式数据库厂商,注册资本 1 亿美元,D 轮融资 2.7 亿美金。
- 2019年9月于Github开源,有2.81万star关注,文档齐全,对使用人员友好,有数据库开发规范(https://asktug.com/t/topic/93819)
- 具备PCTA与PCTP两级认证,因疫情影响,培训与线下考试都已停止
-
Oceanbase
- 2010年于阿里巴巴集团诞生产品,2020年6月正式进行独立公司化运作,注册资本 1 亿元
- 2021年6月1号于gitee正式开源,有521star关注,文档较少,尚需完善
- 具备OBCA、OBCP、OBCE三级认证,线上培训,线下进行考试
2、使用案例
-
Tidb
- 广泛应用于互联网与金融行业,长沙目前已知案例包括和包支付、澳优乳业、福米科技、兴盛优选等,在全国有股份制银行光大、浦发,头部城商行,北京银行等金融行业案例,产品稳定性得到有效验证,企业用户和社区用户超过 1500 家。
-
Oceanbase
- 服务于蚂蚁集团内部、移动运营商,网商银行等大的金融保险机构
3、产品架构
- TiDB 分布式数据库采用 Shared-Nothing 架构,同时整体架构拆分成了计算、存储、调度,多个模块,各模块之间互相通信,可运行在普通 PC、K8S 上,载体多样。扩展性上,可按需灵活扩展计算或存储资源,提高系统整体的吞吐。
- OceanBase 数据库采用 Shared-Nothing 架构,各个节点之间完全对等,每个节点都有自己的 SQL 引擎、存储引擎,运行在普通 PC 服务器组成的集群之上
4、存储引擎
- Tidb HTAP混合数据库
- Oceanbase准“内存数据库” + LSMTree存储,避免随机写
5、标准SQL语句支持
-
TiDB
- 1、支持标准 SQL,DDL 、DML 、DCL、DQL(包括分析函数,各种查询)。
- 2、部分支持完整性约束,不支持check约束和外键约束功能,但支持语法兼容。
- 3、支持表管理、视图管理。
- 4、部分支持分区表,支持 range 和 hash 分区,不支持 list 分区和复合分区;支持全局索引,不支持本地索引,但在后续的 5.0 版本中将全面支持分区表,解除前述相关限制。
- 5、不支持临时表、存储过程,自定义函数,表空间,触发器等创建和使用。
- 6、支持 sequence 创建和使用。
- 7、不支持添加列的auto_increment属性,可以用AUTO_RANDOM(仅支持主键)语法来保证主键唯一性(不需要连续或递增)。
-
Oceanbase支持
- 1、支持大部分查询功能,包括支持单、多表查询;支持子查询;支持内连接、半连接以及外连接;支持分组、聚合;常见的概率、线性回归等数据挖掘函数等
- 2、暂不支持空间数据类型和 JSON 数据类型
- 3、不支持空间分析函数、JSON 函数和性能模式函数
- 4、支持一级分区,模板化和非模板化二级分区,二级分区支持 HASH、KEY、RANGE、RANGE COLUMNS、LIST、LIST COLUMNS 分区
6、分布式事务读写强一致
-
Tidb
-
TiDB 支持分布式事务,提供乐观事务与悲观事务两种事务模型 。TiDB 3.0.8 及以后版本,TiDB 默认采用悲观事务模型。
- 乐观并发控制期望事务间数据冲突不多,只在提交阶段检测冲突能获取更高的性能。悲观并发控制更适合数据冲突较多的场景,能够避免乐观事务在这类场景下事务因冲突而回滚的问题,但相比乐观并发控制,在没有数据冲突的场景下,性能相对要差。
-
TiKV 的 MVCC 实现是通过在Key后面添加版本号来实现
- 当新写入的数据覆盖旧的数据时,旧的数据不会被替换掉,而是与新写入的数据同时保留,并以时间戳来区分版本。
- 数据版本过多会占用大量空间,同时影响数据库的查询性能, GC 的任务便是清理不再需要的旧数据。GC 会被定期触发,默认情况下每 10 分钟一次。每次 GC 时,首先,TiDB 会计算一个称为 safe point 的时间戳(默认为当前时间减去 10 分钟),接下来 TiDB 会在保证 safe point 之后的快照全部拥有正确数据的前提下,删除更早的过期数据。
- GC 在执行过程中会删除大量数据, 可能会对线上业务造成影响。 可通过修改 TiKV 配置中的 gc.max-write-bytes-per-sec 限制 GC worker 每秒数据写入量, 降低对正常请求的影响, 0为关闭该功能。
-
TiDB 实现了快照隔离 (Snapshot Isolation, SI) 级别的一致性。为与 MySQL 基本保持一致,又称其为“可重复读”。
- 事务开始时获取 start timestamp,也是快照的版本号;
- 事务提交时获取 commit timestamp,同时也是数据的版本号
- 事务只能读到在事务 start timestamp 之前最新已提交的数据事务在提交时会根据 timestamp 来检测数据冲突
- MySQL 可重复读隔离级别在更新时并不检验当前版本是否可见,也就是说,即使该行在事务启动后被更新过,同样可以继续更新。这种情况TiDB 会导致事务回滚,导致事务最终失败,而 MySQL 是可以更新成功的。
-
-
Oceanbase
- 默认Read-Committed,通过 MVCC+TSO 实现
7、锁机制
-
Tidb
- 能检测到死锁并解除死锁,悲观锁和乐观锁都支持,默认悲观锁,悲观事务的行为和 MySQL 基本一致,在执行阶段就会上锁,先到先得,避免冲突情况下的重试,可以保证有较多冲突的事务的成功率。但如果业务场景本身冲突较少,乐观锁的性能会更有优势
- TiDB 没有间隙锁,当无法保证符合过滤条件的数据唯一时,MySQL 会锁住过滤条件能涵盖到的所有行:范围锁,全表锁。TiDB 只会对读取到的行加锁。
-
Oceanbase
- 只有行锁,没有表锁
- 只有写锁(X锁),没有读锁
8、高可用性和扩展性
-
TiDB
- 计算、管理、控制节点,任意挂一个都对集群整体无影响
- 两地三中心的架构下,网络延迟保证 10 ms 以内,保证单中心失效的情况下,可以保证 RPO 为 0,PTO 30 s,即业务不丢数据,业务能在 30s 内恢复,同时还有双中心方案,可以在同城双中心部署集群,做到同城双活。
- 底层数据分片粒度较小,灵活度较强。
- TiKV、TiDB、PD都支持在线扩容、缩容,集群工作正常,业务不受影响
-
Oceanbase
- 至少3个zone,单个zone服务器宕机无影响。
- 集群的资源扩容就是为每个Zone增加相应的节点。
- 租户资源的扩容是通过调整其Resource Unit的规格和数量来完成。
9、数据库运维能力
-
Tidb
-
Tidb安装部署更为简单,架构清晰,利用tiup组件,半个工作日能搭建测试集群
-
大表DML
- 在亿级数据及索引存在的情况下,秒级对一段时间范围内的流水数据进行删除,同时对记录和表不造成任何影响。
- 自主测试drop和truncate 200万级别的表,tidb上耗时不到1s,mysql上要3-4s
-
Online DDL
- 针对包含亿级数据的表增加字段。在DDL进行的过程中对业务无影响。
- 自主测试200万级别的表加列和减列,tidb上耗时不到1s,mysql上要6-9s
- 加索引操作由于需要回填数据,因此执行时间略长。而在回填数据期间,需要将回填的数据写入 TiKV, 对 TiKV 会产生额外的写入压力,从而造成一些性能影响。
- 对业务开发较为友善,业务如需经常发版,表结构可能也需要经常迭代,TiDB 的相关功能可以较好满足商业敏捷性的要求。
-
-
Oceanbase
-
组件较多,有Unit、资源池、多租户多层机构,新的版本通过obd组件,0.5个工作日也能运行起来;
-
Online DDL
- 表建好后,主键不能更改。如果需要修改,只能删表重建。
- 列类型修改有较大限制。Varchar 长度只能由短变长,不能由长变短。
- 索引生效时间较长,建议在建表时将索引语句一并纳入。
-
10、最佳实践
-
Tidb
- 建表时避免设置递增主键,同时将大表配置 Region 打散,避免热点分区问题
- 为了确保事务的 ACOD,TiDB 中的事务操作都需要经过两阶段提交,在 TiDB 最新发布的 5.0 中也使用了索引组织表、近似一阶段提交 来降低因为频繁的网络交互致使延迟变高的影响,总体而言,在延迟要求严格的场景中, 使用 5.0 中的关于延迟的优化,和小事务打包来获取极致的低延迟。
START TRANSACTION; UPDATE my_table SET a='new_value' WHERE id = 1; UPDATE my_table SET a='newer_value' WHERE id = 2; UPDATE my_table SET a='newest_value' WHERE id = 3; COMMIT;
-
目前单个事务大小限制在 10GB, 超过 10GB 的事务依然会报错, 不过 10GB 的事务已经能够覆盖大多数场景了:
- 客户端在提交之前, 数据都写在内存中, 而数据量过多时易导致 OOM (Out of Memory) 错误。
- 在第一阶段写入数据耗时增加,与其他事务出现读写冲突的概率会指数级增长, 容易导致事务提交失败。
- 最终导致事务完成提交的耗时增加。
-
为了使性能达到最优, 建议每 100~ 500 行写入一个事务。
-
事务对内存的占用可能会有 3~4 倍的放大, 10GB 大的事务可能会占用 30~40GB 的内存。如果需要执行特别大的事务,需要提前做好内存的规划, 避免对业务产生影响
分布式选项建议与设想
-
Tidb 与 Oceanbase 相比,具备使用范围广,业界认可度高,社区更为成熟的优势。
-
对于我司而言,当前的关注焦点不是 TiDB 或者 OceanBase 是否稳定可靠(据在和包的学长,和在福米的运维朋友反馈,Tidb在应对高并发和去Oracle时,表现都不错),而是怎么才能快速获取到 TiDB 或者 OceanBase 的最佳实践经验,将其纳入企业基础技术栈之内。
-
Tidb最佳实践(和包 + 马上消费的实践经验)
- 使用 NVME 协议的 SSD
- 使用万兆网卡的服务器和交换机
- 结合K8S容器云平台,降低硬件成本,马上消费作为国内第一家将所有 TiDB 都运行在 Kubernetes 容器云上的金融企业,将最小 TiDB 集群资源从 6 台服务器 ( pd-server 与 tidb-server 混合部署)降低成了 2 pods tidb-server、3 pods pd-server、3 pods tikv-server,硬件成本降低为原来的 30% 左右(需要技术积累与多方面测试,节点数多的情况下更有效果)