javazx 发表于 2017-3-6 14:41:55

《大规模分布式存储系统》第9章 分布式存储引擎【9.5】

9.5 消除更新瓶颈
UpdateServer单点看起来像是OceanBase架构的软肋,然而,经过OceanBase团队
持续不断地性能优化以及旁路导入功能的开发,单点的架构在实践过程中经受住了
线上考验。每年淘宝网“双十一”光棍节,OceanBase系统都承载着核心的数据库业
务,系统访问量出现5到10倍的增长,而OceanBase只需简单地增加机器即可。
当然,UpdateServer单点架构并不是不可突破。虽然目前UpdateServer单点架构
还不是瓶颈,但是OceanBase系统设计时已经留好了“后门”,以后可以通过对系统打
补丁的方式支持UpdateServer线性扩展。当然,这里可能会做一些牺牲,比如短期内
暂不支持全局事务,只支持针对单个用户的事务操作。
本节首先回顾OceanBase已经实现的优化工作,包括读写性能优化以及旁路导入
功能,接着介绍一种数据分区实现UpdateServer线性扩展的方法。
9.5.1 读写优化回顾
OceanBase UpdateServer相当于一个内存数据库,其架构设计和“世界上最快的内
存数据库”MemSQL比较类似,能够支持每秒数百万次单行读写操作,这样的性能对
于目前关系数据库的应用场景都是足够的。为了达到这样的性能指标,我们已经完
成或正在进行的工作如下。
1.网络框架优化
9.2.2 节中提到,如果不经过优化,单机每秒最多能够接收的数据包个数只有
10万个左右,而经过优化后的libeasy框架对于千兆网卡每秒最多收包个数超过50
万,对于万兆网卡则超过100万。另外,UpdateServer内部还会在软件层面实现多块
网卡的负载均衡,从而更好地发挥多网卡的优势。通过网络框架优化,使得单机支
持百万次操作成为可能。
2.高性能内存数据结构
UpdateServer的底层是一颗高性能内存B树。为了最大程度地发挥多核的优势,B
树实现时大部分情况下都做到了无锁(lock-free)。测试数据表明,即使在普通的16
核机器上,OceanBase B树每秒支持的单行修改操作都超过150万次。
3.写操作日志优化
在软件层面,写操作日志涉及的工作主要有如下几点:
1)成组提交。将多个写操作聚合在一起,一次性刷入磁盘中。
2)降低日志缓冲区的锁冲突。多个线程同时往日志缓冲区中追加数据,实现时
需要尽可能地减少追加过程的锁冲突。追加过程包含两个阶段:第一个阶段是占
位,第二个阶段是拷贝数据,相比较而言,拷贝数据比较耗时。实现的关键在于只
对占位操作互斥,而允许多线程并发拷贝数据。例如,有两个线程,线程1和线程
2,他们分别需要往缓冲区追加大小为100字节和大小为300字节的数据。假设缓冲区
初始为空,那么,线程1可以首先占住位置0~100,线程2接着占住100~300。最
后,线程1和线程2并发将数据拷贝到刚才占住的位置。
3)日志文件并发写入。UpdateServer中每个日志缓冲区的大小一般为2MB,如
果写入太快,那么,很快会产生多个日志缓冲区需要刷入磁盘,可以并发地将这些
日志缓冲区刷入不同的磁盘。当然,UpdateServer目前并没有实现2和3这两个优化
点。在硬件层面,UpdateServer机器需要配置较好的RAID卡。这些RAID卡自带缓
存,而且容量比较大(例如1GB),从而进一步提升写磁盘性能。
4.内存容量优化
随着数据不断写入,UpdateServer的内存容量将成为瓶颈。因此,有两种解决思
路。一种思路是精心设计UpdateServer的内存数据结构,尽可能地节省内存使用;另
外一种思路就是将UpdateServer内存中的数据很快地分发出去。
OceanBase实现了这两种思路。首先,UpdateServer会将内存中的数据编码为精
心设计的格式,从9.3.1节中可以看出,100以内的64位整数在内存中只需要占用两个
字节。这种编码格式不仅能够有效地减少内存占用,而且往往使得CPU缓存能够容
纳更多的数据,从而弥补编码和解码操作造成的性能损失。另外,当UpdateServer的
内存使用量到达一定大小时,OceanBase会自动触发数据分发操作,将UpdateServer
的数据分发到集群中的ChunkServer中,从而避免UpdateServer的内存容量成为瓶颈。
当然,随着单机内存容量变得越来越大,普通的2U服务器已经具备1TB内存的扩展
能力,数据分发也可能只是一种过渡方案。
9.5.2 数据旁路导入
虽然OceanBase内部实现了大量优化技术,但是UpdateServer单点写入对于某些
OLAP应用仍然可能成为问题。这些应用往往需要定期(例如每天,每个月)导入大
批数据,对导入性能要求很高。为此,OceanBase专门开发了旁路导入功能,本节介
绍直接将数据导入到ChunkServer中的方法(即ChunkServer旁路导入)。
OceanBase的数据按照全局有序排列,因此,旁路导入的第一步就是使用Hadoop
MapReduce这样的工具将所有的数据排好序,并且划分为一个个有序的范围,每个范
围对应一个SSTable文件。接着,再将SSTable文件并行拷贝到集群中所有的
ChunkServer中。最后,通知RootServer要求每个ChunkServer并行加载这些SSTable文
件。每个SSTable文件对应ChunkServer的一个子表,ChunkServer加载完本地的SSTable
文件后会向RootServer汇报,RootServer接着将汇报的子表信息更新到RootTable中。
例9-7 有4台ChunkServer:A、B、C和D。所有的数据排好序后划分为6个范
围:r1(0~100]、r2(100~200]、r3(200~300]、r4(300~400]、r5(400~
500]、r6(500~600],对应的SSTable文件分别记为sst1,sst2,……,sst6。假设每
个子表存储两个副本,那么,拷贝完SSTable文件后,可能的分布情况为:
A:sst1,sst3,sst4
B:sst2,sst3,sst5
C:sst1,sst4,sst6
D:sst2,sst5,sst6
接着,每个ChunkServer分别加载本地的SSTable文件,完成后向RootServer汇
报。RootServer最终会将这些信息记录到RootTable中,如下:
r1(0~100]:A、C
r2(100~200]:B、D
r3(200~300]:A、B
r4(300~400]:A、C
r5(400~500]:B、D
r6(500~600]:C、D
如果导入的过程中ChunkServer发生故障,例如拷贝sst1到机器C失败,那么,旁
路导入模块会自动选择另外一台机器拷贝数据。
当然,实现旁路导入功能时还需要考虑很多问题。例如,如何支持将数据导入
到多个数据中心的主备OceanBase集群,这里不会涉及这些细节。
9.5.3 数据分区
虽然我们坚持认为通过单机性能优化以及硬件性能的提升,UpdateServer单点对
于互联网数据库业务不会成为瓶颈。但是,随着OceanBase的应用场景越来越广,例
如,存储原始日志,我们也可能需要实现更新节点可扩展。本节探讨一种可能的做
法。
OceanBase可以借鉴关系数据库中的分区表的概念,将数据划分为多个分区,允
许不同的分区被不同的UpdateServer服务。例如,将所有的数据按照哈希的方式划分
为4096个分区,这样,同一个集群中最多允许4096个写节点。
如图9-11所示,可以将Users表格和Albums的user_id列按照相同的规则做哈希,
这样,同一个用户的所有数据属于相同的分区。由于同一个分区只会被同一个
UpdateServer服务,因此,保证了同一个用户下读写操作的事务性,另外,不同用户
之间的事务可以通过两阶段提交或者最终一致性的方式实现。这种方式实现起来非
常简单,而且能够完全兼容SQL语法。
图 9-11 哈希分区SQL语法
从图8-1中的整体架构图可以看出,在目前的单更新节点架构中,UpdateServer进
程总是与ChunkServer进程部署到不同的服务器,而且两种服务器对硬件的要求不
同。如果OceanBase支持哈希分区,还能够将UpdateServer进程和ChunkServer进程部
署到一起,这样部署起来会更加方便。
除了哈希分区,OceanBase还能够通过范围分区实现更新节点可扩展,即不同的
用户按照user_id有序分布到多台UpdateServer。虽然支持UpdateServer线性可扩展的
架构看似“比较优雅”,但是,这件事情并不紧急。这是因为,OLTP类应用对性能的
需求是有天花板的(例如全世界人口共50亿,即使其中五分之一的人都在某一天产
生了一笔交易,这一天的总交易笔数也只有10亿笔),单UpdateServer对于OLTP类数
据库业务的性能是足够的。


页: [1]
查看完整版本: 《大规模分布式存储系统》第9章 分布式存储引擎【9.5】