江万寿研究员介绍了开放式遥感数据处理与服务平台项目的来源、进展情况,项目思路以及要达到的目标:可扩展、可伸缩、可配置、可定制。OpenRS的最终目标是搭建一个基本的遥感图像数据处理与应用的框架,实现最常用的图像读写、显示、漫游,以及其他基本的图像处理分析功能以及摄影测量中的传感器成像模型、地理坐标管理等,在此基础上,做成一个开放的社区,为实验室以及国内外研究人员共同开发应用。参与此开放社区的研究人员可以只关注其感兴趣的特定区域,而不用考虑和实现软件其它功能,大量减少重复劳动,可以大大提高研究速度和质量。
MapReduce:超大机群上的简单数据处理
网站: http://blog.csdn.net/active1001/archive/2007/07/02/1675920.aspx
MapReduce是Google的一项重要技术,它是一个编程模型,用以进行大数据量的计算。对于大数据量的计算,通常采用的处理手法就是并行计算。至少现阶段而言,对许多开发人员来说,并行计算还是一个比较遥远的东西。MapReduce就是一种简化并行计算的编程模型,它让那些没有多少并行计算经验的开发人员也可以开发并行应用。在我看来,这也就是MapReduce的价值所在,通过简化编程模型,降低了开发并行应用的入门门槛。相对于现在普通的开发而言,并行计算需要更多的专业知识,有了MapReduce,并行计算就可以得到更广泛的应用。
MapReduce的名字源于这个模型中的两项核心操作:Map和Reduce。也许熟悉Functional Programming的人见到这两个词会倍感亲切。简单的说来,Map是把一组数据一对一的映射为另外的一组数据,其映射的规则由一个函数来指定,比如对[1, 2, 3, 4]进行乘2的映射就变成了[2, 4, 6, 8]。Reduce是对一组数据进行归约,这个归约的规则由一个函数指定,比如对[1, 2, 3, 4]进行求和的归约得到结果是10,而对它进行求积的归约结果是24。
Map操作是独立的对每个元素进行操作,在FP中,操作是没有副作用的,换句话说,Map操作将产生一组全新的数据,而原来的数据保持不变。因此,它是高度并行的。Reduce操作虽然不如Map操作并行性那么好,但是它总会得到一个相对简单的结果,大规模运算也相对独立,因此也是比较适合并行的。
无论是Map还是Reduce都是以另外的函数作为参数,在FP中,这样的函数被称为高阶函数(high-order function)。正是因为它们可以同其它函数相结合,所以,我们只要把Map和Reduce这两个高阶函数进行并行化处理,而无需面面俱到的把所有的函数全部考虑到。这样便形成了一个以Map和Reduce为基础的框架,具体应用相关代码写在用户代码中,之后与MapReduce结合获得并行处理的能力。当然,这么做的前提是按照这个框架的要求,把计算归结为Map和Reduce操作。为什么是Map和Reduce?从前面的内容我们可以看出,在Map过程中,我们将数据并行,也就是将数据分开,而Reduce则把分开的数据合到了一起,换句话说,Map是一个分的过程,Reduce则对应着合,这一分一合便在不知不觉中完成了计算。所以,站在计算的两端来看,与我们通常熟悉的串行计算没有任何差别,所有的复杂性都在中间隐藏了。
所有这些并行化能力的获得都与FP有着密不可分的关系。事实上,不仅仅是MapReduce从FP中获得了灵感,其它一些并行编程模型也走上了同样的道路。FP中有很多的好东西,比如自动内存管理,比如动态类型。在遥远的年代里,因为机器性能的原因,它们无法得到广泛应用,当机器性能不再是瓶颈,这些东西便逐渐复活了。
前面提到过,并行计算对于普通开发人员来说,有一个比较高的门槛。从前我们或许可以不理会并行计算,但是随着Intel开始将多核带入人们的日常生活,并行计算将会变得更加平民化,毕竟谁也不希望自己机器里面的多核只有一个在干活。现在的许多操作系统会把多核视为多处理器,但那也得有多任务才能在CPU处多分得一杯羹。对于服务器端应用来说,拥有多任务的能力是一个正常的现象。但对于很多桌面应用来说,一条道跑到黑的情况比较多见。而且,多任务并非为并行计算专门准备的,所以,控制粒度是很大的。如果需要更细粒度的并行计算,至少从表达能力上来说,多任务就有些麻烦了。
并行计算进入日常开发的难度就在于编程模型,太复杂的东西会被人唾弃的,CORBA在这方面已经是个反面教材了。MapReduce已经为我们演示了一种可以接受的编程模型,接下来,变化还会有,Intel和AMD都在努力。不过,具体的进程得取决于多核CPU占领市场的进度。
MapReduce 中文版
MapReduce是Google开发的C++编程工具,用于大规模数据集(大于1TB)的并行运算。概念\"Map(映射)\"和\"Reduce(化简)\",和他们的主要思想,都是从函数式编程语言里借来的,还有从矢量编程语言里借来的特性。[1]
当前的软件实现是指定一个Map(映射)函数,用来把一组键值对映射成一组新的键值对,指定并发的Reduce(化简)函数,用来保证所有映射的键值对中的每一个共享相同的键组。 映射和化简
简单说来,一个映射函数就是对一些独立元素组成的概念上的列表(例如,一个测试成绩的列表)的每一个元素进行指定的操作(比如前面的例子里,有人发现所有学生的成绩都被高估了一分,他可以定义一个“减一”的映射函数,用来修正这个错误。)。事实上,每个元素都是被独立操作的,而原始列表没有被更改,因为这里创建了一个新的列表来保存新的答案。这就是说,Map操作是可以高度并行的,这对高性能要求的应用以及并行计算领域的需求非常有用。
而化简操作指的是对一个列表的元素进行适当的合并(继续看前面的例子,如果有人想知道班级的平均分该怎么做?他可以定义一个化简函数,通过让列表中的元素跟自己的相邻的元素相加的方式把列表减半,如此递归运算直到列表只剩下一个元素,然后用这个元素除以人数,就得到了平均分。)。虽然他不如映射函数那么并行,但是因为化简总是有一个简单的答案,大规模的运算相对独立,所以化简函数在高度并行环境下也很有用。 分布和可靠性
MapReduce通过把对数据集的大规模操作分发给网络上的每个节点实现可靠性;每个节点会周期性的把完成的工作和状态的更新报告回来。如果一个节点保持沉默超过一个预设的时间间隔,主节点(类同Google File System中的主服务器)记录下这个节点状态为死亡,
并把分配给这个节点的数据发到别的节点。每个操作使用命名文件的原子操作以确保不会发生并行线程间的冲突;当文件被改名的时候,系统可能会把他们复制到任务名以外的另一个名字上去。(避免副作用)。
化简操作工作方式很类似,但是由于化简操作在并行能力较差,主节点会尽量把化简操作调度在一个节点上,或者离需要操作的数据尽可能进的节点上了;这个特性可以满足Google的需求,因为他们有足够的带宽,他们的内部网络没有那么多的机器。 用途
在Google,MapReduce用在非常广泛的应用程序中,包括“分布grep,分布排序,web连接图反转,每台机器的词矢量,web访问日志分析,反向索引构建,文档聚类,机器学习,基于统计的机器翻译...”值得注意的是,MapReduce实现以后,它被用来重新生成Google的整个索引,并取代老的ad hoc程序去更新索引。
MapReduce会生成大量的临时文件,为了提高效率,它利用Google文件系统来管理和访问这些文件。 其他实现
Nutch项目开发了一个实验性的MapReduce的实现[2]。
OpenRS-Cloude:基于MapReduce的并行遥感处理系统
OpenRS-Cloude是建立在MapReduce并行模型和OpenRS插件体系基础之上的分布式遥感数据处理开发系统。主要提供一个可以利用廉价PC机群进行高性能遥感数据处理的分布式平台,主要提供任务并行化处理,Web监控,分布式存储,算法插件化和多语言接口等功能。
OpenRS-Cloude主要由两部分组成:算法调用与任务管理。算法调度主要是通过OpenRS核心插件系统来调用系统本身提供或者第三方开发者实现的各种算法。由于利用了OpenRS插件系统,所以继承了OpenRS的开放特性;任务管理是一套基于MapReduce并行模型的任务管理、调度和监控系统,系统本身提供web页面方式的各种任务提交与管理型接口。MapReduce模型最早被Google最资深的计算机科学家Jeff Dean用于分布式计算,他在处理Google的日常工作时,认识到Google所需的绝大部分数据处理都可以归结为一个简单的并行算法:MapReduce。这个算法能够在很多种计算中达到相当高的效率,而且是可扩展的。 MapReduce的主要两个概念是\"Map(映射)\"和\"Reduce(化简)\"。他们的主要思想,都是从函数式编程语言里借来的,还有从矢量编程语言里借来的特性。简单而言,Map函数是用来把一组键值对映射成一组新的键值对,用于子任务执行,而Reduce函数是用来保证所有映射的键值对中的每一个共享相同的键组,用于子任务处理结果的合并。MapReduce会生成大量的临时文件,为了提高效率,一般采用分布式文件系统来管理和访问这些文件。 OpenRS-Cloud通过结合OpenRS插件系统与MapReduce并行计算模型,为各种遥感算法提供一个通用的并行算法开发环境。
在OpenRS-Cloud中,我们将任务称为Job,而子任务成为Task,每个Job在经过任务分解过程后,形成多个Task,每个Task具有分离内容(inputSpilit),系统将各个子系统根据优先级将子任务发送到各个处理服务器进行并行处理,最终结果汇集在一台服务器上,做最终的结果合并工作,将最终的处理数
据写入到指定的磁盘上。在上述过程中,Map所产生的中间结果存储在分布式文件系统中,用于最终Reduce操作的数据读取和处理。
平台+插件软件设计思想
一、已有的软件系统(平台+插件)介绍与插件分类
现在就来看 一看所有软件系统的根——操作系统(OS)。操作系统是系统软件,是计算机不可缺少的关键软件,只有安装有操作系统的计算机才能为人所用,才能变为真正计 算工具。操作系统除完成其基本功能以外,还为软件开发人员提供了应用程序开发接口(API),软件开发人员使用API进行软件设计与代码编写,程序调试编 译以后,安装在所依托的操作系统之后,用户开发的软件(可分为工具软件和应用软件)就可以正常运行。而这时并不需要对操作系统进行修改,也不需要重新编译 和链接操作系统,对于用户软件来说,操作系统是完全透明的。操作系统与用户软件是一个极好的平台+插件实例。
除操作系统之外,在用户软件方 面也有许多这种平台+插件的软件系统实例,其中大名鼎鼎的就是Adobe公司的PHOTOSHOP图形处理软件。PHOTOSHOP除其图形处理功能卓越 以外,还有一项给开发人员印象较深的就是其插件(Plug-in)功能。为了提高图形的处理功能PHOTOSHOP提供了标准插件开发接口,这样第三方软 件开发商就可以按标准插件接口开发独具特色的图形功能扩展,开发的插件安装后,系统即可使用,而不影响主程序和其它插件,通过此种方法PHOTOSHOP 扩展了成千上万的滤镜(Filter)功能插件。除PHOTOSHOP外,使用插件技术的软件还有IE,Netscape,Macromedia公司的系 列软件,以及Microsoft的Visual Studio开发工具及Office办公软件等。各用户软件领域所应用的插件技术可分为三种类型:
1、 类似批命令的简单插件(文本插件)。事实上这种插件的自由度非常低。使用这种方法的软件有Win Hacker等,运行这种插件后,会一步步要求用户进行选择/输入,最后根据用户的输入来执行一系列事先定义好的操作。这种插件一般是文本文件。功能比较 单一,可扩展性极小。优点是插件做起来非常方便,即使是对程序设计了解不多的人也可以制作。如WinAmp的Skin。
2、使用一种特殊的 脚本语言来实现的插件(脚本插件)。这种插件比较难写,需要软件开发者自己制作一个程序解释内核。比如微软惹了很多麻烦的宏就是这种类型的。 Microsoft Office就提供了开发者用于扩展辅助功能的内置VBScript(VBA)。这种方法的优点在于无需使用其它工具来制作插件,软件本身就可以实现,普 遍出现于各种办公自动化软件中。
3、利用已有的程序开发环境来制作插件(程序插件)。例如PhotoShop等软件使用的方法。使用这种方 法的软件在程序主体中建立了多个自定义的接口,使插件能够自由访问程序中的各种资源。这种插件的优势在于自由度极大,可以无限发挥插件开发者的创意,这种 插件是狭义范围的插件,也是真正意义上的插件。而这种插件机制的编写相对复杂,对
于插件接口之间的协调比较困难,插件的开发也需要专业的程序员才能进行。 本文主要讨论的是第3种类型插件,即利用已有程序开发环境制作的程序插件。 二、平台+插件软件设计基本思想
插 件的本质在于不修改程序主体(平台)的情况下对软件功能进行扩展与加强,当插件的接口公开后,任何公司或个人都可以制作自己的插件来解决一些操作上的不便 或增加新的功能,也就是实现真正意义上的“即插即用”软件开发。平台+插件软件结构是将一个待开发的目标软件分为两部分,一部分为程序的主体或主框架,可定义为平台,另一部分为功能扩展或补充模块,可定义为插件。
在进行软件开发之前,是否采用平台+插件结构进行软件开发,还要依据具体的软件 需求情况进行确定,但一般来讲,使用平台+插件结构进行软件设计会给所开发软件增加新的生命力。当确定平台+插件的软件结构之后,就要分析哪些部分功能由 主体完成,即平台的基本功能,哪些部分功能由插件完成,即需要扩展的插件功能。平台所完成的功能应为一个软件系统的核心和基础,这些基本功能即可为用户使 用,也可为插件使用,就是又可以把平台基本功能分为两个部分,内核功能和插件处理功能。平台的内核功能是整个软件的重要功能,一个软件的大部分功能因由内核功能完成。平台的插件处理功能用于扩展平台和管理插件,为插件操纵平台和与插件通信提供标准平台扩展接口。插件所完成的功能是对平台功能的扩展与补充,一般插件完成系列化功能,例如:PHOTOSHOP的滤镜插件完成对图形的特殊效果处理,这些功能都有一些共性,可以进行集中管理,并且是可以定义出标准 的插件接口。
为了实现平台+插件结构的软件设计需要定义两个标准接口,一个为由平台所实现的平台扩展接口,一个为插件所实现的插件接口。这 里需要说明的是:平台扩展接口完全由平台实现,插件只是调用和使用,插件接口完全由插件实现,平台也只是调用和使用。平台扩展接口实现插件向平台方向的单向通信,插件通过平台扩展接口可获取主框架的各种资源和数据,可包括各种系统句柄,程序内部数据以及内存分配等。插件接口为平台向插件方向的单向通信,平台通过插件接口调用插件所实现的功能,读取插件处理数据等。
平台插件处理功能包括插件注册、管理和调用,以及平台扩展接口的功能实现。插件 注册为按照某种机制首先在系统中搜索已安装插件,之后将搜索到的插件注册到平台上,并在平台上生成相应的调用机制,这包括菜单选项、工具栏、内部调用等。 插件管理完成插件与平台的协调,为各插件在平台上生成管理信息以及进行插件的状态跟踪。插件调用为调用各插件所实现的功能。平台插件处理功能实现的另一部 分功能为平台扩展接口的具体实现。 平台+插件软件设计步骤包括:
1、 确定平台基本功能和插件要完成系列化功能或扩展功能; 2、 定义平台扩展接口和插件接口;
3、 完成平台设计,主要是平台插件处理功能;
4、 向插件开发者提供主平台程序(执行代码),公布平台扩展接口和插件要实现的接口,可能包括开发用的SDK;
5、 插件开发者按要求开发插件,实现插件接口,开发者可使用提供的主平台程序测试插件; 6、 主平台设计者继续完成主平台的内核功能,并可随时公布新增加主平台扩展接口和插件接口;
7、 实现4-6步骤的良性循环,整个软件系统不断向前进化。 平台+插件软件设计的优点:
1、 实现真正意义上的软件组件的“即插即用”;
2、 在二进制级上集成软件,减少大量的软件重新编译与发布麻烦与时间; 3、 能够很好实现软件模块的分工开发,能够大量吸取他人的优长; 4、 可较好实现代码隐藏,保护知识产权。
基于COM的原型实现
平台+插件软件的目标及设计思路已经明确,那么用什么样的方法和技术实现插件(程序插件),从目前已有这方面软件的设计方法来看(Windows系统上的软 件),一种是使用传统DLL方法的实现,一种是使用COM方法的实现。下面就以COM技术为基础,实现一个基本的原型框架设计。COM技术的原理大家都已 经相当熟悉,本文为了实现平台+插件的几方面功能,相应地采用COM的相关方面技术与方法来介绍有关实现要点。整个原型系统开发环境:Windows 2000、Visual C++ 7.0,使用的开发库包括MFC和ATL。 插件注册 为了管理插 件首先是设计一种插件的注册机制,通过此种机制平台可以搜索到系统中所有的可用插件,并在平台上生成各插件的调用点。注册就需要为每插件设置一个特殊标 识,有了这个标识的插件,平台就可以使用。使用COM实现注册机制有一种非常好的方法,这就是组件目录(Component Category)。组件目录也是COM实现的标准接口(Interface,不同于平台+插件中所说的接口)。在设计COM组件时,只为其定义一个目录 分类信息即可,之后就可使用标准的组件目录接口在系统中搜索特定类型的组件,插件注册与标识就可轻松地解决了。
插件管理与调用 由 组件目录获得特定标识的组件后,就需要为每个插件生成管理机制,每个插件都有一个类ID(CLSID),在平台中为每个插件生成一个类ID数组,每个插件 的每一个可调用功能均生成一个菜单项(动态生成菜单项)。对每个插件是否激活,平台都有相应的记录信息。插件调用可通过菜单消息循环或内部调用实现。
平台扩展接口和插件接口 这 两个接口不同于COM技术中的接口,但平台扩展接口和插件接口可使用COM技术的接口定义实现。在原型系统的实现上平台扩展接口定义了一个IServer 接口,插件接口定义了一个IPlugin接口。IServer接口用于为插件传递内部数据接口,IPlugin接口用于读取插件功能信息,并且还用于传递 平台消息与资源句柄。
消息、资源与数据传递 平台与插件之间需要进行大量的消息与数据交互,其中包 括:各种Windows消息、各种Windows资源句柄,以及系统使用的各种内部数据,有时还可能需要分配内存。所有的消息与数据交互均由平台扩展接口 和插件接口所定义的标准方法实现,在原型系统中已经实现了鼠标消息、窗口句柄、设备句柄和程序内部定义数据结构的传递。
结论:原型系统已实现一种通用的平台+插件软件开发的框架模式,通过实践证明这种思路和设计方 法可行,可以应用到我们的具体软件开发上。通过这种方式可以很好地解决软件合作开发与集成问题,对有版本级别的软件开发更为有用。高级版的软件安装有高级 版的插件,低级版的软件不安装高级版的插件,这就给程序分发和开发带来极大的便利。对于有系列化功能的软件,系列化功能由插件实现。
SharpDevelop学习
网址:www.sharpdevelop.com 简介:
SharpDevelop是一个免费开源的IDE开发环境,它是基于类似eclipse的插件思想,完全由C#语言开发的一套完整的.Net IDE开发环境,它具有如下特点:
1.
体积小:和几个G的visual studio相比,它仅仅只有4M多,体积相差了几百倍,但是麻雀虽小,五脏俱全,用它开发普通的程序,足够用了。
2.
新的2.0版本的解决方案和工程文件同visual studio 2005 100%兼容,这下它们就可以互相打开对方的工程,再也不用为兼容性发愁了。
3. 4. 5. 6. 7.
以前的老版本的调试一个问题,但在新版2.0中已经支持断点调试。
它简便易用。但凡使用过VS之类IDE的人,只要简单操作一下,基本就能了解个大致。 多语言支持,当然也包括简体中文。 支持插件扩展。
免费开源,它的代码可以说是学习.net最生动的教材。
对云计算中几种基础设施的朴素看法(RT)
前言
云计算的概念近期可谓如火如荼,备受关注。我先前听到“云”这个名词时,很是觉得太过玄乎——也不知道它用在哪里,更不了解它如何实现,总有雾里看花的感觉!
好在近期工作需要的缘故,学习和开发过类似于“云计算”基础设施的内部系统,之后再回过头来看看业界两大寡头(Google,Amazon)推出各自的云计算服务,从认识上才算是真的将“云”这个天书般的概念落实。后面的文章中我将在个人理解的基础上,针对云计算的概念,体系结构,以及适用性等方面作一些不算很深入分析和对比,希望对大家理解云计算架构有所帮助。
第一部分 什么是云计算
云计算的标准定义留给大家去Google吧,我这里谈谈我简化理解后的云计算是什么东东:先来看云计算的产生原因吧!——首要原因是为了应对待处理数据爆炸式增长与当今机器存储能力和计算能力不足之间的矛盾(借用一下我国当前基本矛盾的书法:)。由于待处理数据越来越多(不是用多少G就能描述的范畴了。想象一下假若要存储并计算数千万用户的访问日志,或者计算数亿个网页的Page Rank),多到了很难在一台或有限数目的存储服务器内容纳,且更无法由一台或数目有限的计算服务器就能处理这样的海量数据。—— 当然,你也许会想到买来漂亮的EMC存储阵列和HP的SUPERSTONE这样的小型机搞定一切,但是它们有点贵喽,这种砸钱的大家伙只能留给阔绰的银行、电信企业,或者国家气象局这些机构使用了—— 这时就需要能在普通机器(比如在中关村攒出的廉价PC)上分布式的存储这些数据,并能在其上分布式计算这些数据。你肯定会说,这不久是分布计算吗?没错,云计算可以说是经分布计算,并行计算,网格计算一脉相承的技术路线,甚至可以说它们基因相同。但它们的给人的外貌却不同,这是因为云计算是经过商业包装的名词,其实就是将分布存储和分布计算这种技术找了个盈利模式——将存储能力和计算能力出售给第三方企业。而第三方不需知道其数据到底存在那个机器上,也不需要知道那个机器在处理它们的数据,因此对它们来说数据在云端,计算也在云端,大约如此,才有了“云计算”这个概念。
目前出售云计算服务的有Amazon和Google两个业界老大(听说Oracle和APPLE也开始搞了,EMC似乎也有计划),出售的服务内容大体相同,盈利方式也大同小异(具体参看他们的网站的S3服务, EC2服务,或Google App Engine服务等)。它们技术架构虽有差异,但从概念上讲可把云计算看成是“存储云”结合“计算云”的有机结合,即“云计算 = 存储云 + 计算云”
第二部分 存储云的架构介绍
存储云概念
存储云依我看就是一个被商业包装过的分布存储系统——只不过它对第三方用户公开存储接口,用户可买容量和带宽,且规模相当宏伟的分布存储系统。关于商业模式问题我们就不多作探讨了,大家可到其网站上仔细瞧瞧。我这里的重点是对用于存储云的分布存储系统作对比分析。(不过假如你对存储云完全不了解,那我建议在看下面内容之前,先去读读相关的论文什么的介绍吧!以便我们的讨论事半功倍。) 存储云结构比较——Dynamo VS Bigtable
比较典型的存储云基础系统有Amazon公司的Dynamo系统与Google公司的Bigtable系统,这两种系统不但已经开始是商用(参见S3 服务和 Google App Engine服务),而且都公开了比较详细的实现论文(尤其dynamo系统论文格外详尽——可见Amazon公司的无私和自信)。它们各自实现架构迥异,存储特性不一,但都结构优美,技术上各有可称道的地方,可谓各有千秋,却又殊途同归。
下面我们将针对它们两者存储数据的要求、体系架构、扩容、负载均衡、容错、数据存取及查询等我觉得重要的方面进行一些点到为止分析比较,以辨明良莠。
数据结构化问题
首先要提到的是两者存储数据属性上的区别,虽然两者都是以key/value形式进行存储,但Dynamo偏向存储原数据,因为其所存储的数据是非结构化数据,对value的解析完全是用户程序的事情,Dynamo系统不识别任何结构数据,都统一按照binary数据对待;而Bigtable存储的是结构化或半结构化数据(web数据特点就是介于结构化和非结构化之间,因此称为半结构化数据。我这里不展开说它了,不了解半结构化数据的赶紧去google一下吧!),其value是有结构的数据——就如关系数据库中的列一般,因而可支持一定程度的Query(比如可按单列进行)。这点上看Bigtable更接近数据库(接近而不是等价!至于和关系数据库的具体区别可去google 一下,网上论述可不少!);另外, Bigtable所存储的数据都是以字符串格式实现,所以对主建或者列(以及其自动加上的时间戳)排序都是以字符序进行,而dynamo的键值并非以字符串存储,而是统一经过md5算法转后成16字节md5_key存储的,因此对数据的访问必须知道key才可进行,故而对扫表(用游标)或者query访问则无能为力。当然在dynamo的基础上,配合一些方式我们实现query也并不可能,一些具体方式我们后面慢慢探讨! 控制与存储架构比较
Dynamo是采用DHT(分布哈希表,请参看有关资料吧)作为基本存储架构和理念,这个架构最大特点是能让数据在环中“存储”均匀,各存储点相互能感知(因数据需要在环内转发,以及相互之间进行故障探测,因此需要节点之间的通讯),自我管理性强,因为它不需要Master主控点控制,有点是无热点,无单点故障危险——插一句,目前新浪的memcachedb(改造memcached,增加了持续化能力)其实可认为是这种架构的最简单代表(数据进入系统后,使用DHT算法均匀的发送到存储节点上,而最后存储引擎采用Berkelery DB,将数据持续化到本地硬盘)。
Bigtable的控制是采用传统的server farm形式,使用一个主控服务器+多个子表服务器构成。而数据存储形式是采用多维Map的稀疏结构,可看成是由多个列表组成,所谓稀疏是说每条记录并非要求有全列。其数据(包括索引,日志,记录数据)最终是存储在分布文件系统DFS之上——数据被以DFS所特有的文件形式分布存储在各各节点之上。相比DHT的存储环自管理技术,它需要有master主控服务器来负责监控各客户存储节点(分配子表,失效检测,负载均衡等),另外索引文件的根也是集中存储,需要客户端首先读取(之后可以采用预读和缓存的技术减少读取索引表的次数)。这种集中控制的做法有一个缺陷就是系统存在单点故障 —— 因此单点需要高可用性,如记录恢复日志或双机备份等——但好处是更人为可控,方便维护,且集中管理时数据同步易于方便——显然,更新集中存储的原数据(如数据索引或节点路由等)相比DHT环中各个节点存储的原数据(如membership,即各点的路由关系)需要利用“闲谈机制”依次通知式地进行渐近更新要容易许多。
容错问题
Dynamo和Bigtable都不是实验室应付领导参观,或者是炫耀技术的Demo,而是要实实在在进行商业运营的产品,因此首先要考虑的是机器成本问题!最节约的方式就是采用普通PC服务器(目前市场价格大约2/3千元就能买到存储1T数据的机器——自然是没有显示器,声卡这些外设的)作为存储机器。但做过大数据处理的人都知道,IDE/STAT硬盘的稳定性和寿命是无法和真正服务器中的SCSI硬盘相媲美(除硬盘外的其余部件的稳定性和寿命也一样和服务器差距颇大),在压力下损坏那是家常便饭——据Google
说,1000台机器的集群中,平均每天坏掉一台机器——因此设计之初就将硬件故障认为是常态的,也就是说容错成为设计优先考虑的问题了。
鉴于上述原因,Dynamo和Bigtable的数据都是冗余存放,也就是说一份数据会被复制成数份(副本数是可以根据数据要紧程度指定的),并被分散放在不同的机器上,以便发生机器宕机(偶然性宕机或网路不通属于临时故障,而硬盘坏掉则是永久故障,永久故障需要进行故障恢复——从副本恢复数据)时还有可用副本可继续提供服务——通常存放三个副本就已经可以高枕无忧了,因为要知道三个副本同期坏的可能性小到了1000*1000*1000分之一。
Dynamo 的冗余副本读写策略比较有趣,它定义了:N,W,R三个参数。其中N代表系统中每条记录的副本数,W代表每次记录成功写操作需要写入的副本数,R代表每次记录读请求最少需要读取的副本数。只要W+R >N就可以保证数据的一致性。因为W+R>N时读写总会有交集——必定最少有W+R-N个读请求会落到被写的副本上,所以必然会读到“最后”被更新的副本数据(至于谁
“最后”的判断需采用时间戳或者时钟向量等技术完成——有逻辑关系先后由时钟向量判断,否则简单的用时间戳先后判断.详情去看dynamo论文吧)。这种做法相比我们最朴素的想法——我们直观的想法一定认为如果系统要求记录冗余N份,那么每次就写入N份,而在读请求时读取任意一份可用记录即可——要更安全,也更灵活。说其更安全是指数据一致性更能被保证:比如说客户写入一条记录,该记录有三个副本在三个不同点上,但是其中一个点临时故障了,因此记录没有被写入/更新。那么在对该记录再读取时,如果取两点(R=2)则必然会读取到最少一个正确的值(临时故障点有可能在读是恢复,那么读出的值则不存在或者不是最新的;若临时故障点还未恢复,则读请求无法访问其上副本)。而使用我们传统方法可能读到发生临时故障的那点,此刻就有可能读出现错误记录(旧的或者不存在),因此可以看到加大W,R可提高系统安全性;说其更灵活则是指可通过配置N,W,R这几个参数以满足包括访问方式、速度和数据安全等迥异需求的各种场景:比如对于写多读少的操作,可将W配低,R配高;想法对于写少读多的操作,则可将W配高,R配低。
Bigtable的容错问题论文中没有详细讲,我想它应该是将该任务交给其下的DFS处理了:DFS是在文件chunk(64M)写入chunk服务器时,将数据chunk传播给最近的N-1个chunk服务器,从而确保了系统中每个chunk存在多个副本,而这些chunk 的位置信息都会记录在master服务器的文件原数据中。再访问文件时,会先获得原数据,再从可用的chunk服务器中获取数据,因此一个chunk server发生故障不影响数据完整性,照样能读。另外DFS的故障的恢复等工作也是在master服务器监控下将某个副本chunk进行复制,以恢复故障机器上的数据副本。
最后值得提一下的是,Dynamo对于临时故障的处理方式是:找到一台可用机器,将数据暂时写到其上的临时表中,待临时故障恢复后,临时表中的数据会自动写回原目的地。这样做得目的是达到永远可写(那怕该云中只有一台机器可用,那么写请求的数据就不会丢失)。这个需求未见Bigtable提到,但从其架构上看DFS对写操作来说,应该也是能达到接近Dynamo的永远可写需求的(master会帮助选择一个可写的chunk
server 作为写请求的接受者的,因此系统只要master不可用,最少再有一台可用chunk server机器就以满足。
扩容问题
对于一个存储可视为无限大的存储系统来说,扩容需求(扩容需求除了存储容量不足外,存储节点并发处理能力不足,也会要求扩容)自然无法逃避,而且对于在线服务系统扩容时期要尽量不停止服务或者尽可能短的停止服务,因此优美的扩容方案是存储云中最值得关注的要点之一。
我们还是先来说说Dynamo系统的扩容策略和实现。试想一下,将一个机器中的指定数据表扩容,首先需要将这个数据表劈开成两个表,然后再把其中一个转移到另外一台新机器上去。而这里的劈表动作说起简单,作起来则颇为费力,因为无论数据表是按照键值区间有序组织(如DHT环方式),或键值本身有序组织(如Bigtable方式),都不可避免的需要扫描整个数据表(特耗资源的操作,绝对会影响其他服务的)才能从中挑选出一部分有序数据移到新表中,从而保证劈开后的两个表仍然维持有序结构。为了避免笨拙的扫表工作,Dynamo取巧了,它会将md5 key所围成的环行区间,尽量划分的粒度细一些,也就是多分成一些较小的区间/段(一个段对应存在硬盘上的一个数据表),但是要求一个物理机器不只存储一个段,而是存储连续区间的一组段表,这样以来在扩容时就能将劈大表的操作给回避了。比如将环分成1024段(存储数据上规模时,实际部署时段表要分的更细致得多),然后又规定每个存储点维护64个段表,那么全部数据起先可部署在 16个机器的存储环上。如果发现某个机器存储不下64个段表时(或者承受不了当前的并发请求量时),则将其中部分段表转移到新扩容的机器上去即可,比如从原机器上转移32个段表拷贝到新机器即可完成扩容——这种小表迁移避免了对大表拆分时的扫表、劈表动作。当然你会说这种扩容有限制,只能扩容6次。没错,因此在实际存储环之初,是需要估计数据总量,扩容次数等问题的,但这绝对值得。Dynamo除了段表思想值得学习外,还提出了扩容期间不停服务这种要求很是可爱。我们也尝试过这种高可用性扩容设计,其主要任务是要理清楚,从而细致处理扩容期间(包括数据扩容和路由更新)的访问请求的状态机。另外要说的是扩容时为了不影响正常请求访问, 都将扩容例程安排在低优先级进行, 让它在正常读写请求压力小时再偷偷进行!
对于Bigtable扩容问题Google本身的论文描述有些暧昧,但却可在另一个类Bigtable系统——hypertable——那里看到比较清晰的说法。Hypertable是Bigtable的开源C++实现。由于Hypertable中记录存储是被集合成固定大小的tablet(默认的最大值是每个200M)存在DFS上——而DFS本身具有可扩容性(允许在线添加新机器到server farm中)—— 因此Hypertable存储总空间的扩容不存任何问题。其要作的只是当子表(Range段)过大时,需要将其从中间key 劈开成两个新表,把包含后半段key范围的新字表迁移到别的range server上去。注意这种分子表的实现路数似乎仍然需要去扫描表,在这一点上我个人认为不如Dynamo做的聪明、利索。关于hypertable的表的管理值得大家去留心,但这里不多说了。(请看hyptertable 站点:http://www.hypertable.org/documentation.html/)
负载均衡问题
负载均衡(意义在于数据存储均衡和访问压力均衡)对于Dynamo系统而言是天生的优势,因为它采用了DHT方式将数据都均匀存储到各个点了,所以没有热点在(或者说要热,则环中所有的点一起热),各点的数据存储量和访问压力应该都是均衡的(这点由md5算法特性决定)。 另外这里还要提一下Dynamo
系统中的Virtual Node概念——VNODE 可看成一个资源容器(类似于虚拟机),存储作为一个服务运行于其中。引入VNODE 目的在于将资源管理粒度单元化。 比如一个VNODE 让你且只让你管理5G硬盘,500M内存等,那么你就只能使用这么多资源。这样有两个显而易见的好处:1 方便管理不同配置的异构机器,比如资源多的机器多部署一些VNODE ,而资源少的机器少不部署一些VNODE 。 2 对于扩容大有好处,因为DHT环中加入一个新节点,如果想保持数据均匀分布的特性,那么必须将全环的数据都要移动才有可能,这样无疑增加了网络震荡,因此最理想的方式是在环内每个点都进行扩容,这样就只需要移动旁边节点的数据了。那么单增加一个或几个机器显然不能均匀分配环的其他存储点旁,因此需要将一台物理机器划分成众多个VNODE ,这样才有可能能将这些VNODE 比较均匀的散布在环内其他节点旁了。随着逐步添加机器,那么数据均匀性逐步提高,可见这是一种逐渐式的数据均衡过程。
对于Bigtable的负载均衡是也是基于传统上server farm :依靠一个master服务器监视子表 server的负载情况,根据所有子表服务器的负载情况进行数据迁移的,比如将访问很热的列表迁移到压力轻的子表服务器上(数据最终还是落在了chunk server —— DFS上的存储服务点,从层级结构上来说处于子表服务器之下)。具体做法你可参见他们的论文,总的来说有没有太多创新。
数据存取和查询问题
Dynamo和Bigtable两种体系都支持key/value形式的记录插入,而且也支持主建的随机查询。不过前面已经提到了如果需要按照列进行查询,或者需要range的query查询,则Dynamo就无能为力了,只能使用Bigtable架构(但要知道Bigtable并没有关系数据那么强,对于query的支持也仅仅是支持条件是单个列,不能以多列为目标进行复合条件查询,更别说join查询等)。从这点上说bigtable更接近数据库,而Dynamo则是一个简单的存储系统。
amazon在S3(可能基于Dynamo)之后,推出了支持query的Simpledb 系统。 该系统和Bigtable很类似,但似乎功能更强,它支持=, !=, <, > <=, >=, STARTS-WITH, AND, OR, NOT, INTERSECTION AND UNION等复杂的query 操作。这真是个出色的产品,不幸的是amazon并没有向对Dynamo那样慷慨的公开发表其实现的论文,因此大家只能猜测其实现,有的说是在Erlang上重写的,有的说在Dynamo基础上开发的,有的说是抛开Dynamo全新实现的,目前说法众多,无从得知。这里我仅仅就我个人的认知,谈谈假如在Dynamo上是如何实现Query功能类似的功能。
首先能想到的是为Dynamo增加schema,也就是将value划分成逻辑列,这样以来在存储时可以按列建立索引文件,那么就自然可以实现对列的 query。索引文件内容可以是列值到主建集合的映射,其存储以文件形式存在于分布文件系统之上。当对列进行query时,首先在索引文件中找到对应的主建集合,然后在以主建从Dynamo中获得记录。不过这样作有一定限制: 1 分布文件系统需要能支持并发修改文件能力(因为索引文件需要频繁改变),而大多数分布文件系统为了数据一致性和效率的考虑,都只能支持并发追加操作,因此要想实时的完成数据更新的同时支持查询操作有难度——简单的方法是定期更新索引文件,那么副作用就是查询的结果不是最新的;2 只能对预先建立索引的单列进行排序(当然可以建立联合索引),并不能支持对任列,或者任意的复合条件完成query查询——我是没想到什么好办法。
另外一个方法是使用关系数据库作Dynamo的存储引擎——如果你看过Dynamo的论文,可否记得它提到了实际的存储引擎可使用Berkelery DB或者mysql等 ——,那么在存储环中进行查询的操作可化整为
零:将查询任务路由到各各存储节点上分别进行查询之后,再将结果收集起来,对于需要排序的请求则还要再集中进行排序一次。这种做法把索引等等的工作都交由关系数据库去作,我们作的只是需要汇总结果。 在这个思路上可以进一步结合数据分发Partition策略:不再按照md5 key那样在节点上均匀的存放数据,而是按照列作partition 篇分发数据,如地址属性中的Beijing,xi an等不同地名的数据路由到指定不同节点上,那么在按地名进行查询时,则可以直接将请求下发到对应存储节点,这样避免了全环下发查询人物,能更有效的完成以列为条件的复杂查询。除此外,还可以对列进行区间排序partation,如对年龄列,按照0-10岁一个区间,10-20一个区间,20-30一个区间,而每个区间存储在不同节点上,这种有序区间部署方法可支持按列排序查询要求。不过有得必有失,partition存放的缺点是数据不够均匀,因此负载不平衡,所以需要能把partation节点纵向扩容,比如把负责20-30区间的存储节点多搞几个以分担并发压力。
第三部分 当前计算云的架构实现
存储云的商业模式是出卖存储能力,而计算云的商业模式是出卖计算能力。存储云的基础技术是分布存储,而计算云的基础技术是分布计算——更准确说在是“并行计算“。 并行计算的作用是将大型的计算任务拆分,然后再派发到云中的节点进行分布式的并行计算,最终再将结果收集后统一整理(如排序、合并等)。如果说云计算云是并行计算的升华的话,那么只在一个层面上有所进步 —— 计算资源虚拟化:计算云中的所有计算资源都被看成一个可分配和回收的计算资源池,用户可根据自己的实际需求购买相应的计算资源。
这种资源虚拟化得益于近日重新兴起的虚拟机技术,采用虚拟机实现资源的虚拟化,既可以避免了硬件异构的特性(无论什么样的硬件机器主要攒在一起,其计算资源都可被量化到计算资源池中,并被动态分配),更可以实现资源的动态调整,因此能极大的节约了云中的计算资源(动态调整就是不需要重新启动系统就可调整资源大小,这是虚拟化技术的最大用处之一)。这种虚拟化和我们在自己机器上安装的虚拟机所采用的虚拟化技术大同小异,其异处就在于我们个人用户的使用模式是将一台物理机器的资源虚拟化成多份,以使得其能同时启动多个操作系统;而云中的虚拟化技术是将多个物理机器的资源虚拟化成一个大的资源池,让用户感觉是一个巨大资源的机器——但是要知道只有任务在能并行计算的前提下,资源池虚拟化才有意义。比如用100个386机器组成的计算云可以处理1T的日志数据,如果日志数据的处理可以被并行进行,那么可让每个386机器都处理1/100T的数据,最后将所有中间结果合并成最后结果。但是如果任务无法平行差分,再大的计算池也没用(云计算应用是有限的,目前最能用的上的是web网站——数据量大,但处理相对简单)。
总而言之:计算云的架构可以看成是:并行计算+ 资源虚拟化。
并行计算架构(Map/Reduce)
对于资源虚拟话的问题,这里不作讨论了,有机会我们专门起个话题进行深入探讨。这里主要说说云中的并行计算方式。并行计算是个老话题了,很多基于MPI的并行计算软件处处可见。MPI采用任务之间
消息传递方式进行数据交换,其并行开发基本思路是将任务分割成可以独立完成的部分,再下发到各计算节点分别计算,计算后各节点将各自的结果汇总到主计算点进行最终汇总,各点之间的的交互由消息传递完成。对于并行计算面临的主要问题是: 1 算法是否可以划分成独立部分;2 获取计算数据以及中间结果存储代价很高,因为海量数据的读取会带来沉重的IO压力——如在处理诸如page rank等互联网应用上,很大程度上大量、频繁的读取分布存储的网页数据造成了任务计算速度的瓶颈。
对于第一个算法问题,从计算架构上考虑勉为其难,关键在于分割算法。而对于第二个IO压力问题,最好的解决办法莫过于Hadoop项目项目所用的Map/Reduce方式,其思想很简单,就是将计算程序下发到数据存储节点,就地进行计算,从而避免了在网络上传输数据的压力。这并非一个创新思想,很久之前就有诸多尝试(比如IBM曾经搞国一个叫Aglet的移动代理项目,就是将计算程序下发到各节点计算和收集信息),但对于海量数据处理的今天这种方式无疑最具吸引力,代价最小。
简单说Map是一个把数据分开的过程,Reduce则是把分开的数据合并的过程。如Hadoop的word count例子:用Map把[one,word, one,dream]进行映射就变成了[{one,1}, {word,1}, {one,1}, {dream,1}],再用Reduce把[{one,1}, {word,1}, {one,1}, {dream,1}]归约变成[{one,2}, {word,1}, {dream,1}]的结果集。 关于Map/Reduce的抽象方法是map/recduce的精髓之一,但本文不多说它了(你可参看函数语言或其他种种资料,这里不在赘述),本文主要想谈谈Map 的数据来源问题。
MAP/REDUCE数据来源
Map 的数据来源初看也并非什么问题,无非就是读本地数据而已(前面已经说过计算程序作为map的回调算子——借用java的说法——被转移到了数据所在地再执行)。然而具体在海量数据处理的应用场景下就必须考虑和分布存储系统搭配了。 Hadoop的搭配方式最简单,就是和其下的分布文件系统DFS配合: 通过文件系统的原数据来定位文件块的分布节点位置,然后将回调算子下发到其上,已顺序读取的方式从本地文件系统上读取数据。对于日志文件分析等应用,上述做法效率很高,因为日志文件读取可是顺序读取,文件系统的预读特点可充分利用 —— 离线日志分析是利用map/reduce分析的典型应用。
但我们也应看到Map/Recduce 的使用也有明显的局限性:第一是,如果对于较为复杂的输入要求,比如需要对数据集合进行query查询,而非顺序读取文件的输入,则不能直接使用Hadoop的Map/Recduce框架;第二是,其下的分布文件系统为了一致性考虑,不支持多个并发写,而且写后不能修改,这些特性对日志等事后分析效果不错,但对于数据需要实时产生的场景有些勉为其难了。因此考虑是否能将Dynamo,甚至是Bigtable等分布存储系统或者分布类数据库系统在Map/Recduce环境下使用便成了新的需求。不过我感觉Bigtable的存储结构似乎不大容易实现在本地环境内完成进行较为复杂的查询(比如多列的符合查询,不一定能完成,且更不容易在本地完成——应为它无法避免到远程取数据,而如果一旦跨机器进行查询则又带来了过多的网络I/O,违背了Map/Reduce架构进行并行计算的设计初衷。那么Dynamo是否可满足负责query需求呢? 如果采用上文在查询时提到的方法:给记录定义对应的schema,并存储在存储点上将其存在传统的关系数据库中(可以在需要列上建立索引),那么将“回调算子——这里就是query语句了”下发到其上,则可按照传统方式在本地进行query!这样以来既符合了Map/Reduce的初衷,又能满足复杂输入需求,同时还能不影响数据的实时产生。因此我认为灵活、方便的并行计算架构可以由Dynamo或其变种存储系统(如上文所说的partition方式)+ Map/Reduce完成。
当前几种云计算架构中的明星系统
目前云计算中的各种子系统可谓风起云涌,层出不穷。我这里简单提及几个我了解过的项目,大家有兴趣的话可重点跟踪它们,近一步了解云计算知识。
1 Bigtable /Dynamo 上文已经讲过了。
2 Hbase 是Hadoop的一个子项目,类似于Bigtable , 最适合使用Hbase存储的数据是非常稀疏的数据(非结构化或者半结构化的数据)。Hbase之所以擅长存储这类数据,是因为Hbase和Bigtable一样,是列导向的存储机制 3 Couchdb 是Apache下的一个面向文档存储,由Erlang开发而成,和其他新型存储系统一样它同样是分布存储系统,具有很好的扩展性。但不同在于没有任何统一的schema可言,数据组织是平坦的,无行无列。如果需要查询等操作,则借助于用户自己提供的聚合与过滤算子,以Map/Reduce方式进行对文档信息进行全文检索处理——这个角度上说它也能实现类似数据库的查询,可方式方法完全不同——但它提供了一个view的数据关系逻辑接口,对用户而言,可以想象成传统的表。
4 Simpledb 是amazon公司开发的一个可供查询的分布数据存储系统,它是Dynamo键值存储的补充和丰富,目前用在其云计算服务中。其具体实现方式没有论文公开。
5 Pig 是yahoo捐献给apache的一个很有趣项目,它不是一个系统,而是一个类SQL语言, 具体目标是在MapReduce上构建的一种高级查询语言。目的是把一些运算编译进MapReduce模型的Map和Reduce中,允许用户可以自己的功能. Pig支持的很多代数运算、复杂数据类型(tuple,map)、统计运算(COUNT,SUM,AVG,MIN,MAX)和相关数据库检索运算(FILTER,GROUP BY,ORDER,DISTINCT,UNION,JOIN,FOREACH ... GENERATE)
结束语:
我了解的差不多就这么多了。要知道这个领域发展很快,知识更新日新月异——各种存储系统和计算架构如雨后春笋层出不穷,相互促进,各显神通。至于那个最好,大约只能取决于你实际的需求了。我也是开始学习时间不长,可能很多地方理解不对或者说的不清楚,欢迎大家批评指正。很希望能结交一些研究类似系统的朋友,那么就算我的目的达到了。呵呵!
因篇幅问题不能全部显示,请点此查看更多更全内容