-
Notifications
You must be signed in to change notification settings - Fork 80
Wasp设计
项目背景
最近几年随之Bigtable和NoSQL的兴起,社区产品HBase逐步走向NoSQL系统的主流产品,优势明显然而缺点也明显,大数据平台下的业务由SQL向NoSQL的迁移比较复杂而应用人员学习成本颇高,并且无法支持事务和多维索引,使得许多业务无法享用来自NoSQL系统中线性拓展能力。Google内部MegaStore(F1是MegaStore的升级版)就作为Bigtable的一个补充而出现,在Bigtable的上层支持了SQL、事务、索引、跨机房灾备,并成为大名鼎鼎的Gmail、APPEngine、Android Market的底层存储。因此我们决定以MegaStore为理论模型进行探索如何在HBase系统上不牺牲线性拓展能力的同时又能提供跨行事务、索引、SQL的功能。通过简单的用户入口SQL,用户可以不需要关注hbase的schema设计,极大的简化了用户的数据迁移和学习成本。
详情见http://research.google.com/pubs/pub36971.html, http://research.google.com/pubs/pub38125.html。
Wasp的命名缘由
Wasp翻译为中文是黄蜂,我们希望系统像黄蜂一样犀利。系统的开发由HBase开发维护团队(团队主管:竹庄)承担。
Wasp的特性
Wasp是分布式的、支持SQL的、事务型数据库:
-
支持索引:本地索引、全局索引
-
支持表分区(EntityGroup),分区可再分区、合并、移动部署,进而系统可线性拓展
-
支持数据类型:int64、int32、string、double、float、datetime
-
SQL语法特性:select、update、delete、insert、create table、delete table、create index、drop index等
-
支持跨行事务,支持NoSQl之上的索引与实体的ACID
-
支持MVCC
-
JDBC访问接口
-
易用的监控:Ganglia – metrics
主要适合场景是读多于写的场景,写的过程会保证事务原子性,因此写入性能比直接写入NoSQL系统要略低。Wasp能在多种不同配置的硬件上运行,通常的描述是商业硬件。在实践中,为了能够有效地利用HBase,Wasp大多是与HBase与Hadoop安装在一起的。这样能很大程度地减少对网络IO的需求,同时能加快处理速度。当在同一服务器上运行Wasp和Hadoop和HBase时,最少会有4个Java进程(DataNode、TaskTracker和RegionServer和FServer)在运行,而且在执行MapReduce任务时,进程数还会激增。要有效地运行所有这些进程,需要一定数量的内存、磁盘和CPU资源,并且这个资源数量有一个最低值。有关HBase和Hadoop的知识请查看《HBase权威指南》《Hadoop权威指南》。有关机器硬件的选型应该直接参考HBase的选型,Wasp是个不对内存占用过多要求的系统,只消耗一定的常规的量的cpu。通常hbase机器中的cpu和内存都有大量剩余,故而,只要够用即可。
Wasp的整体架构
图1
从上面的结构中我们看出,系统有一个中心点Master,若干个数据节点FServer组成。
Master有Backup节点,Active Master挂掉,Backup Node会自动接替Active并承担Active的作用。Master负责了表控制逻辑,Entity Group分配,元数据管理(表元数据,EntityGroup位置元数据),数据节点FServer的控制与管理。
FServer负责系统的请求,EntityGroup的部署服务,SQL的解析分发与执行,以及合并最后的结果并返回给客户端。
值得一提的是,FServer与Master的一些控制信息是通过Zookeeper来交互的。
Wasp是怎样存储数据的
理解它的存储结构有利于设计更高效的应用,最大化系统的性能。当某些原因导致系统重大问题时,用户可能需要修复Wasp中的数据。此时用户就需要知道数据存在何处并且知道如何从HBase中访问其中的内容。当然这种情况不应当发生,但实际的系统中任何异常情况都是可能的。
从图1中可以看出Wasp处理了三种HBase表,一张表是用来存储实体数据的;一张用来存储写入日志;其他若干张表属于索引表。这些表都由EntityGroup实际管理,而一台FServer中可以部署若干EntityGroup。
这里有以下几个要点:
1属于同一张表的EntityGroup使用相同的实体表与索引表。
2父子表共享EntityGroup,一个EntityGroup只有一个Redo Log,即属于父子表关系的表是共享Redo Log的。
3 EntityGroup中使用HBase为存储。
写入操作必须强制带入均衡字段,系统会通过均衡字段来分配要写入的EntityGroup,即,插入或更新操作会转入负责的EntityGroup中继续操作。
数据的可靠性:RedoLog
EntityGroup将数据直接保存到HBase中表中,但牵扯到跨行,跨表操作并需要保证数据的一致性(跨行事务),因此在写入数据到索引表和实体表之前需要先记录操作(合并跨行操作)到redolog表中,每个EntityGroup中拥有一个独立的redolog表。实现了Redo log功能的类叫做RedoLog,每个更新操作(牵扯到若干行)聚合成一条Put,并以当前的时间戳为行键插入到Redo表中。集群从失效中恢复回来需要从RedoLog中恢复数据。
事务
这个事务一个是本地事务,一个是全局的事务。本地事务事务考虑的是在Entity Group内部保证自己ACID。通过Entity Group的Redo Log,我们之所以称之为Redo Log,是因为写进去就是成功的,并且没有UNDO的过程,也就是事务不能回滚,它仅仅是是说我们保证数据一致性的事务机制。一个用户自己的应用肯定是某一个用户ID,这个用户ID肯定属于某一个范围,这个范围尽可能的都放在一起,通过字典序排序,而这个用户跨用户操作是比较少的,我们通常会将全局的Entity Group,也就说转化为两阶段提交,具体的提交操作转化为本地的事务,这块我们并不会直接的将它提给Entity Group,我们会提供一个高效的消息队列,而我们只要同时写进消息队列里去,两阶段提交的事务就是成功的。
本地写事务流程:
图2
事务有自己的时间戳,比如事务一就是时间戳,我们做过这样的优化,我们考虑到原来的操作方式,虽然没有提到,我们认为写的比较慢。原来是在一次事务操作的时候,会阻碍所有事务的写入,这样并发能力会下降。这样我们做了这样的优化,将这次插入过程中的这一行的行键拼接到事务行键中去,这样不牵扯到在一起的跨行操作,这种两不同行写入的话就不需要进行相互阻塞。大家看图3,这里会发现事务五和事务六不是一行的。如果是同一行的话一定要等待,等待前面的事务全部做完才会走下一步。为了支持快照读取,我们在最后最新的,就是之前他已经完全提交的,但是在之前还有没有完全提交的,事务一、二、三、四已经提交了,我们认为快照可以到这个地方来读,
图3
有可能到了再过一小段时间,已经将事务五做完,事务五已经做完,这个时候我们认为当前的快照时间已经到事务六了。这样的话,我们来制作快照读的时间。如图4:
图4
读事务:
流式读取,这一行的写入必须对前面的写入插入成功,这种插入是改,如果已经做完我们重新从数据和索引当中读取出来。
快照读(MVCC),需求中并不需要当天读取最新写作数据。
弱一致性的读取。
在快照读中,在事务当中有一个快照的时间,按照快读的时间作为当前这次查询最大的时间戳,这个时间戳当我们对构建的数据只选一条,就是对索引和实体最终一致性的数据。大家都可以理解为乐观锁的形式,我们对写事务的定义也是乐观锁的形式。
对于用户来说,用户应该自己选择自己的应用模式,这种根据自己的需求来。
EntityGroup的查找
Wasp中的EntityGroup是两层B+tree的结构,用户的查询需要带有均衡字段(建议),使用均衡字段的值在meta表中可以查到包含该均衡字段的EntityGroup以及它所在的地址。然后向EntityGroup所在的服务器通信发起请求处理。
用户在请求了一次EntityGroup之后,地址信息会缓存起来,当再次请求同一个EntityGroup可以不用去元数据中查找,而直接从缓存中拿到地址信息并通信。
示例,有三个分区:
EG1<范围:<负无穷,'20'>,位置:server1>,
EG2<范围:<'20','99'>,位置:server2>,
EG2<范围:<'99',正无穷>,位置:server3>
插入数据,均衡字段的值为'34',所找到的分区即是EG2,并向server2通信,请求server2中的EG2处理这次插入请求。
EntityGroup的生命周期
entity group的各种状态由master触发,用AssignmentManager类进行管理。这个类会从entity group的下线(offline)状态开始一直跟踪,并管理它的状态。下表列举了entity group可能处在的所有状态。
状态 描述
Offline entity group下线
Pending Open 打开entity group的请求已经发送到服务器
Opening 服务器开始打开entity group
Open entity group已经打开,并且完全可以使用
Pending Close 关闭entity group的请求被送到服务器
Closing 服务器正在处理要关闭的entity group
Closed entity group已经被关闭了
Splitting 服务器开始切分entity group
Split entity group已经被切分了
状态的改变可能由master发起,也可能由fserver发起。例如当master把entity group分配到一个服务器后由服务器来完成已打开(opened)过程。另外分裂过程由entity group服务器发起,这个过程可能引发一系列的entity group关闭和打开的事件。
由于事件都是分布式地,服务器使用ZooKeeper来跟踪一个特定znode的状态。
读写数据流程
图5
1连接任意一个FServer
2根据均衡字段查找EntityGroup所在的服务器,如果服务器即本地服务器直接跳过步骤3
3跳转到EntityGroup所在的服务器
4 EntityGroup操作数据读写。
更纤细的FServer内部序列见图3。
图6