YunTable-云时代的BigTable

来源:互联网 发布:手机淘宝怎样分享链接 编辑:程序博客网 时间:2024/04/28 14:00

 原文地址:   http://www.tektalk.org/2010/10/09/yuntable-%E4%BA%91%E6%97%B6%E4%BB%A3%E7%9A%84bigtable/

 

本文是发表于今年第九期《程序员》上的关于YunTable综述,希望大家能喜欢。

无论哪个行业,掌握核心技术的企业总能处于非常强势的地位,并获取较高的利润,在IT界更是如此,比如,强大的搜索引擎和精妙的iOS给Google和苹果带来不仅是市场上的领导地位,更有丰厚的利润。身为一个在云计算相关领域做了三年研究的人,我不禁自问,在云计算行业,什么是最核心的技术呢?也就是说,什么核心技术我们最好能掌握呢?经过我一番思索,总结出两个:其一是系统虚拟化技术,它是IaaS(基础设施即服务)云最核心的组件,相关的技术有开源的Xen,KVM和VMware的vSphere;其二是分布式数据库技术,其是PaaS(平台即服务)云最重要的模块,相关的技术有Google的BigTable,Apache的HBase和Facebook的Cassandra等。同样在实现难度方面,这两个技术也是最大的。虽然这两种技术都有相应的开源版本,但是如果我们不能去亲身去开发和实现这个技术,那么对我们而言,所能获得只能是类似使用经验这类的皮毛而已,但如果能让我们掌握其核心的实现方法的话,这样不仅能使我们有机会开发出在性能和用户体验这两方面更出色的版本,而且同时也能按照不同的业务需求来做相应的优化,并能通过这个项目聚集一批具有实干精神和云时代思维的程序员。

虽然我个人在Java方面有较丰富的项目经验,但可惜缺乏在C语言方面的历练,所以不敢直接涉足系统虚拟化技术所需的内核层开发,因为在调试方面缺乏类似GDB这样简单易用的工具,所以选择了用户层的分布式数据库技术做为突破口,并将Google的BigTable技术作为模板来进行开发,项目名为YunTable,其含义就是云时代的BigTable。在深入YunTable之前,先简要地介绍一下BigTable,它是由Google自主研发的分布式数据库技术,并主要在其内部使用,它能可靠地处理PB以上级别的数据,能支持千台服务器以上的集群,并能实现适用性广泛、可扩展、高性能和高可用性这四个目标,同时BigTable更是已经在超过60个Google的产品和项目上得到了应用,包括 Google Analytics、Google Finance、Orkut、Personalized Search、Writely、Google Earth和YouTube等,也作为业界领先的PaaS云Google App Engine底层的数据存储系统。

YunTable的目标

由于BigTable的功能非常丰富和全面,所以作为一个业余的开源项目不可能像它那样面面俱到,所以YunTable的目标是做一个BigTable的精简版,并使其更适合云环境,它和BigTable之间的关系非常类似Drizzle和MySQL。

在开发过程中,首先专注于为YunTable实现BigTable最核心的功能,那么BigTable最核心的功能有那些了?个人认为主要有三个方面:

    1. 简单的数据模型和灵活的格式:和传统的关系型数据库不同的是,BigTable在数据模型方面,并没有选择强大和复杂,而是提供了非常简单的数据模型,通过这个模型,用户可以动态控制数据的格式,也就是说,数据本身是没有固定的格式(Schema),具体格式由用户自己的应用控制。
    2. 分布式的设计以支撑庞大的集群:首先,选择了在语义和实现上都非常简单明了的Single Master模式来管理整个集群,但是为了能让一个Master节点能管理上千个子节点,所以Master只负责子节点之间数据的分布,实际数据的处理则与Master无关,而由Client端和子节点之间进行交互来完成。
    3. 基于Column的存储:传统的关系型数据库主要以Row为单位存储的,也就是将同一个Row的数据存放在一起,而BigTable则将属于同一个Column或者同一个Column Family的数据存放在一起。由于邻近的数据都属于同一个Column或者相似的Column,所以内容是比较类似的。在这个情况下,可以通过使用压缩算法来对数据进行高效率的压缩,这样不仅能有效地降低数据的存储空间,而且通过减少数据读取的数量来提升系统运行的速度。

 

接着,由于不同的云环境会有不同的需求,比如,有些云环境主要用于海量的数据存储,有些云环境需要数据快速的读写,而有些云环境则追求强一致性,所以YunTable会在之前精简版的基础上,进行下一步的设计和开发,使用户只需通过设定几个不同的参数值就能使YunTable适应不同的云环境,并且简单易用。但因为YunTable还处于初创期,还没有涉及到上面提到的下一步的设计和开发,所以本文接下来的部分将详细介绍YunTable的数据模型、命令行和架构等方面的设计,也就是YunTable是如何实现BigTable的核心功能。

YunTable的数据模型

作为BigTable的传承,YunTable的数据模型也非常简洁,一个Table也是有基本的Row和Column组成,但只支持Row的值或者名字作为唯一键值用来排序和之后的索引,在规模上,一个Table的规模在理论上可以达到PB级,比如:用于存储中国所有公民的个人信息或者互联网上所有网站内容的表。下面是一个简单的例子:

clip_image002

图1.  Table的例子

由于每个Table都会有成百上千的Column,而大多数查询只需得到其中少数几个Column,所以如果每次查询都将所有的Column取出来的话,这样会得不偿失,所以YunTable引入了Column Family这个特性,通过这个特性能将多个Column并为一个小组,比如:下图的“家庭地址”和“工作地址”都隶属于“地址”这个Column Family,这样做的最大的好处是能将这些Column放在一起存储,这样不仅能提高存取效率,而且能避免读取过多的Column,比如,可以选择只选取一个Column Family。Column Family还能用于访问权限控制,比如:“地址”这个Column Family只能让负责管理地址的部门访问。还有,在Table刚创建的时候,YunTable会自动为这个Table创建一个默认Column Family,名为“default_cf”,如果数据在插入的时候,没有定义其Column Family,系统会默认其属于“default_cf”,比如:在图2中,Column名为“名字”或者“性别”的数据都属于“default_cf”,但在显示的时候,为了美观,默认不显示“default_cf”。

clip_image004

图2. Column Family的例子

虽然上面这个例子只有三个Row和五个Column,但如果这个表存储的数据不断增大的话,YunTable会将这个表切为多个Tablet(分片),并让这些Tablet分布到不同服务器上,每个Tablet都会负责一定范围的Row Name,比如,在下图中,Tablet1负责Row Name为310101至310102的数据。

clip_image006

图3. Tablet

为了帮助数据的同步和备份,系统还为每个Cell(单元格)设置相应的Timestamp,系统会根据多个属于同一位置的Cell的Timestamp,来判断哪个Cell是最新的。

YunTable的命令行

YunTable自带一套命令行,主要用于数据处理方面,共支持三个命令。

    1. add:有两大功能:其一是创建新的Table,格式是“add table:table_name”,在这里”table_name”是等待用户输入table名字的占位符,示例:“add table:people” ;其二是为选定的Table创建新的Column Family,格式是“add table:table_name column_family:column_family_name”,在这里,“table_name”为选定Table的名字,“column_family_name”则是新Column Family的名字,具体的例子:“add table:people column_family:address”。
    2. put:主要是用于添加一行新的数据,其格式是“put table  row:row_name column_name:”column_value” column_family_name.column_name:”column_value””,在这里”row”是关键词,在其冒号后输入相应的Row Name,比如,在后面例子里面提到的”me“,在row之后那些,都不是关键字,只要按照那些占位符输入相应参数就可以,具体也可以参看后面的例子,但要注意两点:其一,如果这个column不属于系统默认的column family,那么请在column前输入相关的Column Family,并用“.” 来连接两者;其二,用户可以使用英文的双引号来包裹带空格等特殊字符的Column Value。例子:“put table:people row:me name:"ike" sex:"male" address.homeaddress:"sh"”。
    3. get:可以通过这个命令来获取数据, 格式为“get table:table_name row:row_name”,通过这个命令会显示这个Row Name相对应的数据,例子:“get table:people row:me”,在显示数据的时候,系统还会根据Timestamp对数据进行过滤,也意味着,多个相同的Cell只会显示最新的一个。

总的来说,现在YunTable的命令行已经支持CRUD中创建,添加和查询,并会在今后的版本中增加对删除的支持。

YunTable的架构

clip_image008

图4. YunTable的架构图

在架构上,主要可分为Region、Master和Client这三个模块,而且这三个模块都是独立的,并负责各自的业务逻辑。首先,介绍一下Master节点。

Master节点

随着项目的发展,Master节点的作用也在不断地变化中,特别是0.2版中引入了BigTable中轻Master的理念,也就是说,0.2版中的Master已经不像之前版本那样负责在Region和Client之间对请求和数据进行分发,而只负责维护Table和Region节点之间的对应关系,实际数据的查询和输入则都通过Region节点和Client端之间的交互完成,和Master无关,这样能有效地减轻Master的负担,使得其能支撑百台服务器以上的集群。举个例子,比如,当一个Client端需要处理某个Table的时候,它只需在第一次处理时候,向Master请求和这个Table相关的Region节点的地址,当之后再次处理到这个Table的时候,Client端无需再和Master节点进行沟通,而是直接和相关的Region节点进行交互即可。

Region节点

Region节点,也就是上面所提到的子节点,其作用是负责来自Client端的数据处理请求,并存储和管理大量的数据,Region节点非常类似BigTable论文中所提到的Tablet服务器。每个Region服务器管理多个Tablet,每个Tablet对应一个Column Family,并负责存储属于这个Column Family的数据。除了管理多个Tablet之外,Region服务器还自带WAL日志,全称为“Write-Ahead Log”,主要用于暂存那些最新的数据更新请求,以避免当Tablet中的Memstore被意外关闭时所造成的数据丢失,而当Memstore完成对数据的写入之后,WAL也会清空那些对应的请求。

Tablet,就像上面所说的那样,每个Tablet对应一个column family,而一个Table会有多个Column Family组成,所以一个Table也是由多个有可能分布在不同机器上的Tablet组成。Tablet的实际存储形式为一个以“Tablet”为前缀的目录。Tablet主要有两大部分组成:其一是Memstore:其是缓存在内存的数据文件,主要存储最新添加的数据,当Memstore存储的数据接近限定值时,在Memstore上缓存的数据都将会被冲刷(Flush)到YFile中;其二是YFile,他是主要用于存储数据的持久化文件,在格式上,它是一连串经过排序的键值对,并在文件的末尾加入相应的索引,并且在写入之后是不可修改(Immutable)的,YFile只会在当Memstore被触发冲刷时创建,平时常被顺序读,这样能有效地利用硬盘顺序读性能好的特性。YFile在实现方面参考了HBase的HFile格式和Google的SSTable格式,并做了相应的简化,文件的位置在其所属Tablet的目录中。

Client

现在Client端基本等同于前面提到的命令行,主要用于让用户输入与数据处理相关的命令,并与后端的Master节点和Region节点进行交互,但随着时间的发展,在形式上,Client端有可能是类似JDBC的驱动等。

工作流程

在流程方面,将介绍一下YunTable数据的添加和查询这两个流程,以让大家进一步理解YunTable的架构。

添加流程:

    1. 用户在Client端输入添加命令,比如:“put table:people row:me address.homeaddress:"sh"”。
    2. Client会查找其缓存是不是有和命令中提到的“people”Table相对应的Region(可以对应多个)的信息,如果没有的话,Client会去访问Master节点去获取相关信息。
    3. 当Client得到对应Region的地址时,并会将这个命令发送出去。
    4. 之后,Region先将这个请求记录到WAL中,接着会将根据请求中数据所属Table和Column Family来传递给对应的Tablet,比如,在上面例子中,应该传递给属于“People”这个Table,并且Column Family为“address”的Tablet。
    5. Tablet会将这个请求添加至Memstore中,并返回Region添加成功的信息,最后,Region会把这个信息传回给Client端。

 

查询流程:

    1. 用户在Client端输入添加命令,比如:“get table:people row:me”。
    2. 与上面第2步一致。
    3. 与上面第3步一致。
    4. Region会轮询本地所有属于“People”这个Table 的Tablet。
    5. 每个Tablet都会查询其Memstore和所有YFile,得到所有Row Name为”me”的数据,并将这些数据访问Region。
    6. Region接着把这些数据返回给Client,之后Client会通过返回数据的Timestamp来去掉其中那些过期的数据,并留下的最新的数据,将它们显示在命令行中。

 

YunTable的规划

在规划方面,YunTable0.1版至0.8版主要是实现BigTable的核心功能,并完成相应的分布式测试,而0.9版则是主要完成下一步的设计,开发和测试,以使YunTable更适应云环境。

下面是在具体的规划:

特性

BigTable*

介绍

版本

Key和Value的格式

Y

可以是任意字节数组

0.1

Column Family

Y

通过Column Family来对数据进行分类管理

0.1

支持SSTable的格式

Y

让数据文件一次写入,之后不可更改,来为I/O的性能做优化

0.1

Block Index

Y

在SSTable文件的尾部加入相关的Index,以提升查询速度

0.1

Memstore

Y

就是让比较新的数据放置在内存中以加快查询速度

0.1

Write Ahead Log

Y

每个Region节点会有一个Write Ahead Log来记录数据修改的信息,以免保存在Memstore中的数据丢失

0.1

CRUD命令

Y

支持基本的数据修改和查询的命令

0.2

管理命令

Y

支持命令行来管理Master和Region

0.2

轻量级Master

Y

让Master所承受的负担尽量最小化,以让其支撑和管理更大的集群

0.2

备份

Y

通过将数据进行多次备份,来避免数据丢失的情况

0.8

Bloom Filter

Y

用于让系统快速确定这个Region节点是否存有所需的值

0.8

Row排序

Y

主要支持按照字典顺序(lexicographic order)对Row排序

0.8

容灾支持

Y

要确保当某个Region节点失效时,Client也能很好地处理数据

0.8

批处理

Y

能批量向YunTable插入大量的数据

0.8

压缩

Y

通过压缩数据,来提升速度

0.8

客户端驱动

Y

比如,类似JDBC的驱动

1.0

Master standby

Y

Master会有一个对应的standby节点,来应对Master节点失效的情况

1.0

模块化

N

使得YunTable整体更模块化,来轻松应对新功能的添加

1.0

访问安全

N

增强YunTable的安全性

1.0

为云环境做优化

N

使YunTable更适合云环境

1.0

表1. 在功能特性方面的初步规划(*BigTable这栏里面的“Y”表示BigTable支持这个功能,而“N”表示这个功能不属于BigTable的范畴)