- 设计目标 及 设计思路
1. PB级存储量、数十万级TPS、数百级QPS。
2. 支持跨行跨表事务。
3. 可扩展、低成本、易用。
传统的数据库分库分表在性能上满不足不了需求的。BigTable仅支持单行事务。Google Percolator 使用BigTable + 2PC 技术实现分布式事务,但是性能不满足需求(2-5s),比较适合网页建库这样的半线上业务。
分析淘宝的业务发现,短时(1天)内数据更新量并不是很大,在千万级别左右。OceanBase 基于此采用单台机器记录更新数据(称作增量数据),加上之前某个时刻的基线数据组成实时数据。单台机器记录更新数据的好处是避免了分布式事务,大幅度的提升了事务的性能。
- 架构设计
系统主要分为四部分,即中心节点(RootServer)、更新服务(UpdateServer)、数据节点(ChunkServer)、代理节点(MergeServer)。其中RootServer 与 UpdateServer 均为强一致模型,且统计部署,UpdateServer通过租约方式选主(RootServer充当外围Token管理节点)。MergeServer 与 ChunkServer可以同机部署。
RootServer
RootServer一主一备,通过Linux HA实现高可用,通过VIP对外提供服务,切主服务。
持有UpdateServer的Token,UpdateServer通过强一致保证数据的可靠性,但是牺牲了可用性(CAP理论),UpdateServer单点正是OceanBase的瓶颈。
RootServer 维护集群的元信息,主要是ChunkServer与子表的映射关系,OceanBase采用了一级索引,每个子表连续存储。
UpdateServer
UpdateServer主备之间先同步日志再提交,保证切主之后数据是最新的。数据先写入内存,达到一定数量之后刷入磁盘,格式与ChunkServer一致SSTable,相对ChunkServer存储的数据更稀疏一些。单台机器记录全部更新数据,很容易的实现了跨行跨表的事务。
UpdateServer作为系统内唯一接收写入的服务,且单点提供服务(备份相当于冷备)。UpdateServer的单机性能对于系统至关重要(网络、磁盘、框架等都有优化)。系统通过定期合并 和 数据分发及时的将更新数据合并 或者 下发到ChunkServer。
ChunkServer
存储子表(256MB),子表内通过Block(4KB-64KB)管理。ChunkServer分为快缓存和行缓存。MergeServer接收的读请求会先请求ChunkServer,再请求UpdaServer,然后合并结果返回客户端。
MergeServer
协议解析、词法语法分析、制定逻辑物理计划。
跨机房支持
每个机房具备完整的RootServer、UpdateServer、ChunkServer、MergeServer模块。RootServer只负责本机房内的ChunkServer元信息。所有机房的UpdateServer只有一个主,其他的都是备份。
定期合并与数据分发
1. UpdateSever内存表切换,旧表禁止更新,后续更新写入新表。
2. UpdateSever通知RootServer,版本号变化,RootServer通过心跳通知ChunkServer拉取数据。
3. ChunkServer启动定期合并 或者 数据分发机制,拉取更新数据。
定期合并保证拉取更熟之后写入SSTable文件内,生成新的基线数据。数据分发只是将更新数据写入本地缓存。本地缓存 与 写入磁盘 对数据的可靠性影响较大,机器故障时对于两种情况的处理机制不尽相同。同时需要注意的是,定期合并是一个开销比较大的操作,一般在服务低峰期执行。
ChunkServer上相同子表的不同副本可能数据是不一致的,但是并不影响其读操作,完成合并或者分发的用新数据 + UpdateServer的新表,未完成的用旧数据。
- 架构剖析
UpdateServer一致性选择
从系统维护性考虑,为了保证数据的高可靠,系统选择了强一致性,否则在故障情况下数据的修复需要大量的繁琐人工操作,且不敢确定完全修复。
UpdateServer在网络或者备机异常的情况下,允许提出故障机器,但是需要在此之前通知RootServer,防止故障机器恢复后切为主。主机故障、网络故障、备机故障三个中任何一个故障都能保证服务正常运行,如果三个中任意两个故障保证不了服务正常,但是数据不会丢失。
数据结构
基线数据
整张表通过主键(可以是多列)组织成B+树。
B+树的叶子节点是一个左开右闭的连续存储的子表。
子表以多副本(默认3个)存储在不同的ChunkServer上。
子表可以合并、拆分,保证子表大小是均匀的。
子表包含一个或者多个SSTable文件。
SSTable通过Block(4KB-64KB)进行管理。
Block是压缩的最小单位。
增量数据
更具更新时间维护多喝版本。
最新版本在内存中通过B+树维护一个MemTable。
MemTable区分冷热,在数据转储时需要切换。
转储为SSTable文件,通过4KB-8KB的Block进行管理。
每台UpdateServer使用RAID1进行,double本分。
读写事务
只读事务,MergeServer充当协调者的角色,不需要与UpdateServer交互,ChunkServer会拉去UpdateServer数据进行合并。
读写事务,MergeServer先拉去ChunkServer数据作为参数发送给UpdateServer,执行事务并返回。
UpdateServer单点性能
容量:1亿次更新,每次更新100字节,1kw次插入,每次插入1000字节,1亿 * 100字节 + 1kw * 1000 = 20G,内存膨胀为2倍,即40G。手动转储 + 数据分发可以有效缓解内存问题。
磁盘:SAS磁盘IOPS 300,可以通过RAID缓存解决,通过电容保证断点时数据刷入磁盘。
网络:20WQPS,每次读100字节,20w * 100 = 20MB带宽。
分层结构
逻辑上OceanBase系统分为分布式存储引擎层 和 关系型数据库功能层。类似MemSQL(类似UpdateServer)+ GFS,后续也会分这两层进行介绍。
- 总结
本章只是架构上的一个初探,重点是引入了UpdateServer这种单点更新的技术。很多细节本章并未涉及,包括事务与并发控制、单机引擎的具体实现等细节。对于系统线上运行的实际情况,包括性能、可运维性、跨机房支持的情况等等,如果不是一线亲身参与很难有所掌握。但 OceanBase作为国内分布式数据库的鼻祖,且在工业和商业场景下得到了验证,对于业界的贡献是有目共睹的,它证明了高吞吐的、支持跨行跨表的事务分布式数据库是可行的。