大规模分布式存储系统:原理解析与架构实战
杨传辉前端
分布式系统的数据量远远超出了单个计算机的存储和处理能力。程序员
一个2亿用户的电信运营商,若是平均每一个用户天天拨打接听总共10个电话,每一个电话400字节,5年的话费记录总量即为0.2G×10×0.4K×365×5=1.46PB。除了分布式系统,人们还很难有其余高效的手段来存储和处理这些PB级甚至更多的数据。算法
单机和分布式有两个明显的不一样:数据库
首先,分布式环境下会出现一部分计算机工做正常,另外一部分计算机工做不正常的状况,程序须要在这种状况下尽量地正常工做,这个挑战很是大。
其次,单机环境下的函数调用经常能够在微秒级内返回,因此除了少数访问外部设备(例如磁盘、网卡等)的函数采用异步方式调用外,大部分函数采用同步调用的方式,编译器和操做系统在调用先后自动保存与恢复程序的上下文;在分布式环境下,计算机之间的函数调用(远程调用,即RPC)的返回时间一般是毫秒或亚毫秒(0.1~1.0毫秒)级,差很少是单机环境的100倍,使用同步方式远远不能发挥现代CPU处理器的性能,因此分布式环境下的RPC一般采用异步调用方式,程序须要本身保存和恢复调用先后的上下文,并须要处理更多的异常。编程
著名公司后端
为了处理这些海量内容,每一个互联网公司在后端都有一套成熟的分布式系统用于数据的存储、计算以及价值提取。
Google的核心技术正是后端这些处理海量数据的分布式系统。和Google相似,国外的亚马逊、微软以及国内互联网三巨头阿里巴巴、百度和腾讯的核心技术也是其后端的海量数据处理系统。
互联网公司的分布式存储系统由数量众多的、低成本和高性价比的普通PC服务器经过网络链接而成。缓存
本书做者2007年年末加入百度公司,从事大规模分布式存储的研究和实践工做,曾经开发过相似GFS、MapReduce和Bigtable的分布式系统,后来转战阿里巴巴继续开发分布式数据库OceanBase。安全
分布式存储是基础,云存储和大数据是构建在分布式存储之上的应用。服务器
移动终端的计算能力和存储空间有限,并且有在多个设备之间共享资源的强烈的需求,这就使得网盘、相册等云存储应用很快流行起来。云存储的核心仍是后端的大规模分布式存储系统。
大数据则更近一步,不只须要存储海量数据,还须要经过合适的计算框架或者工具对这些数据进行分析,抽取其中有价值的部分。若是没有分布式存储,便谈不上对大数据进行分析。网络
分布式存储系统
分布式存储系统能够扩展到几百台甚至几千台的集群规模,并且,随着集群规模的增加,系统总体性能表现为线性增加。
分布式存储系统的挑战主要在于数据、状态信息的持久化,要求在自动迁移、自动容错、并发读写的过程当中保证数据的一致性。
分布式存储涉及的技术主要有:
数据分布:如何将数据分布到多台服务器才可以保证数据分布均匀
一致性:如何将数据的多个副本复制到多台服务器,即便在异常状况下,也可以保证不一样副本之间的数据一致性
容错:检测服务器故障并自动将出现故障的服务器上的数据和服务迁移到集群中的其余服务器
负载均衡:新增服务器和集群运行中实现负载均衡
分布式事务,多版本并发控制
数据分类
非结构化数据:包括全部格式的办公文档、文本、图片、图像、音频和视频信息等。
结构化数据:通常存储在关系数据库中,能够用二维关系表结构来表示。结构化数据的模式(Schema,包括属性、数据类型以及数据之间的联系)和内容是分开的,数据的模式须要预先定义。
不一样的分布式存储系统适合处理不一样类型的数据
分布式存储系统分为四类:
一、分布式文件系统
互联网应用须要存储大量的图片、照片、视频等非结构化数据对象,这类数据以对象的形式组织,对象之间没有关联,这样的数据通常称为Blob(Binary Large Object,二进制大对象)数据。分布式文件系统用于存储Blob对象。
在系统实现层面,分布式文件系统内部按照数据块(chunk)来组织数据
二、分布式键值系统
分布式键值系统用于存储关系简单的半结构化数据,它只提供基于主键的CRUD(Create/Read/Update/Delete)功能,即根据主键建立、读取、更新或者删除一条键值记录。
从数据结构的角度看,分布式键值系统与传统的哈希表比较相似,不一样的是,分布式键值系统支持将数据分布到集群中的多个存储节点。
通常用做缓存,好比Memcache。
一致性哈希是分布式键值系统中经常使用的数据分布技术。
三、分布式表格系统
分布式表格系统用于存储关系较为复杂的半结构化数据,与分布式键值系统相比,分布式表格系统不只仅支持简单的CRUD操做,并且支持扫描某个主键范围。分布式表格系统以表格为单位组织数据,每一个表格包括不少行,经过主键标识一行,支持根据主键的CRUD功能以及范围查找功能。
分布式表格系统借鉴了不少关系数据库的技术,例如支持某种程度上的事务。
与分布式数据库相比,分布式表格系统主要支持针对单张表格的操做,不支持一些特别复杂的操做,好比多表关联,多表联接,嵌套子查询;另外,在分布式表格系统中,同一个表格的多个数据行也不要求包含相同类型的列,适合半结构化数据。
四、分布式数据库
分布式数据库通常是从单机关系数据库扩展而来,用于存储结构化数据。分布式数据库采用二维表格组织数据,提供SQL关系查询语言,支持多表关联,嵌套子查询等复杂操做,并提供数据库事务以及并发控制。
典型的系统包括MySQL数据库分片(MySQL Sharding)集群,阿里巴巴OceanBase系统也是一个支持自动扩展的分布式关系数据库。
存储引擎
存储引擎就是哈希表、B树等数据结构在机械磁盘、SSD等持久化介质上的实现。单机存储系统是单机存储引擎的一种封装,对外提供文件、键值、表格或者关系模型。
哈希存储引擎是哈希表的持久化实现,……
数据库将一个或多个操做组成一组,称做事务,事务必须知足原子性、一致性、隔离性以及持久性。
为了保证持久性,对于数据库的每个变化都要在磁盘上记录日志,当数据库系统忽然发生故障,重启后可以恢复到以前一致的状态。
摩尔定律:每18个月计算机等IT产品的性能会翻一番;或者说相同性能的计算机等IT产品,每18个月价钱会降一半。
早期的CPU为单核芯片,现代服务器基本为多核或多个CPU
经典的多CPU架构为对称多处理结构,即在一个计算机上聚集了一组处理器,它们之间对称工做,无主次或从属关系,共享相同的物理内存及总线。
SMP系统的每一个CPU有两个核心(core),CPU与内存之间经过总线通讯。每一个核心有各自的L1d Cache(L1数据缓存)及L1i Cache(L1指令缓存),同一个CPU的多个核心共享L2以及L3缓存。
某些CPU还能够经过超线程技术(Hyper-Threading Technology)使得一个核心具备同时执行两个线程的能力。
如今的主流服务器架构通常为NUMA(Non-Uniform Memory Access,非一致存储访问)架构。它具备多个NUMA节点,每一个NUMA节点是一个SMP结构,通常由多个CPU(如4个)组成,而且具备独立的本地内存、IO槽口等。NUMA节点能够直接快速访问本地内存,也能够经过NUMA互联互通模块访问其余NUMA节点的内存。
以Intel x48主板为例,它是典型的南、北桥架构。北桥芯片经过前端总线(Front Side Bus,FSB)与CPU相连,内存模块以及PCI-E设备(如高端的SSD设备Fusion-IO)挂接在北桥上
网卡(包括千兆以及万兆网卡),硬盘以及中低端固态盘(如Intel 320系列SSD)挂接在南桥上。
传统的数据中心网络拓扑
接入层交换机、汇聚层以及核心层的交换机。
因为同一个接入层的服务器每每部署在一个机架内,所以,设计系统的时候须要考虑服务器是否在一个机架内,减小跨机架拷贝大量数据。例如,Hadoop HDFS默认存储三个副本,其中两个副本放在同一个机架,就是这个缘由。
Google在2008年的时候将网络改造为扁平化拓扑结构,即三级CLOS网络,同一个集群内最多支持20480台服务器,且任何两台都有1Gb带宽。CLOS网络须要额外投入更多的交换机,带来的好处也是明显的,设计系统时不须要考虑底层网络拓扑,从而很方便地将整个集群作成一个计算资源池。
同一个数据中心内部的传输延时是比较小的,网络一次来回的时间在1毫秒以内。数据中心之间的传输延迟是很大的,取决于光在光纤中的传输时间。例如,北京与杭州之间的直线距离大约为1300千米,光在信息传输中走折线,假设折线距离为直线距离的1.5倍,那么光传输一次网络来回延时的理论值为1300×1.5×2/300000=13毫秒,实际测试值大约为40毫秒。
存储系统的性能瓶颈通常在于IO。顺序读取1MB数据的时间为:磁盘寻道时间+数据读取时间,即10ms+1MB/100MB/s×1000=20ms。存储系统的性能瓶颈主要在于磁盘随机读写。
固态磁盘(SSD),各大互联网公司都有大量基于SSD的应用。SSD的特色是随机读取延迟小,可以提供很高的IOPS(每秒读写,Input/Output Per Second)性能;主要问题在于容量和价格。
磁盘适合大块顺序访问的存储系统,SSD适合随机访问较多或者对延时比较敏感的关键系统。
从分布式系统的角度看,整个集群中全部服务器上的存储介质(内存、机械硬盘,SSD)构成一个总体,其余服务器上的存储介质与本机存储介质同样都是可访问的,区别仅仅在于须要额外的网络传输及网络协议栈等访问开销
集群中有30个机架,每一个机架接入40台服务器,同一个机架的服务器接入到同一个接入交换机,不一样机架的服务器接入到不一样的接入交换机。
哈希存储引擎不支持顺序扫描
B树(B-Tree)存储引擎支持顺序扫描,对应的存储系统是关系数据库。
LSM树(Log-Structured Merge Tree)存储引擎和B树存储引擎同样,支持增、删、改、随机读取以及顺序扫描。它经过批量转储技术规避磁盘随机写入问题,普遍应用于互联网的后台存储系统,例如Google Bigtable、Google LevelDB以及Facebook开源的Cassandra系统
Bitcask是一个基于哈希表结构的键值存储系统,它仅支持追加操做(Append-only),即全部的写操做只追加而不修改老的数据。在Bitcask系统中,每一个文件有必定的大小限制,当文件增长到相应的大小时,就会产生一个新的文件,老的文件只读不写。在任意时刻,只有一个文件是可写的,用于数据追加,称为活跃数据文件。
Bitcask数据文件中的数据是一条一条的写入操做,每一条记录的数据项分别为主键(key)、value内容(value)、主键长度(key_sz)、value长度(value_sz)、时间戳(timestamp)以及crc校验值。(数据删除操做也不会删除旧的条目,而是将value设定为一个特殊的值用做标识)。内存中采用基于哈希表的索引数据结构,哈希表的做用是经过主键快速地定位到value的位置。哈希表结构中的每一项包含了三个用于定位数据的信息,分别是文件编号(file id),value在文件中的位置(value_pos),value长度(value_sz),经过读取file_id对应文件的value_pos开始的value_sz个字节,这就获得了最终的value值。写入时首先将Key-Value记录追加到活跃数据文件的末尾,接着更新内存哈希表,所以,每一个写操做总共须要进行一次顺序的磁盘写入和一次内存操做。
系统基于一个假设,value的长度远大于主键的长度。假如value的平均长度为1KB,每条记录在内存中的索引信息为32字节,那么,磁盘内存比为32:1。这样,32GB内存索引的数据量为32GB×32=1TB。
Bitcask系统中的记录删除或者更新后,原来的记录成为垃圾数据。若是这些数据一直保存下去,文件会无限膨胀下去,为了解决这个问题,Bitcask须要按期执行合并(Compaction)操做以实现垃圾回收。所谓合并操做,即将全部老数据文件中的数据扫描一遍并生成新的数据文件,这里的合并其实就是对同一个key的多个操做以只保留最新一个的原则进行删除,每次合并后,新生成的数据文件就再也不有冗余数据了。
Bitcask系统中的哈希索引存储在内存中,若是不作额外的工做,服务器断电重启重建哈希表须要扫描一遍数据文件,若是数据文件很大,这是一个很是耗时的过程。Bitcask经过索引文件(hint file)来提升重建哈希表的速度。索引文件就是将内存中的哈希索引表转储到磁盘生成的结果文件。
相比哈希存储引擎,B树存储引擎不只支持随机读取,还支持范围扫描
叶子节点保存每行的完整数据
B+树一次检索最多须要h-1次磁盘IO,复杂度为O(h)=O(logdN)(N为元素个数,d为每一个节点的出度,h为B+树高度)
修改操做首先须要记录提交日志,接着修改内存中的B+树。若是内存中的被修改过的页面超过必定的比率,后台线程会将这些页面刷到磁盘中持久化
缓冲区管理器负责将可用的内存划分红缓冲区,缓冲区是与页面同等大小的区域,磁盘块的内容能够传送到缓冲区中。缓冲区管理器的关键在于替换策略,即选择将哪些页面淘汰出缓冲池。
LSM树(Log Structured Merge Tree)的思想很是朴素,就是将对数据的修改增量保持在内存中,达到指定的大小限制后将这些修改操做批量写入磁盘,读取时须要合并磁盘中的历史数据和内存中最近的修改操做。LSM树的优点在于有效地规避了磁盘随机写入问题,但读取时可能须要访问较多的磁盘文件
LevelDB存储引擎主要包括:内存中的MemTable和不可变MemTable(Immutable MemTable,也称为Frozen MemTable,即冻结MemTable)以及磁盘上的几种主要文件:当前(Current)文件、清单(Manifest)文件、操做日志(Commit Log,也称为提交日志)文件以及SSTable文件。当应用写入一条记录时,LevelDB会首先将修改操做写入到操做日志文件,成功后再将修改操做应用到MemTable,这样就完成了写入操做。
当MemTable占用的内存达到一个上限值后,须要将内存的数据转储到外存文件中。LevelDB会将原先的MemTable冻结成为不可变MemTable,并生成一个新的MemTable。新到来的数据被记入新的操做日志文件和新生成的MemTable中。顾名思义,不可变MemTable的内容是不可更改的,只能读取不能写入或者删除。LevelDB后台线程会将不可变MemTable的数据排序后转储到磁盘,造成一个新的SSTable文件,这个操做称为Compaction。SSTable文件是内存中的数据不断进行Compaction操做后造成的,且SSTable的全部文件是一种层级结构,第0层为Level 0,第1层为Level 1,以此类推。
SSTable中的文件是按照记录的主键排序的,每一个文件有最小的主键和最大的主键。LevelDB的清单文件记录了这些元数据,包括属于哪一个层级、文件名称、最小主键和最大主键。当前文件记录了当前使用的清单文件名。在LevelDB的运行过程当中,随着Compaction的进行,SSTable文件会发生变化,新的文件会产生,老的文件被废弃,此时每每会生成新的清单文件来记载这种变化,而当前文件则用来指出哪一个清单文件才是当前有效的。
直观上,LevelDB每次查询都须要从老到新读取每一个层级的SSTable文件以及内存中的MemTable。LevelDB作了一个优化,因为LevelDB对外只支持随机读取单条记录,查询时LevelDB首先会去查看内存中的MemTable,若是MemTable包含记录的主键及其对应的值,则返回记录便可;若是MemTable没有读到该主键,则接下来到一样处于内存中的不可变Memtable中去读取;相似地,若是仍是没有读到,只能依次重新到老读取磁盘中的SSTable文件。
数据模型
文件、关系以及随着NoSQL技术流行起来的键值模型、关系弱化的表格模型
文件系统以目录树的形式组织文件,以类UNIX操做系统为例,根目录为/,包含/usr、/bin、/home等子目录,每一个子目录又包含其余子目录或者文件
POSIX(Portable Operating System Interface)是应用程序访问文件系统的API标准,它定义了文件系统存储接口及操做集。
POSIX标准适合单机文件系统,在分布式文件系统中,出于性能考虑,通常不会彻底遵照这个标准。NFS(Network File System)文件系统容许客户端缓存文件数据,多个客户端并发修改同一个文件时可能出现不一致的状况。举个例子,NFS客户端A和B须要同时修改NFS服务器的某个文件,每一个客户端都在本地缓存了文件的副本,A修改后先提交,B后提交,那么,即便A和B修改的是文件的不一样位置,也会出现B的修改覆盖A的状况。
对象模型与文件模型比较相似,用于存储图片、视频、文档等二进制数据块,典型的系统包括Amazon Simple Storage(S3),Taobao File System(TFS)。这些系统弱化了目录树的概念,Amazon S3只支持一级目录,不支持子目录,Taobao TFS甚至不支持目录结构。与文件模型不一样的是,对象模型要求对象一次性写入到系统,只能删除整个对象,不容许修改其中某个部分。
SQL查询还有一个强大的特性是容许在WHERE、FROM和HAVING子句中使用子查询,子查询又是一个完整的select-from-where语句。
大量的NoSQL系统采用了键值模型(也称为Key-Value模型),Key-Value模型过于简单,支持的应用场景有限,NoSQL系统中使用比较普遍的模型是表格模型。
表格模型弱化了关系模型中的多表关联,支持基于单表的简单操做,典型的系统是Google Bigtable以及其开源Java实现HBase。表格模型除了支持简单的基于主键的操做,还支持范围扫描,另外,也支持基于列的操做。与关系模型不一样的是,表格模型通常不支持多表关联操做,Bigtable这样的系统也不支持二级索引,事务操做支持也比较弱,各个系统支持的功能差别较大,没有统一的标准。另外,表格模型每每还支持无模式(schema-less)特性,也就是说,不须要预先定义每行包括哪些列以及每一个列的类型,多行之间容许包含不一样列。
关系数据库在海量数据场景面临以下挑战:一、事务关系模型要求多个SQL操做知足ACID特性,全部的SQL操做要么所有成功,要么所有失败。在分布式系统中,若是多个操做属于不一样的服务器,保证它们的原子性须要用到两阶段提交协议,而这个协议的性能很低,且不能容忍服务器故障,很难应用在海量数据场景。二、联表传统的数据库设计时须要知足范式要求,例如,第三范式要求在一个关系中不能出如今其余关系中已包含的非主键信息。假设存在一个部门信息表,其中每一个部门有部门编号、部门名称、部门简介等信息,那么在员工信息表中列出部门编号后就不能加入部门名称、部门简介等部门有关的信息,不然就会有大量的数据冗余。而在海量数据的场景,为了不数据库多表关联操做,每每会使用数据冗余等违反数据库范式的手段。实践代表,这些手段带来的收益远高于成本。
关系数据库采用B树存储引擎,更新操做性能不如LSM树这样的存储引擎。另外,若是只有基于主键的增、删、查、改操做,关系数据库的性能也不如专门定制的Key-Value存储系统。
数据库事务具备原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)以及持久性(Durability)
多个事务并发执行时,若是它们的执行结果和按照某种顺序一个接着一个串行执行的效果等同,这种隔离级别称为可串行化。可串行化是比较理想的状况,商业数据库为了性能考虑,每每会定义多种隔离级别。事务的并发控制通常经过锁机制来实现,锁能够有不一样的粒度,能够锁住行,也能够锁住数据块甚至锁住整个表格
为了提升读事务性能,能够采用写时复制(Copy-On-Write,COW)或者多版本并发控制(Multi-Version Concurrency Control,MVCC)技术来避免写事务阻塞读事务。
原子性,事务的原子性也体如今事务对数据的读取上,例如,一个事务对同一数据项的屡次读取的结果必定是相同的。
一致性,事务须要保持数据库数据的正确性、完整性和一致性,通常状况下银行帐务余额不能是负数,信用卡消费不能超过该卡的信用额度等。
隔离性,数据库须要保证每个事务在它的修改所有完成以前,对其余的事务是不可见的,换句话说,不能让其余事务看到该事务的中间状态。从银行帐户A转一笔款项a到帐户B,不能让其余事务(例如帐户查询)看到A帐户已经扣除款项a但B帐户却尚未增长款项a的状态。
永久性,事务完成后,它对于数据库的影响是永久性的,即便系统出现各类异常也是如此。
出于性能考虑,许多数据库容许使用者选择牺牲隔离属性来换取并发度,从而得到性能的提高。SQL定义了4种隔离级别。
隔离级别的下降可能致使读到脏数据或者事务执行异常
锁也分为两种类型:读锁以及写锁,容许对同一个元素加多个读锁,但只容许加一个写锁,且写事务将阻塞读事务。这里的元素能够是一行,也能够是一个数据块甚至一个表格
T1和T2两个事务操做不一样行,初始时A=B=25,T1将A加100,T2将B乘以2,因为T1和T2操做不一样行,两个事务没有锁冲突,能够并行执行而不会破坏系统的一致性。
T1扫描从A到C的全部行,将它们的结果相加后更新A,初始时A=C=25,假设在T1执行过程当中T2插入一行B,那么,事务T1和T2没法作到可串行化。为了保证数据库一致性,T1执行范围扫描时须要锁住从A到C这个范围的全部更新,T2插入B时,因为整个范围被锁住,T2获取锁失败而等待T1先执行完成。
多个事务并发执行可能引入死锁。表2-6中T1读取A,而后将A的值加100后更新B,T2读取B,而后将B的值乘以2更新A,初始时A=B=25。T1持有A的读锁,须要获取B的写锁,而T2持有B的读锁,须要A的写锁。T1和T2这两个事务循环依赖,任何一个事务都没法顺利完成。
解决死锁的思路主要有两种:第一种思路是为每一个事务设置一个超时时间,超时后自动回滚,表2-6中若是T1或T2两者之中的某个事务回滚,则另一个事务能够成功执行。第二种思路是死锁检测。死锁出现的缘由在于事务之间互相依赖,T1依赖T2,T2又依赖T1,依赖关系构成一个环路。检测到死锁后能够经过回滚其中某些事务来消除循环依赖。
互联网业务中读事务占的比例每每远远超过写事务,不少应用的读写比例达到6:1,甚至10:1。写时复制(Copy-On-Write,COW)读操做不用加锁,极大地提升了读取性能。
1)拷贝:将从叶子到根节点路径上的全部节点拷贝出来。 2)修改:对拷贝的节点执行修改。 3)提交:原子地切换根节点的指针,使之指向新的根节点。
若是读操做发生在第3步提交以前,那么,将读取老节点的数据,不然将读取新节点,读操做不须要加锁保护
写时复制技术涉及引用计数,对每一个节点维护一个引用计数,表示被多少节点引用,若是引用计数变为0,说明没有节点引用,能够被垃圾回收。
写时复制技术原理简单,问题是每次写操做都须要拷贝从叶子到根节点路径上的全部节点,写操做成本高
除了写时复制技术,多版本并发控制,即MVCC(Multi-Version Concurrency Control),也可以实现读事务不加锁。MVCC对每行数据维护多个版本,不管事务的执行时间有多长,MVCC老是可以提供与事务开始时刻相一致的数据。
以MySQL InnoDB存储引擎为例,InnoDB对每一行维护了两个隐含的列,其中一列存储行被修改的“时间”,另一列存储行被删除的“时间”,注意,InnoDB存储的并非绝对时间,而是与时间对应的数据库系统的版本号,每当一个事务开始时,InnoDB都会给这个事务分配一个递增的版本号,因此版本号也能够被认为是事务号。对于每一行查询语句,InnoDB都会把这个查询语句的版本号同这个查询语句遇到的行的版本号进行对比,而后结合不一样的事务隔离级别,来决定是否返回改行。
若是行的修改或者删除版本号大于事务号,说明行是被该事务后面启动的事务修改或者删除的。在可重复读取隔离级别下,后开始的事务对数据的影响不该该被先开始的事务看见,因此应该忽略后开始的事务的更新或者删除操做。
MVCC读取数据的时候不用加锁,每一个查询都经过版本检查,只得到本身须要的数据版本,从而大大提升了系统的并发度。固然,为了实现多版本,必须对每行存储额外的多个版本的数据。另外,MVCC存储引擎还必须按期删除再也不须要的版本,及时回收空间。
故障恢复
数据库运行过程当中可能会发生故障,这个时候某些事务可能执行到一半但没有提交,当系统重启时,须要可以恢复到一致的状态,即要么提交整个事务,要么回滚。数据库系统以及其余的分布式存储系统通常采用操做日志(有时也称为提交日志,即Commit Log)技术来实现故障恢复。操做日志分为回滚日志(UNDO Log)、重作日志(REDO Log)以及UNDO/REDO日志。
为了保证数据库的一致性,数据库操做须要持久化到磁盘,若是每次操做都随机更新磁盘的某个数据块,系统性能将会不好。所以,经过操做日志顺序记录每一个数据库操做并在内存中执行这些操做,内存中的数据按期刷新到磁盘,实现将随机写请求转化为顺序写请求。
操做日志记录了事务的操做。例如,事务T对表格中的X执行加10操做,初始时X=5,更新后X=15,那么,UNDO日志记为<T,X,5>,REDO日志记为<T,X,15>,UNDO/REDO日志记为<T,X,5,15>。关系数据库系统通常采用UNDO/REDO日志。
存储系统若是采用REDO日志,其写操做流程以下: 1)将REDO日志以追加写的方式写入磁盘的日志文件。 2)将REDO日志的修改操做应用到内存中。 3)返回操做成功或者失败。
存储系统要求先将REDO日志刷入磁盘才能够更新内存中的数据,若是每一个事务都要求将日志当即刷入磁盘,系统的吞吐量将会不好。所以,存储系统每每有一个是否当即刷入磁盘的选项,对于一致性要求很高的应用,能够设置为当即刷入;相应地,对于一致性要求不过高的应用,能够设置为不要求当即刷入,首先将REDO日志缓存到操做系统或者存储系统的内存缓冲区中,按期刷入磁盘。这种作法有一个问题,若是存储系统意外故障,可能丢失最后一部分更新操做。
成组提交(Group Commit)技术是一种有效的优化手段。REDO日志首先写入到存储系统的日志缓冲区中: a)日志缓冲区中的数据量超过必定大小,好比512KB; b)距离上次刷入磁盘超过必定时间,好比10ms。当知足以上两个条件中的某一个时,将日志缓冲区中的多个事务操做一次性刷入磁盘,接着一次性将多个事务的修改操做应用到内存中并逐个返回客户端操做结果。与按期刷入磁盘不一样的是,成组提交技术保证REDO日志成功刷入磁盘后才返回写操做成功。这种作法可能会牺牲写事务的延时,但大大提升了系统的吞吐量。
若是全部的数据都保存在内存中,那么可能出现两个问题: ●故障恢复时须要回放全部的REDO日志,效率较低。若是REDO日志较多,好比超过100GB,那么,故障恢复时间是没法接受的。 ●内存不足
所以,须要将内存中的数据按期转储(Dump)到磁盘,这种技术称为checkpoint(检查点)技术。系统按期将内存中的操做以某种易于加载的形式(checkpoint文件)转储到磁盘中,并记录checkpoint时刻的日志回放点,之后故障恢复只须要回放checkpoint时刻的日志回放点以后的REDO日志。因为将内存数据转储到磁盘须要很长的时间,而这段时间还可能有新的更新操做,checkpoint必须找到一个一致的状态。checkpoint流程以下: 1)日志文件中记录"START CKPT"。 2)将内存中的数据以某种易于加载的组织方式转储到磁盘中,造成checkpoint文件。checkpoint文件中每每记录"START CKPT"的日志回放点,用于故障恢复。 3)日志文件中记录"END CKPT"。
传统的行式数据库将一个个完整的数据行存储在数据页中。若是处理查询时须要用到大部分的数据列,这种方式在磁盘IO上是比较高效的。
列式数据库是将同一个数据列的各个值存放在一块儿。插入某个数据行时,该行的各个数据列的值也会存放到不一样的地方。
列式数据库大大地提升了OLAP大数据量查询的效率。固然,列式数据库不是万能的,每次读取某个数据行时,须要分别从不一样的地方读取各个数据列的值,而后合并在一块儿造成数据行
不少列式数据库还支持列组(column group,Bigtable系统中称为locality group),即将多个常常一块儿访问的数据列的各个值存放在一块儿。若是读取的数据列属于相同的列组,列式数据库能够从相同的地方一次性读取多个数据列的值,避免了多个数据列的合并。列组是一种行列混合存储模式,这种模式可以同时知足OLTP和OLAP的查询需求。
因为同一个数据列的数据重复度很高,所以,列式数据库压缩时有很大的优点。例如,Google Bigtable列式数据库对网页库压缩能够达到15倍以上的压缩率
另外,能够针对列式存储作专门的索引优化。好比,性别列只有两个值,“男”和“女”,能够对这一列创建位图索引:如图2-12所示,“男”对应的位图为100101,表示第一、四、6行值为“男”;“女”对应的位图为011010,表示第二、三、5行值为“女”。若是须要查找男性或者女性的个数,只须要统计相应的位图中1出现的次数便可。另外,创建位图索引后0和1的重复度高,能够采用专门的编码方式对其进行压缩。
分布式系统面临的第一个问题就是数据分布,即将数据均匀地分布到多个存储节点。另外,为了保证可靠性和可用性,须要将数据复制多个副本,这就带来了多个副本之间的数据一致性问题。大规模分布式存储系统的重要目标就是节省成本,于是只能采用性价比较高的PC服务器。这些服务器性能很好,可是故障率很高,要求系统可以在软件层面实现自动容错。当存储节点出现故障时,系统可以自动检测出来,并将原有的数据和服务迁移到集群中其余正常工做的节点。
分布式系统中有两个重要的协议,包括Paxos选举协议以及两阶段提交协议。Paxos协议用于多个节点之间达成一致,每每用于实现总控节点选举。两阶段提交协议用于保证跨多个节点操做的原子性,这些操做要么所有成功,要么所有失败。
服务器宕机
重启后也须要恢复内存信息。
设计容错系统的一个基本原则是:网络永远是不可靠的,任何一个消息只有收到对方的回复后才能够认为发送成功,系统设计时老是假设网络将会出现异常并采起相应的处理措施。
磁盘故障分为两种状况:磁盘损坏和磁盘数据错误。
多台服务器,即便其中一台服务器磁盘出现故障,也能从其余服务器上恢复数据
对于磁盘数据错误,每每能够采用校验和(checksum)机制来解决
在分布式系统中,若是某个节点向另一个节点发起RPC(Remote Procedure Call)调用,这个RPC执行的结果有三种状态:“成功”、“失败”、“超时”(未知状态),也称为分布式存储系统的三态。
当出现超时状态时,只能经过不断读取以前操做的状态来验证RPC操做是否成功。固然,设计分布式存储系统时能够将操做设计为“幂等”的,也就是说,操做执行一次与执行屡次的结果相同,例如,覆盖写就是一种常见的幂等操做。
因为异常的存在,分布式存储系统设计时每每会将数据冗余存储多份,每一份称为一个副本。
副本是分布式存储系统容错技术的惟一手段。因为多个副本的存在,如何保证副本之间的一致性是整个分布式系统的理论核心。
通常来讲,存储系统能够支持强一致性,也能够为了性能考虑只支持最终一致性。从客户端的角度看,通常要求存储系统可以支持读写一致性,会话一致性,单调读,单调写等特性。
常见的性能指标有:系统的吞吐能力以及系统的响应时间
这两个指标每每是矛盾的,追求高吞吐的系统,每每很难作到低延迟;追求低延迟的系统,吞吐量也会受到限制
若是系统部署在同一个数据中心,只要系统设计合理,在保证强一致性的前提下,不会对性能和可用性形成太大的影响。Alibaba的OceanBase系统以及Google的分布式存储系统都倾向强一致性。
生成一张有30张缩略图(假设图片原始大小为256KB)的页面须要多少时间?
●方案1:顺序操做,每次先从磁盘中读取图片,再执行生成缩略图操做,执行时间为:30×10ms(磁盘随机读取时间)+30×256K/30MB/s(假设缩略图生成速度为30MB/s)=560ms
●方案2:并行操做,一次性发送30个请求,每一个请求读取一张图片并生成缩略图,执行时间为:10ms+256K/300MB/s=18ms
分布式系统区别于传统单机系统在于可以将数据分布到多个节点,并在多个节点之间实现负载均衡。数据分布的方式主要有两种,一种是哈希分布,如一致性哈希,表明系统为Amazon的Dynamo系统;另一种方法是顺序分布,即每张表格上的数据按照主键总体有序,表明系统为Google的Bigtable系统。Bigtable将一张大表根据主键切分为有序的范围,每一个有序范围是一个子表。
哈希取模的方法很常见,其方法是根据数据的某一种特征计算哈希值,并将哈希值与集群中的服务器创建映射关系,从而将不一样哈希值的数据分布到不一样的服务器上。所谓数据特征能够是key-value系统中的主键(key),也能够是其余与业务逻辑相关的值。例如,将集群中的服务器按0到N-1编号(N为服务器的数量),根据数据的主键(hash(key)%N)或者数据所属的用户id(hash(user_id)%N)计算哈希值,来决定将数据映射到哪一台服务器。
若是哈希函数的散列特性很好,哈希方式能够将数据比较均匀地分布到集群中去,然而,找出一个散列特性很好的哈希函数是很难的。这是由于,若是按照主键散列,那么同一个用户id下的数据可能被分散到多台服务器,这会使得一次操做同一个用户id下的多条记录变得困难;若是按照用户id散列,容易出现“数据倾斜”(data skew)问题,即某些大用户的数据量很大,不管集群的规模有多大,这些用户始终由一台服务器处理。
传统的哈希分布算法还有一个问题:当服务器上线或者下线时,N值发生变化,数据映射彻底被打乱,几乎全部的数据都须要从新分布,这将带来大量的数据迁移。
一种思路是再也不简单地将哈希值和服务器个数作除法取模映射,而是将哈希值与服务器的对应关系做为元数据,交给专门的元数据服务器来管理。访问数据时,首先计算哈希值,再查询元数据服务器,得到该哈希值对应的服务器。这样,集群扩容时,能够将部分哈希值分配给新加入的机器并迁移对应的数据。另外一种思路就是采用一致性哈希。
哈希散列破坏了数据的有序性,只支持随机读取操做,不可以支持顺序扫描
顺序分布在分布式表格系统中比较常见,通常的作法是将大表顺序划分为连续的范围,每一个范围称为一个子表,总控服务器负责将这些子表按照必定的策略分配到存储节点上。
用户表(User表)的主键范围为1~7000,在分布式存储系统中划分为多个子表,分别对应数据范围1~1000,1001~2000,……6001~7000
读User表时,须要经过Meta表查找相应的User子表所在的存储节点
分布式存储系统的每一个集群中通常有一个总控节点,其余节点为工做节点,由总控节点根据全局负载信息进行总体调度。工做节点刚上线时,总控节点须要将数据迁移到该节点,另外,系统运行过程当中也须要不断地执行迁移任务,将数据从负载较高的工做节点迁移到负载较低的工做节点。
分布式存储系统经过复制协议将数据同步到多个存储节点,并确保多个副本之间的数据一致性。
同一份数据的多个副本中每每有一个副本为主副本(Primary),其余副本为备副本(Backup),由主副本将数据复制到备份副本。
复制协议分为两种,强同步复制以及异步复制,两者的区别在于用户的写请求是否须要同步到备副本才能够返回成功。
一致性和可用性是矛盾的,强同步复制协议能够保证主备副本之间的一致性,可是当备副本出现故障时,也可能阻塞存储系统的正常写服务,系统的总体可用性受到影响;异步复制协议的可用性相对较好,可是一致性得不到保障,主副本出现故障时还有数据丢失的可能。
主副本将写请求复制到其余备副本,常见的作法是同步操做日志
假设全部副本的个数为N,且N>2,即备副本个数大于1。那么,实现强同步协议时,主副本能够将操做日志并发地发给全部备副本并等待回复,只要至少1个备副本返回成功就能够回复客户端操做成功。强同步的好处在于若是主副本出现故障,至少有1个备副本拥有完整的数据,分布式存储系统能够自动地将服务切换到最新的备副本而不用担忧数据丢失的状况。
强同步复制和异步复制都是将主副本的数据以某种形式发送到其余副本,这种复制协议称为基于主副本的复制协议
在任什么时候刻只能有一个副本为主副本
NWR复制协议,其中,N为副本数量,W为写操做的副本数,R为读操做的副本数。NWR协议中多个副本再也不区分主和备
只要W+R>N,能够保证读到的副本中至少有一个包含了最新的更新。然而,这种协议的问题在于不一样副本的操做顺序可能不一致,从多个副本读取时可能出现冲突。这种方式在实际系统中比较少见,不建议使用。
存储系统设计时须要在一致性和可用性之间权衡,在某些场景下,不容许丢失数据,在另一些场景下,极小的几率丢失部分数据时容许的,可用性更加剧要。例如,Oracle数据库的DataGuard复制组件包含三种模式:
●最大保护模式(Maximum Protection):即强同步复制模式,
●最大性能模式(Maximum Performance):即异步复制模式
单台服务器故障的几率是不高的,然而,只要集群的规模足够大,天天均可能有机器故障发生
在分布式系统中,故障检测每每经过租约(Lease)协议实现
容错处理的第一步是故障检测,心跳是一种很天然的想法。假设总控机A须要确认工做机B是否发生故障,那么总控机A每隔一段时间,好比1秒,向工做机B发送一个心跳包。若是一切正常,机器B将响应机器A的心跳包;不然,机器A重试必定次数后认为机器B发生了故障。然而,机器A收不到机器B的心跳并不能确保机器B发生故障并中止了服务,在系统运行过程当中,可能发生各类错误,好比机器A与机器B之间网络发生问题,机器B过于繁忙致使没法响应机器A的心跳包
租约机制就是带有超时时间的一种受权。假设机器A须要检测机器B是否发生故障,机器A能够给机器B发放租约,机器B持有的租约在有效期内才容许提供服务,不然主动中止服务。机器B的租约快要到期的时候向机器A从新申请租约。正常状况下,机器B经过不断申请租约来延长有效期,当机器B出现故障或者与机器A之间的网络发生故障时,机器B的租约将过时,从而机器A可以确保机器B再也不提供服务,机器B的服务能够被安全地迁移到其余服务器。
单层结构的分布式存储系统维护了多个副本,例如副本个数为3,主备副本之间经过操做日志同步。某单层结构的分布式存储系统有3个数据分片A、B、C,每一个数据分片存储了三个副本。其中,A1,B1,C1为主副本,分别存储在节点1,节点2以及节点3。假设节点1发生故障,将被总控节点检测到,总控节点选择一个最新的副本,好比A2或者A3替换A1成为新的主副本并提供写服务。
两层结构的分布式存储系统会将全部的数据持久化写入底层的分布式文件系统,每一个数据分片同一时刻只有一个提供服务的节点。如图3-5所示,某双层结构的分布式存储系统有3个数据分片,A、B和C。它们分别被节点1,节点2和节点3所服务。当节点1发生故障时,总控节点将选择一个工做节点,好比节点2,加载A的服务。因为A的全部数据都存储在共享的分布式文件系统中,节点2只须要从底层分布式文件系统读取A的数据并加载到内存中。
总控节点自身也可能出现故障,为了实现总控节点的高可用性(High Availability),总控节点的状态也将实时同步到备机,当故障发生时,能够经过外部服务选举某个备机做为新的总控节点,而这个外部服务也必须是高可用的。为了进行选主或者维护系统中重要的全局信息,能够维护一套经过Paxos协议实现的分布式锁服务,好比Google Chubby或者它的开源实现Apache Zookeeper。
分布式存储系统中每每有一个总控节点用于维护数据分布信息,执行工做机管理,数据定位,故障检测和恢复,负载均衡等全局调度工做。
开源的Hadoop也可以扩展到3000台以上的集群。
同一个组内的节点服务相同的数据,这样的系统称为同构系统。同构系统的问题在于增长副本须要迁移的数据量太大,假设每一个存储节点服务的数据量为1TB,内部传输带宽限制为20MB/s,那么增长副本拷贝数据须要的时间为1TB/20MB/s=50000s,大约十几个小时。
系统中有五个分片(A,B,C,D,E),每一个分片包含三个副本,如分片A的三个副本分别为A1,A2以及A3。假设节点1发生永久性故障,那么能够从剩余的节点中任意选择健康的节点来增长A,B以及E的副本。因为整个集群都参与到节点1的故障恢复过程,故障恢复时间很短,并且集群规模越大,优点就会越明显。
异构系统
分布式系统涉及的协议不少,例如租约,复制协议,一致性协议
两阶段提交协议用于保证跨多个节点操做的原子性,也就是说,跨多个节点的操做要么在全部节点上所有执行成功,要么所有失败。两阶段提交协议(Two-phase Commit,2PC)常常用来实现分布式事务。
Paxos协议用于确保多个节点对某个投票(例如哪一个节点为主节点)达成一致。
在两阶段协议中,系统通常包含两类节点:一类为协调者( coordinator),一般一个系统中只有一个;另外一类为事务参与者( participants, cohorts 或 workers),通常包含多个。
一、阶段1:请求阶段(Prepare Phase)。在请求阶段,协调者通知事务参与者准备提交或者取消事务,而后进入表决过程。在表决过程当中,参与者将告知协调者本身的决策:赞成(事务参与者本地执行成功)或者取消(事务参与者本地执行失败)。
二、阶段2:提交阶段(Commit Phase)。在提交阶段,协调者将基于第一个阶段的投票结果进行决策:提交或者取消。当且仅当全部的参与者赞成提交事务协调者才通知全部的参与者提交事务,不然协调者通知全部的参与者取消事务。参与者在接收到协调者发来的消息后将执行相应的操做。
A组织B、C和D三我的去爬长城:若是全部人都赞成去爬长城,那么活动将举行;若是有一人不一样意去爬长城,那么活动将取消。
假如D一直不能回复邮件,那么A、B和C将不得不处于一直等待的状态。而且B和C所持有的资源一直不能释放,
A能够经过引入事务的超时机制防止资源一直不能释放的状况。
更为严重的是,假如A发完邮件后生病住院了,即便B、C和D都发邮件告诉A赞成下周三去爬长城,若是A没有备份,事务将被阻塞。
两阶段提交协议可能面临两种故障:
●事务参与者发生故障。给每一个事务设置一个超时时间,若是某个事务参与者一直不响应,到达超时时间后整个事务失败。
●协调者发生故障。协调者须要将事务相关信息记录到操做日志并同步到备用协调者,假如协调者发生故障,备用协调者能够接替它完成后续的工做。若是没有备用协调者,协调者又发生了永久性故障,事务参与者将没法完成事务而一直等待下去。
大多数分布式存储系统都采用敬而远之的作法,放弃对分布式事务的支持。
Paxos协议用于解决多个节点之间的一致性问题。多个节点之间经过操做日志同步数据,若是只有一个节点为主节点,那么,很容易确保多个节点之间操做日志的一致性。考虑到主节点可能出现故障,系统须要选举出新的主节点。Paxos协议正是用来实现这个需求。
为了实现高可用性,主节点每每将数据以操做日志的形式同步到备节点。若是主节点发生故障,备节点会提议本身成为主节点。这里存在的问题是网络分区的时候,可能会存在多个备节点提议(Proposer,提议者)本身成为主节点。Paxos协议保证,即便同时存在多个proposer,也可以保证全部节点最终达成一致,即选举出惟一的主节点。
大多数状况下,系统只有一个proposer,他的提议也老是会很快地被大多数节点接受。Paxos协议执行步骤以下: 1)批准(accept):Proposer发送accept消息要求全部其余节点(acceptor,接受者)接受某个提议值,acceptor能够接受或者拒绝。 2)确认(acknowledge):若是超过一半的acceptor接受,意味着提议值已经生效,proposer发送acknowledge消息通知全部的acceptor提议生效。
当出现网络或者其余异常时,系统中可能存在多个proposer,他们各自发起不一样的提议。
若是proposer第一次发起的accept请求没有被acceptor中的多数派批准(例如与其余proposer的提议冲突),那么,须要完整地执行一轮Paxos协议。过程以下:
Paxos协议须要考虑两个问题:正确性,即只有一个提议值会生效;可终止性,即最后总会有一个提议值生效。
Paxos协议有两种用法:一种用法是用它来实现全局的锁服务或者命名和配置服务,例如 Apache Zookeeper
另一种用法是用它来将用户数据复制到多个数据中心
2PC协议最大的缺陷在于没法处理协调者宕机问题。若是协调者宕机,那么,2PC协议中的每一个参与者可能都不知道事务应该提交仍是回滚,整个协议被阻塞,执行过程当中申请的资源都没法释放。所以,常见的作法是将2PC和Paxos协议结合起来,经过2PC保证多个数据分片上的操做的原子性,经过Paxos协议实现同一个数据分片的多个副本之间的一致性。另外,经过Paxos协议解决2PC协议中协调者宕机问题。当2PC协议中的协调者出现故障时,经过Paxos协议选举出新的协调者继续提供服务。
跨机房部署方案有三个:集群总体切换、单个集群跨机房、Paxos选主副本。
在前两种方案中,总控节点须要和工做节点之间保持租约(lease),当工做节点出现故障时,自动将它上面服务的主副本切换到其余工做节点。若是采用Paxos协议选主副本,那么,每一个数据分片的多个副本构成一个Paxos复制组。B一、B二、B三、B4构成一个复制组,某一时刻B1为复制组的主副本,当B1出现故障时,其余副本将尝试切换为主副本,Paxos协议保证只有一个副本会成功。这样,总控节点与工做节点之间再也不须要保持租约,总控节点出现故障也不会对工做节点产生影响。
Google文件系统(GFS)是构建在廉价服务器之上的大型分布式系统。
GFS是Google分布式存储的基石,其余存储系统,如Google Bigtable、Google Megastore、Google Percolator均直接或者间接地构建在GFS之上。另外,Google大规模批处理系统MapReduce也须要利用GFS做为海量数据的输入输出。
GFS系统的节点可分为三种角色:GFS Master(主控服务器)、GFS ChunkServer(CS,数据块服务器)以及GFS客户端。
客户端是GFS提供给应用程序的访问接口,它是一组专用接口,不遵循POSIX规范,以库文件的形式提供。客户端访问GFS时,首先访问主控服务器节点,获取与之进行交互的CS信息,而后直接访问这些CS,完成数据存取工做。
CDN经过将网络内容发布到靠近用户的边缘节点,使不一样地域的用户在访问相同网页时能够就近获取。
所谓的边缘节点是CDN服务提供商通过精心挑选的距离用户很是近的服务器节点,仅“一跳”(Single Hop)之遥。用户在访问时就无需再通过多个路由器,大大减小访问时间。
DNS在对域名解析时再也不向用户返回源服务器的IP,而是返回了由智能CDN负载均衡系统选定的某个边缘节点的IP。用户利用这个IP访问边缘节点,而后该节点经过其内部DNS解析获得源服务器IP并发出请求来获取用户所需的页面,若是请求成功,边缘节点会将页面缓存下来,下次用户访问时能够直接读取,而不须要每次都访问源服务器。
淘宝CDN系统用于支持用户购物,尤为是“双11”光棍节时的海量图片请求。图片存储在后台的TFS集群中,CDN系统将这些图片缓存到离用户最近的边缘节点。
相比分布式存储系统,分布式缓存系统的实现要容易不少。这是由于缓存系统不须要考虑数据持久化,若是缓存服务器出现故障,只须要简单地将它从集群中剔除便可。
因为Blob存储系统读访问量大,更新和删除不多,特别适合经过CDN技术分发到离用户最近的节点。
新上线的CDN缓存节点配备的磁盘均为SSD。
分布式键值模型能够当作是分布式表格模型的一种特例。然而,因为它只支持针对单个key-value的增、删、查、改操做,所以,适用哈希分布算法。
Amazon Dynamo以很简单的键值方式存储数据,不支持复杂的查询。
Dynamo写入数据时,首先,根据一致性哈希算法计算出每一个数据副本所在的存储节点,其中一个副本做为本次写操做的协调者。接着,协调者并发地往全部其余副本发送写请求,每一个副本将接收到的数据写入本地,协调者也将数据写入本地。当某个副本写入成功后,回复协调者。若是发给某个副本的写请求失败,协调者会将它加入重试列表不断重试。等到W-1个副本回复写入成功后(即加上协调者共W个副本写入成功),协调者能够回复客户端写入成功。协调者回复客户端成功后,还会继续等待或者重试,直到全部的副本都写入成功。
Dynamo读取数据时,首先,根据一致性哈希算法计算出每一个副本所在的存储节点,其中一个副本做为本次读操做的协调者。接着,协调者根据负载策略选择R个副本,并发地向它们发送读请求。每一个副本读取本地数据,协调者也读取本地数据。当某个副本读取成功后,回复协调者读取结果。等到R-1个副本回复读取成功后(即加上协调者共R个副本读取成功),协调者能够回复客户端。这里分为两种状况:若是R个副本返回的数据彻底一致,将某个副本的读取结果回复客户端;不然,须要根据冲突处理规则合并多个副本的读取结果。Dynamo系统默认的策略是根据修改时间戳选择最新的数据,固然用户也能够自定义冲突处理方法。读取过程当中若是发现某些副本上的数据版本太旧,Dynamo内部会异步发起一次读取修复操做,使用冲突解决后的结果修正错误的副本。
Dynamo设计支持可插拔的存储引擎,好比Berkerly DB(BDB),MySQL InnoDB等。
Dynamo采用无中心节点的P2P设计,增长了系统可扩展性,但同时带来了一致性问题,影响上层应用。另外,一致性问题也使得异常状况下的测试变得更加困难,因为Dynamo只保证最基本的最终一致性,多客户端并发操做的时候很难预测操做结果,也很难预测不一致的时间窗口,影响测试用例设计。
主流的分布式系统通常都带有中心节点,这样可以简化设计,并且中心节点只维护少许元数据,通常不会成为性能瓶颈。
无中心节点的设计短时间以内难以成为主流
Tair是淘宝开发的一个分布式键/值存储引擎。Tair分为持久化和非持久化两种使用方式:非持久化的Tair能够当作是一个分布式缓存,持久化的Tair将数据存放于磁盘中。
Tair做为一个分布式系统,是由一个中心控制节点和若干个服务节点组成。其中,中心控制节点称为Config Server,服务节点称为Data Server。Config Server负责管理全部的Data Server,维护其状态信息;Data Server对外提供各类数据服务,并以心跳的形式将自身情况汇报给Config Server。Config Server是控制点,并且是单点,目前采用一主一备的形式来保证可靠性,全部的Data Server地位都是等价的。
根据数据的主键计算哈希值后,分布到Q个桶中,桶是负载均衡和数据迁移的基本单位。Config Server按照必定的策略把每一个桶指派到不一样的Data Server上。
当某台Data Server故障不可用时,Config Server可以检测到。每一个哈希桶在Tair中存储多个副本,若是是备副本,那么Config Server会从新为其指定一台Data Server,若是是持久化存储,还将复制数据到新的Data Server上。若是是主副本,那么ConfigServer首先将某个正常的备副本提高为主副本,对外提供服务。接着,再选择另一台Data Server增长一个备副本,确保数据的备份数。
机器加入或者负载不均衡可能致使桶迁移,迁移的过程当中须要保证对外服务。当迁移发生时,假设Data Server A要把桶三、四、5迁移到Data Server B。迁移完成前,客户端的路由表没有变化,客户端对三、四、5的访问请求都会路由到A。如今假设3还没开始迁移,4正在迁移中,5已经迁移完成。那么若是对3访问,A直接服务;若是对5访问,A会把请求转发给B,而且将B的返回结果返回给用户;若是对4访问,由A处理,同时若是是对4的修改操做,会记录修改日志,等到桶4迁移完成时,还要把修改日志发送到B,在B上应用这些修改操做,直到A和B之间数据彻底一致迁移才真正完成。
Tair默认包含两个存储引擎:Mdb和Fdb,此外,还支持Berkerly DB、Tokyo Cabinet、InnoDB、Leveldb等各类存储引擎。
Amazon Dynamo采用P2P架构,而在Tair中引入了中心节点Config Server。这种方式很容易处理数据的一致性,再也不须要向量时钟、数据回传、Merkle树、冲突处理等复杂的P2P技术。另外,中心节点的负载很低。做者认为,分布式键值系统的总体架构应该参考Tair,而不是Dynamo。
Tair最主要的用途在于分布式缓存,持久化存储起步比较晚,在实现细节上也有一些不尽如人意的地方。例如,Tair持久化存储经过复制技术来提升可靠性,然而,这种复制是异步的。所以,当有Data Server发生故障时,客户有可能在必定时间内读不到最新的数据,甚至发生最新修改的数据丢失的状况。
分布式表格系统对外提供表格模型,每一个表格由不少行组成,经过主键惟一标识,每一行包含不少列。整个表格在系统中全局有序,顺序分布。
Hadoop
Bigtable是Google开发的基于GFS和Chubby的分布式表格系统。Google的不少数据,包括Web索引、卫星图像数据等在内的海量结构化和半结构化数据,都存储在Bigtable中。
Bigtable系统由不少表格组成,每一个表格包含不少行,每行经过一个主键(Row Key)惟一标识,每行又包含不少列(Column)。某一行的某一列构成一个单元(Cell),每一个单元包含多个版本的数据。总体上看,Bigtable是一个分布式多维映射表。另外,Bigtable将多个列组织成列族(column family),这样,列名由两个部分组成:(column family,qualifier)。列族是Bigtable中访问控制的基本单元,也就是说,访问权限的设置是在列族这一级别上进行的。Bigtable中的列族在建立表格的时候须要预先定义好,个数也不容许过多;然而,每一个列族包含哪些qualifier是不须要预先定义的,qualifier能够任意多个,适合表示半结构化数据。Bigtable中的行主键能够是任意的字符串,最大不超过64KB。Bigtable表中的数据按照行主键进行排序,排序使用的是字典序。行主键com.cnn.www是域名www.cnn.com变换后的结果,这样作的好处是使得全部www.cnn.com下的子域名在系统中连续存放。这一行数据包含两个列族:"contents"和"anchor"。其中,列族"anchor"又包含两个列,qualifier分别为"cnnsi.com"和"my:look.ca"。 Google的不少服务,好比Web检索和用户的个性化设置,都须要保存不一样时间的数据,这些不一样的数据版本必须经过时间戳来区分。t四、t5和t6表示保存了三个时间点获取的网页
失效的版本将会由Bigtable的垃圾回收机制自动删除
Bigtable构建在GFS之上,为文件系统增长一层分布式索引层。另外,Bigtable依赖Google的Chubby(即分布式锁服务)进行服务器选举及全局信息维护。
Bigtable将大表划分为大小在100~200MB的子表(tablet),每一个子表对应一个连续的数据范围。
客户端程序库(Client):提供Bigtable到应用程序的接口,应用程序经过客户端程序库对表格的数据单元进行增、删、查、改等操做。客户端经过Chubby锁服务获取一些控制信息,但全部表格的数据内容都在客户端与子表服务器之间直接传送;
主控服务器(Master):管理全部的子表服务器,包括分配子表给子表服务器,指导子表服务器实现子表的合并,接受来自子表服务器的子表分裂消息,监控子表服务器,在子表服务器之间进行负载均衡并实现子表服务器的故障恢复等。
Chubby是一个分布式锁服务,底层的核心算法为Paxos。Paxos算法的实现过程须要一个“多数派”就某个值达成一致,进而才能获得一个分布式一致性状态。也就是说,只要一半以上的节点不发生故障,Chubby就可以正常提供服务。Chubby服务部署在多个数据中心,典型的部署为两地三数据中心五副本,同城的两个数据中心分别部署两个副本,异地的数据中心部署一个副本,任何一个数据中心总体发生故障都不影响正常服务
Bigtable系统保证强一致性
Bigtable中Master对Tablet Server的监控是经过Chubby完成的,Tablet Server在初始化时都会从Chubby中获取一个独占锁
因为Bigtable负载均衡的过程当中会停一会读写服务,负载均衡策略不该当过于激进。
随着数据不断写入和删除,某些子表可能太大,某些子表可能过小,须要执行子表分裂与合并操做。顺序分布与哈希分布的区别在于哈希分布每每是静态的,而顺序分布是动态的,须要经过分裂与合并操做动态调整。
Bigtable采用Merge-dump存储引擎。数据写入时须要先写操做日志,成功后应用到内存中的MemTable中,写操做日志是往磁盘中的日志文件追加数据,很好地利用了磁盘设备的特性。当内存中的MemTable达到必定大小,须要将MemTable转储(Dump)到磁盘中生成SSTable文件。因为数据同时存在MemTable和可能多个SSTable中,读取操做须要按从旧到新的时间顺序合并SSTable和内存中的MemTable数据。数据在SSTable中连续存放,所以能够同时知足随机读取和顺序读取两种需求。为了防止磁盘中的SSTable文件过多,须要定时将多个SSTable经过compaction过程合并为一个SSTable,从而减小后续读操做须要读取的文件个数。
插入、删除、更新、增长(Add)等操做在Merge-dump引擎中都当作一回事,除了最先生成的SSTable外,SSTable中记录的只是操做,而不是最终的结果,须要等到读取(随机或者顺序)时才合并获得最终结果。
数据在SSTable中按照主键有序存储
Tablet Server的缓存包括两种:块缓存(Block Cache)和行缓存(Row Cache)。其中,块缓存的单位为SSTable中的数据块,行缓存的单位为一行记录。随机读取时,首先查找行缓存;若是行缓存不命中,接着再查找块缓存。
Compaction后生成新的SSTable,原有的SSTable成为垃圾须要被回收掉
Master按期执行垃圾回收任务,这是一个标记删除(mark-and-sweep)过程
GFS+Bigtable两层架构以一种很优雅的方式兼顾系统的强一致性和可用性。底层文件系统GFS是弱一致性系统,可用性和性能很好,可是多客户端追加可能出现重复记录等数据不一致问题;上层的表格系统Bigtable经过多级分布式索引的方式使得系统对外总体表现为强一致性。
单副本服务。Bigtable架构很是适合离线或者半线上应用,然而,Tablet Server节点出现故障时部分数据短期内没法提供读写服务,不适合实时性要求特别高的业务,如交易类业务。
Google Bigtable架构把可扩展性基本作到了极致,Megastore则是在Bigtable系统之上提供友好的数据库功能支持,加强易用性。Megastore是介于传统的关系型数据库和NoSQL之间的存储技术,它在Google内部使用普遍,如Google App Engine、社交类应用等。
最新读取和快照读取利用了Bigtable存储多版本数据的特性,保证不会读到未提交的事务。非一致性读取忽略日志的状态而直接读取Bigtable内存中最新的值,可能读到不完整的事务。
Megastore事务中的写操做采用了预写式日志(Write-ahead日志或REDO日志),也就是说,只有当全部的操做都在日志中记录下来后,写操做才会对数据执行修改。
Paxos协议使用了乐观锁的机制:尽管可能有多个写操做同时试图写同一个日志位置,但最后只有一个会成功。其余失败的写操做都会观察到成功的写操做,而后停止并重试。
假设事务T1和T2对同一个实体组并发执行,T1执行时读取a和b,T2读取a和d,接着T1和T2同时提交。Paxos协议保证T1和T2中有且只有一个事务提交成功,假如T1提交成功,T2将从新读取a和d后再次经过Paxos协议提交
对于多个集群之间的操做日志同步,Megastore系统采用的是基于Paxos的复制协议机制,对于普通的Master-Slave强同步机制,Master宕机后,Slave若是须要切换为Master继续提供服务须要首先确认Master宕机,检测Master宕机这段时间是须要中止写服务的,不然将形成数据不一致。
分布式数据库
有不少思路能够实现关系数据库的可扩展性。例如,在应用层划分数据,将不一样的数据分片划分到不一样的关系数据库上,如MySQL Sharding;或者在关系数据库内部支持数据自动分片,如Microsoft SQL Azure;或者干脆从存储引擎开始重写一个全新的分布式数据库,如Google Spanner以及Alibaba OceanBase。
为了扩展关系数据库,最简单也是最为常见的作法就是应用层按照规则将数据拆分为多个分片,分布到多个数据库节点,并引入一个中间层来对应用屏蔽后端的数据库拆分细节。
以MySQL Sharding架构为例,分为几个部分:中间层dbproxy集群、数据库组、元数据服务器、常驻进程。
应用程序经过MySQL原生的客户端与系统交互,支持JDBC,原有的单机访问数据库程序能够无缝迁移。
中间层解析客户端SQL请求并转发到后端的数据库。具体来说,它解析MySQL协议,执行SQL路由,SQL过滤,读写分离,结果归并,排序以及分组,等等。
主机负责全部的写事务及强一致读事务,备机能够支持有必定延迟的读事务。
元数据服务器主要负责维护dbgroup拆分规则并用于dbgroup选主。dbproxy经过元数据服务器获取拆分规则从而肯定SQL语句的执行计划。另外,若是dbgroup的主机出现故障,须要经过元数据服务器选主。元数据服务器自己也须要多个副本实现HA,一种常见的方式是采用Zookeeper实现。
部署在每台数据库服务器上的常驻进程,用于实现监控,单点切换,安装,卸载程序等。dbgroup中的数据库须要进行主备切换,软件升级等,这些控制逻辑须要与数据库读写事务处理逻辑隔离开来。假设数据库按照用户哈希分区,同一个用户的数据分布在一个数据库组上。若是SQL请求只涉及同一个用户(这对于大多数应用都是成立的),那么,中间层将请求转发给相应的数据库组,等待返回结果并将结果返回给客户端;若是SQL请求涉及多个用户,那么中间层须要转发给多个数据库组,等待返回结果并将结果执行合并、分组、排序等操做后返回客户端。因为中间层的协议与MySQL兼容,客户端彻底感觉不到与访问单台MySQL机器之间的差异。
引入数据库中间层将后端分库分表对应用透明化在大型互联网公司内部很常见。
数据库复制:MySQL主备之间只支持异步复制,并且主库压力较大时可能产生很大的延迟,所以,主备切换可能会丢失最后一部分更新事务,这时每每须要人工介入。
Microsoft SQL Azure是微软的云关系型数据库,后端存储又称为云SQL Server(Cloud SQL Server)。它构建在SQL Server之上,经过分布式技术提高传统关系型数据库的可扩展性和容错能力。
Google Spanner是Google的全球级分布式数据库(Globally-Distributed Database)。Spanner的扩展性达到了全球级,能够扩展到数百个数据中心,数百万台机器,上万亿行记录。更为重要的是,除了夸张的可扩展性以外,它还能经过同步复制和多版本控制来知足外部一致性,支持跨数据中心事务。
Spanner构建在Google下一代分布式文件系统Colossus之上。Colossus是GFS的延续,相比GFS,Colossus的主要改进点在于实时性,而且支持海量小文件。
正常状况下,这个主副本会在快要到期的时候将本身再次选为主副本;若是出现异常,例如主副本所在的spanserver宕机,其余副本会在10秒后经过Paxos协议选举为新的主副本。
Google的分布式存储系统一步步地从Bigtable到Megastore,再到Spanner,这也印证了分布式技术和传统关系数据库技术融合的必然性,即底层经过分布式技术实现可扩展性,上层经过关系数据库的模型和接口将系统的功能暴露给用户。阿里巴巴的OceanBase系统在设计之初就考虑到这两种技术融合的必然性,所以,一开始就将系统的最终目标定为:可扩展的关系数据库。
Amazon Web Services(AWS)是Amazon构建的一个云计算平台的总称,它提供了一系列云服务。经过这些服务,用户可否访问和使用Amazon的存储和计算基础设施。
一、计算类:AWS核心产品为弹性计算云EC2(Elastic Computing)。EC2几乎能够认为是迄今为止云计算领域最为成功的产品,通俗地讲,就是提供虚拟机,用户的应用程序部署在EC2实例中。EC2架构的核心是弹性伸缩,当托管的应用程序访问量变化时可以自动增长或者减小EC2实例,并经过弹性负载均衡技术将访问请求分发到新增的EC2实例上。在计费模式上,EC2按照使用量计费,而不是采用传统的预付费方式
EBS(Elastic Block Store)是一个分布式块设备,能够像本地的磁盘同样直接挂载在EC2实例上,与本地磁盘不一样的是,保存到EBS的数据会由EBS的管理节点自动复制到多个存储节点上。EC2实例的本地存储是不可靠的,若是EC2实例出现故障,本地存储上保存的数据将会丢失,而保存到EBS上的数据不会丢失。EBS用于替代EC2实例的本地存储,从而加强EC2可靠性。
二、存储类:存储类产品较多,包括简单对象存储S3,表格存储系统SimpleDB、 DynamoDB、分布式关系数据库服务(Relational Datastore Service,RDS)以及简单消息存储(Simple Queue Service,SQS)
为了提升访问性能,S3中的对象还可以经过CloudFront缓存到不一样地理位置的内容分发网络(Content Delivery Network,CDN)节点。SimpleDB和DynamoDB是分布式表格系统,支持对一张表格进行读写操做;RDS是分布式数据库,目前支持MySQL以及Oracle两种数据库。
三、工具集中包含各类语言的SDK、程序自动部署以及各类管理工具。另外,AWS经过CloudWatch系统提供丰富的监控功能。
假设网站MyWebSite.com托管在AWS平台的某个可用区域中。AWS开发者将Web应用上传到AWS平台并部署到指定的EC2实例上。EC2实例通常分红多个自动扩展组(Auto Scaling Group),并经过弹性负载均衡(Elastic Load Balancing)技术将访问请求自动分发到自动扩展组内的EC2实例。开发者的Web应用能够使用AWS平台上的存储类服务,包括S三、SimpleDB、DynamoDB、RDS以及SQS。
网站上每每有一些大对象,好比图片、视频,这些大对象存储在S3系统中,并经过内容分发技术缓存到多个CloudFront节点。当Internet用户浏览MyWebSite.com时,可能会请求S3中的大对象,这样的请求将经过DNS按照必定的策略定位到CloudFront节点。CloudFront首先在本地缓存节点查找对象,若是不存在,将请求源站获取S3中存储的对象数据,这一步操做称为回源。
Google云平台(Google App Engine,GAE)是一种PaaS服务,使得外部开发者能够经过Google指望的方式使用它的基础设施服务,目前支持Python和Java两种语言。GAE尤为适用于企业构建本身的企业私有云。
GAE云平台主要包含以下几个部分:
一、前端服务器。前端的功能包括负载均衡以及路由。前端服务器将静态内容请求转发到静态文件服务器,将动态内容请求转发到应用服务器。
二、应用服务器。应用服务器装载应用的代码并处理接收到的动态内容请求。
三、应用管理节点(App Master)。调度应用服务器,将应用服务器的变化通知前端,从而前端能够将访问流量切换到正确的应用服务器。
四、存储区。包括DataStore、MemCache以及BlobStore三个部分。应用的持久化数据主要存储在DataStore中,MemCache用于缓存,BlobStore是DataStore的一种补充,用于存储大对象。
五、服务区。除了必备的应用服务器以及存储区以外,GAE还包含不少服务,好比图像处理服务(Images)、邮件服务、抓取服务(URL fetch)、任务队列(Task Queue)以及用户服务(Users)等。
六、管理工具。GAE提供Web管理工具用于管理应用并监控应用的运行状态,好比资源消耗、应用日志等。
GAE的核心组件为应用服务器以及存储区,其中,应用服务器用于托管GAE平台用户的应用程序,存储区提供云存储服务
GAE对外不提供虚拟机服务,所以,对于不一样的开发语言,须要提供不一样的应用服务器实现,目前支持Python和Java两种语言
从托管Web应用程序的角度看,云平台主要包括云存储以及应用运行平台,
云存储组件包括两层:分布式存储层以及存储访问层。分布式存储层管理存储服务器集群,实现各个存储设备之间的协同工做,保证数据可靠性,对外屏蔽数据所在位置,数据迁移,数据复制,机器增减等变化,使得整个分布式系统看起来像是一台服务器。分布式存储层是云存储系统的核心,也是整个云存储平台最难实现的部分。CDN节点将云存储系统中的热点数据缓存到离用户最近的位置,从而减小用户的访问延时并节约带宽。
应用运行平台的主体为计算实例,计算实例最主要的功能有两个:开发者的应用程序运行环境以及离线任务处理。不一样的云计算平台厂商的计算实例形式每每不一样:AWS(Amazon Web Service)平台中的计算实例为Amazon的弹性计算(Elastic Computing,EC2)虚拟机,它们既用于托管开发者的Web程序,又可用来执行Hadoop MapReduce计算或者图像以及视频转换等离线任务;GAE(Google App Engine)平台中的计算实例分为前端实例(Frontend Instance)以及后端实例(Backend Instance),其中,前端实例为GAE特有的Python、Java以及Go语言运行容器,用于托管开发者使用Python、Java或者Go语言开发的Web程序,后端实例执行运行时间较长的离线任务;
云存储平台还包含一些公共服务,这些基础服务由云存储组件及运行平台组件所共用,如:
一、消息服务。消息服务将执行流程异步化,用于应用程序解耦
二、缓存服务。缓存服务用于存储云存储系统中的读多写少的热点数据,大多数云存储平台提供Memcache服务
三、用户管理。用户管理主要功能是用户身份认证,确保用户的身份合法,并存储用户相关的我的信息。云计算平台通常支持单点登陆,在多个应用系统中,用户只须要登陆一次就能够访问全部相互信任的系统。
四、权限管理。为多个服务提供集中的权限控制,以确保应用和数据只能被有受权的用户访问。
五、安全服务。SQL注入漏洞、XSS跨站脚本漏洞。主机入侵检测经过主机日志安全分析,实时侦测系统密码破解,异常IP登陆等攻击行为并实时报警;DDos缓解技术可以抵御SYN flood以及其余拒绝服务攻击。
六、计费管理。计算出用户的使用费用,并提供完善和详细的报表。云存储系统计费涉及的参数通常包括:CPU时间,网络出口带宽,存储量以及服务调用次数(包括读写API调用次数)。
七、资源管理。管理云存储平台中的全部服务器资源,将应用程序或者虚拟机映射自动部署到合适的计算实例,另外,自动调整计算实例的数量来帮助运行于其上的应用更好地应对突发流量。当计算实例发生故障时,资源管理系统还须要通知前端的负载均衡层,将流量切换到其余计算实例。
八、运维管理。云存储平台的运维须要作到自动化,从而下降运维成本
NoSQL存储系统则百花齐放,常见的NoSQL系统包括仅支持根据主键进行CRUD(Create,Read,Update,Delete)操做的键值(Key-Value)存储系统,也有基于传统的B树或者LSM树(Log-Structured Merge Tree)的存储系统。
CDN以及P2P技术将云存储系统中的热点数据缓存到离用户较近的边缘节点或者临近的其余用户的客户端,从而起到访问加速的做用,而且节省云存储服务提供商的网络带宽成本。
云存储系统经过存储访问层被我的用户的终端设备直接访问,或者被云存储平台中托管的应用程序访问。云存储访问层的功能包括:Web服务、负载均衡、安全服务以及计费。云存储系统对外提供统一的访问接口,常见的接口是REST或者SOAP这样的Web服务,须要经过Apache或者Nginx这样的Web服务器进行协议转化,Web服务器前端常用LVS(Linux Virtual Server)、HaProxy这样的软件或者专业的负载均衡设备(如F5负载均衡器)进行负载均衡。存储访问层须要提供安全和计费服务,安全服务包括身份认证、访问受权、综合防御、安全审计、DDos攻击预防/防火墙等。
基于虚拟机的弹性计算平台的优点在于兼容性,支持各类编程语言和平台。
云引擎。典型的云引擎为Google App Engine,底层设计的涉及的技术主要是应用容器(好比Java Tomcat、Jetty,Python Runtime)以及应用容器自动伸缩。当应用的负载太高时,自动增长应用的运行容器数;反之,自动减小应用的运行容器数。
提到大数据,首先想到的就是MapReduce,不少人甚至将大数据与MapReduce画等号。虽然MapReduce解决了海量数据离线分析问题,可是,随着应用对数据的实时性要求愈来愈高,流式计算系统和实时分析系统获得愈来愈普遍的应用。
数据的爆发式的增加,有一个趋势叫新摩尔定律。根据IDC做出的预测,数据一直都在以每一年50%的速度增加,也就是说每两年增长一倍,这意味着人类在最近两年产生的数据量至关于以前产生的所有数据量。
从各类各样类型的数据,包括非结构化数据、半结构化数据以及结构化数据中,快速获取有价值信息的能力,就是大数据技术。
一提到大数据,大部分人首先想到的就是Hadoop。Hadoop是Google GFS以及MapReduce系统的开源实现,用户能够在不了解分布式底层细节的状况下开发分布式程序。它提供了离线处理功能,但没法作到动态和实时的分析。为了解决实时性问题,流计算和实时分析系统应运而生。
大数据技术进一步从海量数据中抽取数据的价值,从而诞生Google搜索引擎、Amazon商品推荐系统。
提到大数据,大多数人首先想到的就是MapReduce。MapReduce使得普通程序员能够在不了解分布式底层细节的前提下开发分布式程序。使用者只需编写两个称为Map和Reduce的函数便可,MapReduce框架会自动处理数据划分、多机并行执行、任务之间的协调,而且可以处理某个任务执行失败或者机器出现故障的状况。
MapReduce框架包含三种角色:主控进程(Master)用于执行任务划分、调度、任务之间的协调等;Map工做进程(Map Worker,简称Map进程)以及Reduce工做进程(Reduce Worker,简称Reduce进程)分别用于执行Map任务和Reduce任务。
MapReduce框架实现时主要作了两点优化:
一、本地化:尽可能将任务分配给离输入文件最近的Map进程,如同一台机器或者同一个机架。经过本地化策略,可以大大减小传输的数据量。
二、备份任务:若是某个Map或者Reduce任务执行的时间较长,主控进程会生成一个该任务的备份并分配给另一个空闲的Map或者Reduce进程。在大集群环境下,即便全部机器的配置相同,机器的负载不一样也会致使处理能力相差很大,经过备份任务减小“拖后腿”的任务,从而下降整个做业的整体执行时间。
MapReduce框架有效地解决了海量数据的离线批处理问题,引起了一系列的扩展和改进。这些扩展包括:Google Tenzing、Google Pregel。
Google Tenzing是一个构建在MapReduce之上的SQL执行引擎,支持SQL查询且可以扩展到成千上万台机器,极大地方便了数据分析人员。
- 查询服务器(Query Server):做为链接客户端和worker池的中间桥梁而存在。查询服务器会解析客户端发送的查询请求,进行SQL优化,而后将执行计划发送给分布式Worker池执行。
- 分布式Worker池:做为执行系统,它会根据查询服务器生成的执行计划运行MapReduce任务。Worker池包含master和worker两种节点,其中,master对应MapReduce框架中的master进程,worker对应MapReduce框架中的map和reduce进程。
- 查询流程 1)用户经过Web UI、CLI或者API向查询服务器提交查询。 2)查询服务器将查询请求解析为一个中间语法树。 3)查询服务器从元数据服务器获取相应的元数据,而后建立一个更加完整的中间格式。 4)优化器扫描该中间格式进行各类优化,生成物理查询计划。 5)优化后的物理查询计划由一个或多个MapReduce做业组成。对于每一个MapReduce做业,查询服务器经过master监听者找到一个可用的master,master将该做业划分为多个任务。 6)空闲的worker从master拉取已就绪的任务。Reduce进程会将它们的结果写入到一个中间存储区域中。 7)查询服务器监控这些中间存储区域,收集中间结果,并流失地返回给客户端。
- 查询服务器负责将用户的SQL操做转化为MapReduce做业
Google Pregel用于图模型迭代计算,图中的每一个节点对应一个任务,每一个图节点会产生输出消息给图中与它关联的后续节点,而每一个节点会对从其余节点传入的输入消息进行处理。
流式计算同时具备存储系统和计算系统的特色,常常应用在一些相似反做弊、交易异常监控等场景。
源数据写入到流处理节点,流处理节点内部运行用户自定义的钩子函数对输入流进行处理,处理完后根据必定的规则转发给下游的流处理节点继续处理。
典型的钩子函数包括:聚合函数:计算最近一段时间窗口内数据的聚合值,如max、min、avg、sum、 count等。
流处理节点能够经过主备同步(Master/Slave)的方式容错,即将数据强同步到备机,若是主机出现故障,备机自动切换为主机继续提供服务。然而,这种方式的代价很高,且流式处理系统每每对错误有必定的容忍度,实际应用时常常选择其余代价更低的容错方式。
Yahoo S4最初是Yahoo为了提升搜索广告有效点击率而开发的一个流式处理系统。S4的主要设计目标是提供一种简单的编程接口来处理数据流,使得用户能够定制流式计算的操做算子。在容错设计上,S4作得比较简单:一旦S4集群中的某个节点故障,会自动切换到另一个备用节点,可是原节点的内存状态将丢失。
S4中每一个流处理节点称为一个处理节点(Processing Node,PN),其主要工做是监听事件,当事件到达时调用合适的处理元(Processing Elements,PE)处理事件。
事件监听器(Event Listener)负责监听事件并转交给PE容器(Processing Element Container,PEC),由PEC交给合适的PE处理业务逻辑。配置文件中会配置PE原型(PE prototype),包括其功能、处理的事件类型(event type)、关心的key以及关心的key值。每一个PE只负责处理本身所关心的事件,也就是说,只有当事件类型、key类型和key值都匹配时,才会交由该PE进行计算处理。PE处理完逻辑后根据其定义的输出方法能够输出事件,事件交由分发器(Dispatcher)与通讯层(Communication Layer)进行交互并由输出器(Emitter)输出至下一个逻辑节点。
通讯层提供集群路由(Routing)、负载均衡(Load Balancing)、故障恢复管理(Failover Management)、逻辑节点到物理节点的映射(存放在Zookeeper上)。当检测到节点故障时,会切换到备用节点,并自动更新映射关系。通讯层隐藏的映射使得PN发送消息时只须要关心逻辑节点而不用关心物理节点。
Twitter Storm是目前普遍使用的流式计算系统,它创造性地引入了一种记录级容错的方法。
海量数据离线分析对于MapReduce这样的批处理系统挑战并不大,若是要求实时,又分为两种状况:若是查询模式单一,那么,能够经过MapReduce预处理后将最终结果导入到在线系统提供实时查询;若是查询模式复杂,例如涉及多个列任意组合查询,那么,只能经过实时分析系统解决。实时分析系统融合了并行数据库和云计算这两类技术,可以从海量数据中快速分析出汇总结果。
并行数据库每每采用MPP(Massively Parallel Processing,大规模并行处理)架构。MPP架构是一种不共享的结构,每一个节点能够运行本身的操做系统、数据库等。每一个节点内的CPU不能访问另外一个节点的内存,节点之间的信息交互是经过节点互联网络实现的。
将数据分布到多个节点,每一个节点扫描本地数据,并由Merge操做符执行结果汇总。
Merge操做符:系统中存在一个或者多个合并节点,它会发送命令给各个数据分片请求相应的数据,每一个数据分片所在的节点扫描本地数据,排序后回复合并节点,由合并节点经过merge操做符执行数据汇总。Merge操做符是一个统称,涉及的操做多是limit、order by、group by、join等。
若是Merge节点处理的数据量特别大,能够经过Split操做符将数据划分到多个节点,每一个节点对一部分数据执行group by、join等操做后再合并最终结果。如图13-10,假如须要执行"select*from A,B where A.x=B.y",能够分别根据A.x和B.x的哈希值将表A和B划分为A0、A1以及B0、B1。由两个节点分别对A0、B0以及A一、B1执行join操做后再合并join结果。
Greenplum是EMC公司研发的一款采用MPP架构的OLAP产品,底层基于开源的PostgreSQL数据库。
Vertica在架构上与OceanBase有类似之处。
Google Dremel是Google的实时分析系统,能够扩展到上千台机器规模,处理PB级别的数据。
Dremel系统融合了并行数据库和Web搜索技术。首先,它借鉴了Web搜索中的“查询树”的概念,将一个巨大复杂的查询,分割成大量较小的查询,使其能并发地在大量节点上执行。其次,和并行数据库相似,Dremel提供了一个SQL-like的接口,且支持列式存储。
Dremel与MapReduce的比较 MapReduce的输出结果直接由reduce任务写入到分布式文件系统,所以,只要reduce任务个数足够多,输出结果能够很大;而Dremel中的最终数据汇聚到一个根节点,所以通常要求最终的结果集比较小,例如GB级别如下。 Dremel的优点在于实时性,只要服务器个数足够多,大部分状况下可以在3秒之内处理完成TB级别数据。