北京航空航天大学毕业设计(论文)单位代码 10006 学 号 10061096 分 类 TP393.1 密 级 毕业设计(论文)基于Hubot的个人云系统的设计与实现院(系) 名 称 计算机学院 专 业 名 称 计算机科学与技术 学 生 名 称 刘中巍 指 导 教 师 杨海燕/朱哲 2014年6月基于Hubot的个人云系统的设计与实现 刘中巍 北京航空航天大学基于Hubot的个人云系统的设计与实现 刘中巍 北京航空航天大学北京航空航天大学本科毕业设计(论文)任务书Ⅰ、毕业设计(论文)题目:基于Hubot的个人云系统的设计与实现 Ⅱ、毕业设计(论文)使用的原始资料(数据)及设计技术要求:1.本论文使用的原始资料主要包括Hubot2.7.3的源码、MongoDB官网的技术文档以及关于分布式系统构建的相关文档等。2.构建的个人云系统应该满足如下要求:1) 终端具有泛型的特性:与用户交互的终端应该是泛型的,即在不同的系统以及硬件上能够保证基本的一致性。2) 分布式webapp具有一致性、高容错性与可恢复性:分布式的webapp作为Hubot系统解析的命令的载体,应具有一致性、高容错性与可恢复性。一致性体现在:不同节点之间的行为相似,同样的请求参数,在不同节点之间的计算结果应该是可预测的(算法中随机因子的干扰,会有些许偏差)。高容错性体现在:多节点组成的集群,在单一节点宕机的情况下不应该影响集群整体的可用性,即此时集群的出错情况对用户是不可见的。可恢复性体现在:由于集群中的数据存储是分布式的,对不同的存储节点而言,存储的数据有可能是不完全一样的(分布式数据库集群分片,会有部分的冗余)。所以当存储某些数据的节点宕机后,那么当此节点重新恢复到集群时,应该保证在宕机阶段未能存入的数据可以及时的恢复。 3) Hubot系统具有可扩展的特性:即在系统运行的状态下,可以加入新的命令,并在此阶段不影响用户的使用。Ⅲ、毕业设计(论文)工作内容:本课题的主要研究内容是:以个人云计算技术和个人云存储技术为基础,通过全栈式开发的方式,以Hubot作为命令解析系统,用分布式webapp作为命令执行的载体,设计并构建基于Hubot的个人云的终端泛型的原型系统,并通过相关的实验说明个人云系统在功能和特性上的有效性。Ⅳ、主要参考资料[1]Lerner.Ng-Book-The Complete Book on AngularJS[M],Fullstack IO,2013-12-29[2] 朴灵.深入浅出nodejs.人民邮电出版社[M],2013-12-01[3] Kyle Banker .MongoDB in action[M]. Manning Publications,2011-12-01 [4] github .Learn Hubot the hard way[Z].github,2014-4-15 [5]Kristina Chodorow.深入学习MongoDB[M].人民邮电出版社,2012-3[6]Cnode开源社区[Z],http://cnodejs.org/[7]ATA开源社区[Z],http://www.atatech.org/ 计算机 学院 计算机科学与技术专业 类 100614 班学生刘中巍毕业设计(论文)时间:2014年3月01日至2014年6月6日答辩时间:2014年6月9日成绩:指导教师:杨海燕/朱哲兼职教师或答疑教师(并指出所负责部分): 系(教研室)主任(签字): 本人声明我声明,本论文及其研究工作是由本人在导师指导下独立完成的,在完成论文时所利用的一切资料均已在参考文献中列出。 作者:刘中巍 签字: 时间:2014年 6 月基于Hubot的个人云系统的设计与实现学 生:刘中巍指导教师:杨海燕/朱哲摘 要 个人云系统是在个人云计算和个人云存储的基础上发展而来的概念,定义了一种结合个人云计算的计算能力,以及个人云存储的大容量存储能力,以服务于个人为目的云平台。个人云系统刚刚兴起,有人认为它将替代传统的操作系统,实现个人计算的一次新革命。很多公司都在个人云系统领域进行了尝试,但是由于成本、安全性、易用性、生态系统的不完整等原因,尚未有一款成熟的产品实现个人云系统的完整构建。 本文给出一种基于Hubot构建个人云系统的技术实践,在介绍了相关开发技术的基础上,着重介绍构成个人云系统的四个组成部分的设计与实现方案,包括获取命令的终端泛型的Terminal、进行命令解析和派发的Hubot系统、命令的载体,分布式的webapp、以及以个人云存储为基础的文件系统。最后,用实验验证了该原型系统满足了既定的功能以及特性。关键字:分布式系统,个人云系统,HubotDesign and implementation of personal cloud system based on HubotStudent:Liu ZhongweiInstructor:Yang Haiyan/Zhu ZheAbstractPersonal cloud system is a concept evolved from the concept of personal cloud computing and personal cloud storage. It defines a cloud platform combining the computing power of the personal cloud and the large capacity storage of the personal cloud storage, and serving for the private individual. The development of personal cloud system is at starting stage, some people believe that it will replace the traditional operating system, to achieve a new revolution in personal computing. Many companies have been tried in the field of personal cloud system, but due to the incomplete, cost, safety, ease of use, ecosystem, there is not a mature product implementing the construction of personal cloud system.This paper presents a technical practice of constructing personal cloud system based on Hubot. It introduces the related development technologies, and focuses on the design and implementation schemes of the four parts composing the personal cloud system. The four parts are the genericity Terminal for acquiring commands, the Hubot system for command parsing and distributing, the distributed webapp for executing command and the file system based on the personal cloud storage. Finally, the experiment shows that the prototype system to meet the needs of the intended functions and characteristics.Keywords:Distributed system,Personal cloud system,Hubot目录 1绪论 1 1.1课题背景与意义 1 1.2国内外的研究现状 3 1.3课题的目标与内容 4 1.4论文的组织结构 7 2.相关技术简介 8 2.1全栈式开发技术 8 2.2分布式webapp的简介 16 2.3分布式数据库系统简介 19 2.4全双工数据通信协议WebSocket 22 2.5Hubot简介 24 3.系统的设计与实现 29 3.1整体设计 29 3.2终端泛型的Terminal的设计 30 3.3Hubot系统设计 33 3.4分布式webapp设计 37 3.5底层文件系统 41 4.实验验证 46 4.1环境配置 46 4.2功能验证 57 4.3特性验证 68 4.4实验分析 76 5总结与展望 77 5.1总结 77 5.2工作展望 77 致谢 79 参考文献 801绪论1.1课题背景与意义1.1.1什么是个人云系统个人云系统是在个人云计算[1]和个人云存储[2]的基础上提出的概念。个人云计算是云计算在个人领域的延伸,是以Internet为中心的个人信息处理,即通过Internet对个人的各种信息进行组织、存储、分发和再加工。个人云存储是云存储的一个具体应用分支,指的是将云存储技术惠及个人,让每个人都能够将数据通过云端进行存储、分享等。与传统的操作系统不同,个人云系统既可以利用个人云计算提供的计算能力,也可以利用个人云存储的大容量存储能力,是一种以服务于个人为目的的云平台,个人云系统具有平台无关性、资源利用高效性、高可维护性以及高容灾性。1.1.2为什么构建个人云系统 个人云系统是未来的一个趋势。摩尔定律在近年来已经逐渐证明无法继续维持。如果没有新的硬件技术革命,那么单节点的计算能力将会到达一个瓶颈。提升单一节点的运算能力将是一种极大的浪费。于是云计算应运而生,过去庞大的单机系统架构由垂直扩展系统逐渐向水平扩展多个节点的集群方向发展。 虽然从个人电脑的角度来讲,运算能力已经不再是瓶颈,但是数据大爆炸时代的到来告诉我们,未来是会被数据包围的,我们无时无刻不会处理大数据,于是个人云系统的概念就应运而生了,个人云系统解决的问题就是如何惠及普通人的大规模数据运算需求。 与传统的个人操作系统相比,个人云系统具有如下的特点:1)个人云系统是跨平台的,没有特定的载体,无需特定的硬件与终端,因此可以做到跨多终端共享数据;2)个人云系统可以高效利用资源,由于云端的计算能力与存储资源是共享的,是统一分配的,那么相同数量的单一节点就可以惠及更多的用户,从而节省更多的资源,提高硬件的利用率。3)个人云系统具有高可维护性,传统的系统是安装在硬盘上的,那么很多用户无法分享到系统升级带来的好处,但是个人云系统是基于云端的,系统的更新是主动的,无需用户的操作就可以自动完成更新,这样便可以解决很多拖尾效应(安卓平台的版本纷杂,用户通常不会手动的更新新的固件,造成安卓开发者需要兼容多版本的安卓系统,因此这成为安卓平台碎片化的最大祸首,一定程度上阻碍了安卓系统的发展);4)个人云系统具有高容灾性,由于个人云系统是分布式的,单一节点的宕机并不会影响整个系统的使用,这也提高了个人云系统的可用性。个人云系统刚刚兴起,有人认为它将替代传统的操作系统,实现个人计算的一次新革命。回顾计算机发展的历史,大型计算机演进到个人计算机,个人计算机演进到大型的公共云计算,体现了否定之否定的哲学原理。而在个人领域,公共云计算正在演进到个人云计算,实现一次新的否定和飞跃。1.1.3课题的来源本课题的来源于阿里巴巴云计算UED(User Experience Design)团队的一次尝试,在阿里巴巴收购了酷盘之后,酷盘和淘云盘的结合增进了阿里巴巴在云存储上的能力,于是就提出了跨平台的个人办公终端的设想,并试图通过设计与构建基于Hubot的原型系统来探索个人云系统的基本结构和特性。通过阿里云提供的大规模云计算能力以及个人云存储酷盘和淘云盘的存储支持,将硬盘完全移到云端,并将应用以webapp的方式提供,webapp是架构在阿里云可伸缩的ECS云服务器上的,这样既可以利用高效且丰富的云计算资源,又可以将存储的数据保存在云端,大大增加了机密数据的可维护性和安全性。所以这个课题暂时由提出这个想法的阿里云UED进行实现,由于本课题涉及部分商业的非开源代码,所以在本次实现中将不会使用酷盘等部分的核心代码,将会采用百度PCS作为替代。1.2国内外的研究现状国外的云计算开始较早,早期的探索是从云存储开始,成功的产品有从早期的Dropbox[3]到后来的Google Drive[4]等等。后来随着云计算进一步发展,一款真正的云OS诞生了,那就是Chrome OS[5],Chrome OS是一款具有里程碑意义的操作系统,它是基于linux的开源操作系统,在Chrome OS中绝大部分的应用都是在浏览器中完成的,迅速、简洁、安全是Chrome OS的重要特征。但是就个人云概念的理解上,稍有偏差的是在Terminal(在本文中泛指终端,是个人云系统与用户进行交互的载体)的定义,对于Chrome OS而言,Chrome OS需要一个特定的载体,需要x86或者arm架构的系统,才能承载Chrome OS,但是个人云系统中的Terminal是泛指的,是不应该限定Terminal的硬件的,而且由于用户脱离传统的操作系统而使用云系统的使用习惯尚未形成,所以目前的个人云系统的相关生态系统也并不完整。国内对于个人云系统的研究基本还都处在云存储以及混合式云存储的模式。国内的主要云产品有百度云,阿里云的ACE(云引擎)、OSS(结构化存储)、ECS(云服务器)、OTS(开放结构化存储)等等。百度云是百度公司推出的一款云服务产品,通过百度云,用户可以将照片、文档、音乐、通讯录等数据在各类设备中使用,或者在百度的朋友圈中进行分享,与传统的网盘相比,百度云包括了云磁盘、相册、通讯录等云服务。但是百度云的定位还是偏向云存储,尚未完全利用个人云计算的能力。阿里云的ECS、ACE、OSS、OTS等都是阿里云面向开发者提供的云计算产品,其中ECS是云服务器服务,ACE是云引擎服务,OSS是开放云存储服务,OTS是开放结构化数据存储服务。可以说个人云系统中每一个我们需要的模块,在阿里云都有对应的产品,但是尚没有一个成熟的产品将这些模块进行结合,从而构建个人云系统。主要的问题在于如何构建一种商业模式才能与个人云系统进行结合并商业化。因为传统的系统通常是与个人电脑进行绑定的,而这并不是适用于个人云系统,那么个人云系统的盈利模式是怎样的,尚未有一个定论,因此这也是目前很多公司迟迟不推出个人云系统的原因。腾讯是国内另一家在个人云系统领域有所尝试的公司,主要是的产品是webQQ,将传统的即时通讯软件QQ移植到了云端,并添加了相应的分布式webapp,比如图片处理等。从某种意义来讲,webQQ是国内最接近个人云系统定义的一款产品,但是其最大的缺陷在于没有整合个人云存储服务,主要的考量在于安全性,因为依托即时通信的系统在大规模的即时数据交换的过程中如何保证数据的安全和隐私性是另一个难题。可以说,国内的个人云领域的尝试还处在起步阶段,目前尚没有一款产品能够真正的完全符合个人云的定义。主要的原因在于尚未把云存储和webapp以及信息相结合,国内的个人云系统尚处在试验阶段,基本都是只做了数据、webapp、终端中的其一或者其二,尚不能算完全的个人云系统。综上所述,目前的个人云领域还处在探索的阶段,主要的问题由于成本、安全性、易用性、生态系统的不完整等原因,目前尚未有能够满足个人云系统的全部特性的产品出现,所以在本课题中,将会设计和构建一个基于Hubot的个人云的原型系统,用以阐述和说明个人云系统的原理和结构。1.3课题的目标与内容1.3.1目标 在个人云计算和个人云存储的基础上,构建一个具有跨平台、资源高效利用、高可维护性、高容灾性的基于Hubot的个人云的原型系统。设计和构建该系统的目的在于,探索个人云系统的基本架构和特性。本课题构建的个人云系统具有如下的结构,如图1.1所示图 1.1个人云系统的基本结构通过用户交互获取命令的Terminal,该部分是整个系统的前端部分,是与用户直接交互的部分,用户与Terminal进行交互,向其中输入命令并从中得到命令执行的结果,该部分的主要作用就是做命令的传输以及命令结果的展示。进行命令解析并派发的Hubot系统,该部分是整个系统的核心部分,是命令的解析器、是调度webapp和文件系统的大脑。命令的载体,分布式的webapp,分布式webapp是命令的载体之一,它是整个系统的执行程序,通过Hubot系统进行分发调用。以个人云存储为基础的文件系统,该部分是整个系统的最底层,作为webapp的持久化存储,文件系统的主要功能就是持久化个人云系统的数据。1.3.2研究内容 根据研究的目标,对应的研究包括如下几个方面:研究终端泛型的Terminal的构建方法终端泛型的概念很宽泛,在本文中泛型主要是针对硬件平台,包括x86、arm等硬件架构。目前有很多方式进行跨终端的程序构建,例如Java通过虚拟机和中间字节码的方式打包跨终端的程序,但是前提是需要此终端支持并安装JVM虚拟机,为了尽可能的减少不同终端的差异导致的不必要的兼容问题,本课题将会采用HTML5来作为跨终端的技术手段。主要研究HTML5构建终端泛型Terminal的技术,需要对跨平台的HTML5开发进行深入的了解。最后设计并构建一款可以在不同系统,不同硬件上运行的Terminal程序。可扩展的Hubot命令解析系统的构建方法如何在不影响用户使用的前提情况下,升级命令集是个人云系统的另一个研究内容。本课题采用的方式是将Hubot平台进行分布式的部署,从而在要更新命令集的时候,只需要部分轮流更新节点的命令集即可,这样就可以保证用户在无察觉的情况下更新命令集甚至整个系统,这需要对分布式的架构有深入的了解,还需要对Hubot系统进行深入的研究。研究分布式webapp的构建方法Hubot系统命令解析时,会分发不同的命令到不同的命令执行程序,对于需要大规模计算的程序,构建对应的分布式的webapp,可以分享云计算带来的计算能力以及相应的特性。对此,需要深入了解分布式的webapp的开发方式以及分布式数据库的构建与维护方法。基于云存储的文件系统的构建方法为了利用云存储的大容量等特性,将传统的系统的文件系统移到云端,这需要了解在本课题中使用的通信协议WebSocket,方可将文件系统的命令返回结果通过Hubot传递给Ternimal,在协议的基础上,才能构建基于个人云存储的文件系统。 第五,根据上述的研究成果,并借助现有云产品的结构与经验,设计并构建基于Hubot的个人云系统。1.4论文的组织结构 本课题的主要内容是设计和构建基于Hubot的个人云的原型系统,并通过实验说明该原型系统的结构及功能有效性和具有的特性。本文首先分析了个人云系统的背景与构建个人云系统的意义;其次对构建个人云系统的核心技术进行了较详细的阐述;然后着重介绍了个人云系统的设计思路与构建方式;最后进行了相关的实验分析。 论文的组织结构如下: 第一章绪论 介绍本文的研究背景,阐述了个人云系统的国内外的研究现状,提出了本文的研究目标和主要的工作内容。 第二章相关技术的简介 介绍本文工作涉及的主要相关技术重点分析了全栈式开发的方式,分布式webapp的构建方式等等。 第三章系统的设计与实现 介绍基于Hubot的个人云系统的各个模块的设计思路与实现方案。 第四章实验验证 首先介绍如何配置个人云系统的环境,然后对个人云系统的主要功能模块进行验证,并用实例说明其具有的分布式等特性。 第五章总结与展望 完成整个原型系统的设计与实现后,对开发工作中获取的经验进行总结,并讨论系统存在的问题和下一步的工作展望。2.相关技术简介 在构建基于Hubot的个人云系统的过程中,为了提高开发效率,将会采用全栈式开发的方式进行开发, 其好处在于,只需要一种开发语言即可完成从前端到后台的开发,从而可以使部分的代码在前端与后端进行共用,大大减少了在不同开发环境下切换开发语言造成的成本开销。在模块之间采用WebSocket协议进行通信,该协议是目前在浏览器端进行全双工通信的唯一方式,为了保证系统的实时性,前端Ternimal与Hubot之间采用WebSocket协议通信。另外Hubot的命令执行程序将会采用分布式webapp和分布式数据库的相关技术进行构建。因此在本章主要介绍全栈式开发,分布式webapp,分布式数据库以及WebSocket等相关技术。2.1全栈式开发技术2.1.1简介随着不同终端(pad/mobile/pc)的兴起,对开发人员的要求越来越高,纯浏览器端的响应式已经不能满足用户体验的高要求,往往需要针对不同的终端开发定制的版本。为了提升开发效率,前后端分离的需求越来越被重视,后端负责业务与数据接口,前端负责展现与交互逻辑,同一份数据接口,可以定制开发多个版本。正如当初PHP的LAMP、Spring的SSH等开发堆栈一样,Javascript带来了完整的MEAN开发堆栈,即MongoDB、ExpressJS、AngularJS和Node.js的简称。MongoDB是一个使用JSON风格存储的数据库,非常适合javascript(JSON是JS数据格式),ExpressJS是一个Web应用框架,提供组件和模块帮助建立一个网站应用,AngularJS是一个前端MVC框架,Node.js是一个并发、异步、事件驱动的Javascript服务器后端开发平台。在MongoDB中可以直接存储JSON格式的数据,然后在ExpressJS和NodeJS服务器编写一个基于JSON的查询,并无缝地(无需像其他语言需要在JSON和语言数据模型之间转换)传递JSON到AngularJS前端。同时,数据库调试和管理也变得轻松了许多,存储在数据库中的对象基本上等同于在客户端看到的对象。更妙的是,前端工作人员也能够轻松了解后端代码和数据库查询,使用的是相同的语法和对象,而不必考虑多套语言的最佳实践,降低了入门门槛。 全栈式开发的整体框架如图2.1所示: 图 2.1 全栈式开发的整体框架示意图[6]2.1.2MongoDB简介MongoDB[7]是一个介于关系数据库和非关系数据库之间的产品,它是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似JSON的BSON格式,因此可以存储比较复杂的数据类型。MongoDB最大的特点是支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。它的特点是高性能、易部署、易使用,存储数据非常方便。主要功能特性有:面向集合存储,易存储对象类型的数据。模式自由。支持动态查询。支持完全索引,包含内部对象。支持查询。支持复制和故障恢复。使用高效的二进制数据存储,包括大型对象(如视频等)。自动处理碎片,以支持云计算层次的扩展性支持RUBY,PYTHON,JAVA,C++,PHP等多种语言。文件存储格式为BSON(一种JSON的扩展)可通过网络访问所谓“面向集合”(Collenction-Orented),意思是数据被分组存储在数据集中,被称为一个集合(Collenction)。每个集合在数据库中都有一个唯一的标识名,并且可以包含无限数目的文档。集合的概念类似于关系型数据库(RDBMS)里的表(table),不同的是它不需要定义任何模式(schema)。 模式自由(schema-free),意味着对于存储在MongoDB数据库中的文件,我们不需要知道它的任何结构定义。在需要时完全可以把不同结构的文件存储在同一个数据库里。存储在集合中的文档,被存储为键-值对的形式。键用于唯一标识一个文档,为字符串类型,而值则可以是各种复杂的文件类型。这种存储形式称为BSON(Binary Serialized Document Format)。MongoDB服务端可运行在Linux、Windows或OS X平台,支持32位和64位应用,默认端口为27017。推荐运行在64位平台上运行,因为MongoDB在32位模式运行时支持的最大文件尺寸为2GB。下面是MongoDB[7]的内部实现方式,见图2.2:图 2.2 MongoDB的内部实现方式[8]MongoDB在数据存储时按命名空间进行划分,一个Collection是一个命名空间,一个索引是另一个命名空间,索引的底层实现是BTree,同一个命名空间的数据被分成很多个Extent,Extent之间通过双向链表进行连接。每一个Extent中的数据保存了具体每一行的数据,这些数据也是通过双向链表来连接的。2.1.3Express简介Express 是一个简洁而灵活的 Node.js Web应用框架,提供一系列强大特性用于创建各种Web应用,具有丰富的HTTP工具以及来自Connect框架的中间件可供随取随用,使创建强健、友好的API变得快速又简单,Express不对Node.js已有的特性进行二次抽象,只是在它之上扩展了Web应用所需的功能。Express[9]是基于中间件的形式进行构建的,下面来看一段示例的代码如图2.3:图 2.3 Express实例代码从图2.3中可以看出Epxress的中间件的使用方式,其中bodyParser和methodOverride都是中间件,如需要加载中间件,首先需要require这个中间件,require操作类似java中的import,然后采用app.use()的方式加载即可。 下面来看一个中间件是如何进行初始化的,首先是采用require的方式初始化中间件,然后进入中间件的初始化过程,如图2.4所示。 图 2.4中间件初始化的过程通过上述过程,一个Express的中间件就构建完毕了,而构建整个应用的其他工作就是如何用中间件来实现代码逻辑了。 2.1.4AngularJS简介AngularJS [10]是一个为动态WEB应用设计的结构框架。它用HTML作为模板语言,通过扩展HTML的语法,能使应用组件的构建更加清楚、简洁。它的创新点在于,利用数据绑定和依赖注入,使用户不用再写大量的代码。这些全都是通过浏览器端的Javascript实现的,这也使得它能够完美地和任何服务器端技术结合。AngularJS是为了克服HTML在构建应用上的不足而设计的。HTML是一门很好的为静态文本展示设计的声明式语言,但要构建WEB应用的话它就显得乏力了。通常,我们是通过以下技术来解决静态网页技术在构建动态应用上的不足:类库 - 类库是一些函数的集合,可用于编写WEB应用。由编写的代码起主导作用,由你来决定何时使用类库。类库有:jQuery等框架 - 框架是一种特殊的、已经实现了的WEB应用,你只需要对它填充具体的业务逻辑。这里框架是起主导作用的,由它来根据具体的应用逻辑来调用代码。框架有:knockout、sproutcore等。AngularJS使用了不同的方法,它尝试去补足HTML本身在构建应用方面的缺陷。AngularJS通过使用我们称为指令(directives)的结构,让浏览器能够识别新的语法。例如:使用双大括号{{}}语法进行数据绑定;使用DOM控制结构来实现迭代或者隐藏DOM片段;支持表单和表单的验证;能将逻辑代码关联到相关的DOM元素上;能将HTML分组成可重用的组件。AngularJS试图成为WEB应用中的一种端对端的解决方案。这意味着它不只是WEB应用中的一个小部分,而是一个完整的端对端的解决方案。这会让AngularJS在构建一个CRUD(增加Create、查询Retrieve、更新Update、删除Delete)的应用时显得很轻松。AngularJS的一些出众之处如下:构建一个CRUD应用可能用到的全部内容包括:数据绑定、基本模板标识符、表单验证、路由、深度链接、组件重用、依赖注入。测试方面包括:单元测试、端对端测试、模拟和自动化测试框架。具有目录布局和测试脚本的种子应用作为起点。AngularJS通过为开发者呈现一个更高层次的抽象来简化应用的开发。如同其他的抽象技术一样,这也会损失一部分灵活性。换句话说,并不是所有的应用都适合用AngularJS来做。AngularJS主要考虑的是构建CRUD应用。幸运的是,至少90%的WEB应用都是CRUD应用。在AngularJS中很重要的一个概念就是Scope,可以说AngularJS应用是构建在Scope之上的,那么要想深入的了解Scope,见图2.5: 图 2.5 AngularJS的Scope[11]这是AngularJS的典型的Scope的一个实现,因为Scope是Javascript的对象的一个实现,所以也是基于原型的继承。假设父类 parentScope 有如下成员属性 aString, aNumber, anArray, anObject, 以及aFunction。子类childScope原型继承父类parentScope,如果子Scope尝试去访问parentScope中定义的属性,JavaScript会先在子Scope中查找,如果没有该属性,则到它继承的Scope去获取属性,如果继承的原型对象parentScope中都没有该属性,那么继续在它的原型中寻找,从原型链一直往上直到到达rootScope。2.1.5Nodejs简介Node [12]是一个服务器端 JavaScript 解释器,它将改变服务器应该如何工作的概念。它的目标是帮助程序员构建高度可伸缩的应用程序,编写能够处理数万条同时连接到一个(只有一个)物理机的连接代码。Node公开宣称的目标是“旨在提供一种简单的构建可伸缩网络程序的方法”。当前的服务器程序存在什么问题?在Java™和PHP这类语言中,每个连接都会生成一个新线程,每个新线程可能需要2MB的配套内存。在一个拥有8GBRAM的系统上,理论上最大的并发连接数量是4000个用户。随着客户群的增长,如果希望Web 应用程序支持更多用户,则必须添加更多服务器。当然,这会增加服务器成本、流量成本和人工成本等成本。除这些成本上升外,还有一个潜在技术问题,即用户可能针对每个请求使用不同的服务器,因此,任何共享资源都必须在所有服务器之间共享。鉴于上述所有原因,整个Web应用程序架构(包括流量、处理器速度和内存速度)中的瓶颈是:服务器能够处理的并发连接的最大数量。Node解决这个问题的方法是:更改连接到服务器的方式。每个连接发射一个在 Node引擎的进程中运行的事件,而不是为每个连接生成一个新的OS线程(并为其分配一些配套内存)。Node声称它绝不会死锁,因为它根本不允许使用锁,它不会直接阻塞I/O调用。Node还宣称,运行它的服务器能支持数万个并发连接。图2.6是Node.js的底层架构图:图 2.6 Node.js的底层架构图由于底层V8引擎的优化以及libuv提供的事件驱动能力,让Nodejs有了源源不断的动力。2.1.6全栈式开发的价值现代项目的开发,需要掌握多种技术。互联网项目,需要用到后端开发、前端开发、界面设计、产品设计、数据库、各种移动客户端、三屏兼容、restFul API设计和OAuth等等,比较前卫的项目,还会用到Single Page Application、Web Socket、HTML5/CSS3这些技术以及像第三方开发像微信公众号微博应用等等。Web前端也远远不是从前的切个图用个jQuery上个AJAX兼容各种浏览器那么简单了。现代的Web前端,需要用到模块化开发、多屏兼容、MVC,各种复杂的交互与优化,甚至需要用到Node.js来协助前端的开发。 那么采用全栈式开发就是一个最好的选择,因为全栈式开发可以保证前端到后台都采用同一种语言进行开发,这大大地减少了在不同语言之间切换造成的成本,包括类库的不通用,编程思维的不同,测试框架的不兼容等等。而全栈式开发的好处在于让开发者可以更快捷的开发,从全局的角度设计和构建整个项目,保证前后端代码的通用和可测试,从而提升开发效率与质量,降低开发成本。2.2分布式webapp的简介分布式webapp是分布式系统的一种,通常情况下是由分布式系统和分布式数据库组成的。在一个分布式系统中,一组独立的计算机展现给用户的是一个统一的整体,就好像是一个系统似的。系统拥有多种通用的物理和逻辑资源,可以动态的分配任务,分散的物理和逻辑资源通过计算机网络实现信息交换。系统中存在一个以全局的方式管理计算机资源的分布式操作系统。通常对用户来说,分布式系统只有一个模型或范型。在操作系统之上有一层软件中间件(middleware)负责实现这个模型。一个著名的分布式系统的例子是万维网(World Wide Web),在万维网中,所有的一切看起来就好像是一个文档(Web页面)一样。下面用一个实际的分布式webapp来举例说明分布式webapp的系统架构,在此以pedneedus(微步,脚部测量软件公司)的官方网站举例,pedneedus官网的架构是一个典型的分布式webapp的架构,如图2.7所示:图 2.7 pedneedus官网的逻辑分层首先介绍整个系统的逻辑分层,从逻辑分层的角度而言,整个系统分为四层,最上面一层是控制层也叫路由层,负责将用户的请求进行仲裁,并将仲裁后的请求发送到业务层;业务层属于整个系统的前端部分,在业务层中主要处理的是用户请求的数据的结构以及相应的逻辑实现,当用户需要进行数据持久化或者获取持久化数据的时候,此时需要通过数据库操作层进行数据获取;数据库操作层属于整个系统的后端部分,也称为ORM层,主要的功能是将数据库的Scheme(此处可理解为数据的逻辑结构)映射为程序中的对象或者操作方法;在整个系统的最底端是数据库,其作用是持久化数据以及持久化数据的查询工作。下面来看一下pedneedus官网的结构分层,见图2.8图 2.8 pedneedus官网的结构分层与逻辑分层进行对应,前端集群包括控制层和业务层,服务端集群包括数据库操作层,而Memcache集群比较特殊是一个独立的部分,主要的作用是在弥补集群之间无法共享内存与session的缺陷,通过内存式数据库的方式在多节点之间共享数据。在本文中实现的分布式webapp是一个标准的水平扩展,与上述的pedneedus系统结构类似,和传统的集中式应用的区别在于分布式webapp的架构如图2.9所示: 图 2.9 分布式系统架构[13]任何单一节点的宕机不会影响其他节点,而集中式的架构是垂直分布的,一旦主机宕机,那么结果将是灾难性的。2.3分布式数据库系统简介分布式数据库系统通常使用较小的计算机系统,每台计算机可单独放在一个地方,每台计算机中都有DBMS的一份完整拷贝副本,并具有自己局部的数据库,位于不同地点的许多计算机通过网络互相连接,共同组成一个完整的、全局的大型数据库。这种组织数据库的方法克服了物理中心数据库组织的弱点。首先,降低了数据传送代价,因为大多数的对数据库的访问操作都是针对局部数据库的,而不是对其他位置的数据库访问;其次,系统的可靠性提高了很多,因为当网络出现故障时,仍然允许对局部数据库的操作,而且一个位置的故障不影响其他位置的处理工作,只有当访问出现故障位置的数据时,在某种程度上才受影响;第三,便于系统的扩充,增加一个新的局部数据库,或在某个位置扩充一台适当的小型计算机,都很容易实现。然而有些功能要付出更高的代价。例如,为了调配在几个位置上的活动,事务管理的性能比在中心数据库时花费更高,而且甚至抵消许多其他的优点。分布式数据库系统的优点:1)更适合分布式的管理与控制,分布式数据库系统的结构更适合具有地理分布特性的组织或机构使用,允许分布在不同区域、不同级别的各个部门对其自身的数据实行局部控制。例如:实现全局数据在本地录入、查询、维护,这时由于计算机资源靠近用户,可以降低通信代价,提高响应速度,而涉及其他场地数据库中的数据只是少量的,从而可以大大减少网络上的信息传输量,同时,局部数据的安全性也可以做得更好。2)具有灵活的体系结构。集中式数据库系统强调的是集中式控制,物理数据库是存放在一个场地上的,由一个DBMS集中管理。多个用户只可以通过近程或远程终端在多用户操作系统支持下运行该DBMS来共享集中式是数据库中的数据。而分布式数据库系统的场地局部,DBMS的自治性,使得大部分的局部事务管理和控制都能就地解决,只有在涉及其他场地的数据时才需要通过网络作为全局事务来管理。分布式DBMS可以设计成具有不同程度的自治性,从具有充分的场地自治到几乎是完全集中式的控制。3)系统经济,可靠性高,可用性好。与一个大型计算机支持一个大型的集中式数据库再加一些进程和远程终端相比,由超级微型计算机或超级小型计算机支持的分布式数据库系统往往具有更高的性价比和实施灵活性。分布式系统比集中式系统具有更高的可靠性和更好的可用性。如由于数据分布在多个场地并有许多复制数据,在个别场地或个别通信链路发生故障时,不致于导致整个系统的崩溃,而且系统的局部故障不会引起全局失控。4)在一定条件下响应速度加快。如果存取的数据在本地数据库中,那么就可以由用户所在的计算机来执行,速度就快。5)可扩展性好,易于集成现有系统,也易于扩充。对于一个企业或组织,可以采用分布式数据库技术在已建立的若干数据库的基础上开发全局应用,对原有的局部数据库系统作某些改动,形成一个分布式系统。这比重建一个大型数据库系统要简单,既省时间,又省财力、物力。也可以通过增加场地数的办法,迅速扩充已有的分布式数据库系统。在本文中使用的分布式数据库是基于MongoDB构建的,MongoDB是非关系型数据库,由于MongoDB采用JSON或者BSON的方式进行存储,而不是采用数据表的方式进行数据存储,这样可以大大的减少数据库的冗余。因此,在构建大规模分布式数据库集群的时候,MongoDB的冗余分片会比同样结构的Mysql小很多,另外在MongoDB中cluster(集群)和sharding(分片)配置相较Mysql更为高效和简单。MongoDB在构建集群的方式上支持以下三种,replica set(副本集)、Sharding(分片集),Master-slave(主从复制)。Replica set(副本集)简单来讲就是集群中包含多份的数据冗余,节点包括主节点(M)、备节点(S)以及仲裁节点(A)。结构见图2.10所示图 2.10 MongoDB副本集[14]主节点存储数据,备节点做主节点的全量冗余备份,仲裁节点不存储数据仅作为仲裁备节点的权重使用。客户端同时连接主节点和备节点,不连接仲裁节点。默认情况下主节点提供增删改查服务,备节点不提供任何服务,但是也可以做主备节点的查询分离,即主节点提供写操作(写入、更新、删除),备节点提供读操作(查询)。仲裁节点是一个特殊的节点,它本身不存储数据,其主要作用是决定哪一个备节点在主节点宕机之后提升级别升为主节点。Sharding(分片)和Replica set(复制集)类似都需要一个仲裁节点,但是Sharding还需要配置节点和路由节点,总体的集群结构见图2.11 图 2.11 MongoDB 分片集群[15]在Sharding集群中包含路由节点(mongos)、配置节点(c mongod)、分片节点(shard)。其中路由节点是MongoDB集群的前端路由,客户端由此接入,用户接入Mongos的时候,可以像连接一个数据库节点一样操作整个集群。配置节点存储了整个集群的MetaData,包括部分的Chunk信息,也就是说配置节点负责存储整个集群的全部配置信息,包括每个shard分片的数据起止位置,每个分片的大小等等。分片节点,用于存储实际的数据块,在生产环境中一个shard分片可以由一台机器或者一个replica set担任,这样既可以得到shard集群的优势,又可以得到replica set防止单点故障的优势。2.4全双工数据通信协议WebSocketWebSocket 协议是HTML5的一种新协议。它实现了浏览器与服务器间的全双工通信(full-duplex)。现很多网站为了实现即时通讯(real-time),所用的都是轮询(polling)的方式。即在特定的时间间隔(time interval)(如每1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给客服端的浏览器。这种传统的HTTP request 的模式带来的缺点很明显,浏览器需要不断的向服务器发出请求(request),然而HTTP request 的header是非常长的,里面包含的数据可能只是一个很小的值,这样会占用很多的带宽。目前最长用的轮询方式是采用Comet技术,这种技术虽然可达到全双工通信,但依然需要发出请求(reuqest)。支持WebSocket API的浏览器和服务器只需要一个握手的动作,就形成了一条快速通道,两者之间就可以直接进行数据互相传送。在WebSocket 协议中,为实现即时服务带来了两大好处:首先是公共报头Header,互相沟通的Header是很小的,大概只有 2 Bytes;其次是Server Push(服务器端推送),服务器可以主动传送数据给客户端,因此,可以用WebSocket在客户端和服务器之间建立极低的延迟,近乎即时的连接。下面来看下一个标准的WebSocket请求,浏览器请求如下 GET / HTTP/1.1 Upgrade: WebSocket Connection: Upgrade Host: example.com Origin: null Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ== Sec-WebSocket-Version: 13服务器端返回的数据如下HTTP/1.1 101 Switching Protocols Upgrade: WebSocket Connection: Upgrade Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s= Sec-WebSocket-Origin: null Sec-WebSocket-Location: ws://example.com/ 由上面的两个请求可以看出WebSocket是基于http1.1协议的一种改进,主要的改进位置在于添加了WebSocket字段,并通过WebSocket字段进行连接状态的维持,原本无状态的Http协议通过冗余的报文头进行验证,而WebSocket只需要通过握手操作之后动态生成的唯一的WebSocket字段进行验证即可,从而减小了整个报文的长度。Google Chrome浏览器最先支持WebSocket,随后是Safari,Firefox,此外最新版本的Opera和IE(Opera11,IE10)也支持WebSocket。由于HTML5技术的普及,承载个人云系统的硬件上面搭载的浏览器基本是以webkit内核(即Chrome浏览器的内核)为主,因此可以选用WebSocket协议作为前后端的通信协议 在本文中将会采用socket.io做为使用WebSocket的类库,socket.io是一个为实时应用提供跨平台通信的类库。socket.io让实时应用在每个浏览器和移动设备上成为了一种可能,socket.io的名字来源于它使用了浏览器支持的WebSocket协议,由于并不是所有的浏览器都支持Webscoket,因此socket.io具有一系列的降级功能,在支持WebSocket的浏览器上采用WebSocket,在不支持的浏览器上如下所示,自上到下查找一种支持的技术进行通信WebSocketAdobe Flash SocketAjax Long PollingAjax Mutipart StreamingForever IframeJSONP Polling由于socket.io的降级策略十分强大,所以在本文中将会采用socket.io的方式来使用WebSocket协议。2.5Hubot简介Hubot是github[16]的运维机器人,github用Hubot做自动化运维与发布,Hubot是一个命令解析机器人。在本系统中,将会采用Hubot作为个人云系统的命令解析系统。Hubot命令解析系统是本项目的核心部分。因为Hubot是整个项目的命令解析器,所以,每当调用Hubot指令的时候都会经历整个Hubot的解析过程,下面先介绍Hubot系统的主体结构。 2.5.1 Hubot的实例化流程在调用Hubot模块进行实例化的时候,首先要获取当前Hubot实例所需要的参数和配置,然后先根据提供的参数和配置进行实例化Hubot,当Hubot实例已经创建了之后,此时开始加载监听脚本(命令解析的分发程序),在Hubot中可以自动加载如下四个位置的监听脚本。 1)bin目录中的scripts文件夹中的文件。2)src目录中的scripts文件夹中的文件。3)bin目录下Hubot-scripts.json中定义文件(需通过npm install 才能使用)。 4)bin目录下external-scripts.json中定义的文件。 当监听脚本加载完毕了之后,一个Hubot实例就正式开始运作,在本文中Hubot实例还需启动WebSocket信道进行前后端通信。2.5.2Hubot文件入口Hubot的入口文件,主要暴漏了一个方法以及多个对象,主要的作用是,创建一个Hubot实例,每当一个Hubot实例创建完毕就会加不同位置的监听脚本,这些脚本就是Hubot命令集,所以如果想要自定义命令集,那么最简单的方法就是将自己构建的命令集放置在Hubot文件的对应目录即可。module.exports = { User Brain Robot Adapter Response Listener TextListener TextMessage EnTerminalessage LeaveMessage TopicMessage CatchAllMessage }module.exports.loadBot = (adapterPath, adapterName, enableHttpd, botName) ->new Robot adapterPath, adapterName, enableHttpd, botName 从上面的代码可以看出,一个Hubot实例的创建需要一个用户实例,一个用来数据持久化的Brain实例,message监听实例,以及response应答实例。在下面的段落中会介绍每一个实例的具体作用。2.5.3创建Hubot用户Hubot用户实例的作用在于将每一个由Hubot系统解析的命令与一个用户进行绑定,然后通过brain来进行数据持久化,从而进行用户的数据的持久化。下面是Hubot用户类的构造方法。constructor: (@id, options = {}) -> for k of (options or {}) @[k] = options[k]@['name'] ||= @id建立用户,将options中的属性或者方法加入到user对象中,整个模块的意义在于,Hubot的实例有可能是一个系统的子账户,例如QQ或者Skype,那么需要通过一种方式将整个用户以Hubot所识别的方式进行封装,从而可以在每次返回Hubot执行结果的时候维持当前的用户状态信息,此方法返回一个user对象的实例。2.5.4Hubot brain数据持久化Hubot brain实例类似一个虚拟数据库,它是存储在内存之中的,主要的作用是对数据进行存储以及获取,每一次的查询可以通过brain进行记录,所以可以通过整个方法将每次用户的调用进行记录。constructor: (robot) -> @data = users: { } _private: { } @autoSave = true robot.on "running", => @resetSaveInterval 5 由上面的代码可知robot也是Event Emitter的实例(可以集成事件的分发机制,即事件监听模式),当robot收到running事件的时候进行自动存储,存储的数据在this.data之中,主要是users和_private对象中 ,所以比较每次存储的数据就是哪一个用户调用了什么指令。每当用户下次要执行的时候会自动提示上次用户执行了什么指令。 set: (key, value) -> if key is Object(key) pair = key else pair = {} pair[key] = value extend @data._private, pair @emit 'loaded', @data @设置key,value作为存储,如果只设置key的时候则必须为对象,然后将对象的属性赋到data.private的属性上当设置完毕之后,发出loaded事件,并将data作为数据进行发送,此时事件才会被Hubot的解析脚本执行,也就是说无论输入的命令是否正确,Hubot都会进行记忆,然后才去调用脚本解析。2.5.5Hubot message 监听类Hubot message监听类分为两种listener,一种是Listener,另一种是Text Listener,Listener应用场景更广泛,相较Text Listener,Listener适应不只是正则表达式的场景,比如有的时候我们的命令不能简单的用文本匹配,比如一段语音,那么此时采用listener就比较合适了。Text Listener的应用场景是匹配正则表达式的情况,继承自Listener只能匹配正则表达式,在命令匹配中用的比较多。2.5.6Hubot response 应答类 每个Hubot命令都需要一种方式进行既定的监听,而response应答实例的作用就是在Hubot系统中定义应答方式的实例。下面是response类的构造方法。 constructor: (@robot, @message, @match) -> @envelope = room: @message.room user: @message.user message: @messageResponse类提供send、emote、reply、topic、play、locked、radom、finish、http方法,分别是不同的消息的应答方式。常用的是send 、reply,每一个response对应一条Hubot的指令。3.系统的设计与实现3.1整体设计 如图3.1所示,基于Hubot的个人云原型系统从物理结构(部署)上分为前端集群和后端集群两个部分。图 3.1 Hubot的个人云系统系统前端集群分为两个部分,一个是终端泛型的Terminal,另一个是Hubot命令解析系统;系统后端集群分为两个部分,一个是命令执行程序,分布式webapp,另一个是基于个人云存储的文件系统。原型系统主要是由这四个部分组成的。1)通过用户交互获取命令的终端泛型的Terminal,是个人云系统的最顶层,主要的作用在于获取用户的命令,并将命令传递给Hubot系统;另外还具有将命令结果进行展现的功能。2)进行命令解析并进行派发的Hubot系统,是个人云系统的大脑,是整个系统的纽带,它负责将Terminal传递回来的命令进行解析,并根据解析的结果进行派发,派发给不同的命令执行程序(分布式webapp是其中的一种),当命令执行结果返回后,需要将结果交给Terminal。3)命令的载体,分布式的webapp,是命令执行程序的一种,负责接收Hubot的指令,并利用云计算提供的计算能力以及高容错性等特性,返回可预测的数据。4)以个人云存储为基础的文件系统,是个人云系统的文件存储模块,主要为个人云系统提供了文件操作能力。3.2终端泛型的Terminal的设计 终端泛型在本文中主要指的是在不同的系统以及硬件体系上能够保证系统基本的一致。由于不同的硬件差异性较大,不论是采用类似Java的中间代码结合虚拟机的形式或是采用Erlang等解释型语言结合解释器的方式,都无法避免需要在原有的系统上配置环境,而这种方式也难以避免不同体系下的兼容性问题。针对终端泛型这个问题,最好的办法就是采用HTML5技术,将Terminal采用Webshell的方式进行构建,不同的硬件体系都提供浏览器,就嵌入式系统而言,浏览器的内核大多以webkit为主(chrome浏览器的内核,HTML5支持很好),非嵌入式的系统中大部分的浏览器也都支持HTML5技术,所以Terminal将采用Webshell的方式进行构建,下面进行阐述Webshell的总体设计。3.2.1 Webshell的指令在Webshell中可以运行的命令大体可以分为三种1.Webshell指令,无需向后端进行传输即可获得的命令,具体的的列表如下:theme:获取当前的Webshell的theme,version:获取当前Webshell的版本。 2.Hubot指令,Hubot指令都是以Hubot开头的,这类的命令需要请求Hubot命令集接口,然后通过WebSocket协议,然后将结果返回回来。 3.文件系统指令,关于文件系统的指令。3.2.2Webshell的逻辑结构 Webshell主要采用AngularJS作为前端框架,采用socket.io作为WebSocket的通信的类库。图3.2是Webshell的基本结构图 3.2webshell的基本结构用户输入一个命令之后,Webshell会进行初步的解析判断,判断命令的类型,并对不同的命令进行标记,组成一个命令对象,并将命令对象交给命令分发器,命令分发器会根据命令的类型进行分发。如果是Hubot命令,那么会将命令分发给Hubot系统,由Hubot系统负责命令的解析以及运行。如果是文件系统命令,那么会将命令分发给文件系统的api,由文件系统直接返回结果。如果是Webshell命令,那么分发器直接会将命令派发到Webshell的命令执行程序,并返回结果。3.2.3Webshell的程序结构Webshell采用AngularJS作为框架进行构建,AngularJS是MVVM架构的Javascript框架,MVVM代表的含义是model-view-view-model,AngularJS提供了从模型到视图的数据双向绑定。即模型的改变,会导致与之绑定的视图更新;同理,视图的改变也会导致与之绑定的模型的更新。对于Webshell的设计而言,显示在页面上面的每条命令与结果都映射到了Model中的一条数据。下面见图3.3了解具体的指令的执行过程。图 3.3 Angularjs MVVM的过程 当用户输入命令的时候,Webshell的视图发生了改变,与之绑定的Model此时监听到了视图的变化,Model调用命令对象的构造方法,构建命令对象并将此命令对象推入命令对象数组的队列队尾,然后在调用相应的命令分发器进行命令的分发;当命令结果返回的时候,由Formattor(格式数据的helper方法)创建命令对象,并将命令对象推入命令对象数组的队列队尾,此时Model改变,与之对应的视图(view)立即发生改变,此时Webshell中就显示了一条新的命令返回的结果。当然,在Webshell中有Model-View之间的双向绑定关系,有的时候还是需要手动的调用API,去实现部分的功能。在Webshell中暴露了5个开放方法用于手动实现部分功能。主要有setTheme:设置当前的Webshell的样式,getTheme:获取当前Webshell的样式,setPrompt:设置当前的命令行的prompt,getPrompt:获取当前的命令行的prompt,clear:清理整个缓冲区,output:向缓冲区输入结果。Webshell的命令分发系统采用socket.io作为使用Webscoket协议的类库。socket.io分为客户端和服务器端。在webshell中使用的是socket.io的客户端程序,主要负责与socket.io服务器程序进行通信,并将返回的结果交给formatter。关于socket.io的部分将在Hubot章节进行系统说明3.3Hubot系统设计3.3.1Hubot命令解析部分Hubot系统是本项目的核心部分。因为Hubot是整个系统的命令解析器,也是前后端通信的中转站。下面先来了解一下Hubot系统的初始化过程,如图3.4所示。图 3.4 Hubot的实例化过程 当调用Hubot模块的时候,会实例化一个Hubot实例, 当此Hubot实例生成后,会先载入adapter(适配器,hubot的api可以通过多种方式进行调用,每一种方式对应一个适配器),载入成功后会发出connected事件,此时script文件开始载入,adapter中的handler开始实例化,当handler实例化完毕后发出completed事件,此时adapter开始载入的script文件,载入完毕后一个Hubot实例就开始进行事件监听,加入Hubot命令系统。 在此处需要重点关注的地方是script文件,script文件的主要作用是作为命令解析系统的脚本。那么我们只需要构建相关的脚本即可。具体的脚本代码如图3.5所示:图 3.5 Hubot script 示例module.exports中的函数为暴露在外边的方法,上面的robot.respond中的正则表达式是匹配的命令格式,而getAdvice是处理命令的函数。当一个命令由Hubot进行分发解析之后,会由robot.response进行处理,然后调用相应的处理函数,最后返回结果,这样一条命令就算解析完毕了。3.3.2Hubot与其他模块通信Hubot与Webshell模块之间是采用socket.io的方式进行通信的,Hubot系统中的部分为socket.io服务器,而Webshell模块中的为socket.io客户端。采用的是事件驱动模型,见图3.6所示图 3.6 Hubot 通信的事件驱动模型在Hubot系统中设定监听webshell中分发命令的cmd事件,在webshell中监听命令返回结果的resopnseMessage事件,当用户输入数据的时候前端派发cmd事件,当命令执行完毕后Hubot派发表示命令返回结果的responseMessag的事件。这样的好处在于webshell和Hubot之间进行了解耦,webshell无需了解Hubot的接口,而Hubot也无需了解webshell的实现,它们之间只需要通过特定的事件进行沟通即可。这就是Hubot与Webshell之间的事件驱动模型。3.4分布式webapp设计Hubot命令的设计方式有很多中,在个人云系统中Hubot命令可以是分布式的webapp,由于分布式webapp利用了云计算的高效计算能力,所以采用分布式webapp构建命令可以给个人云系统添加很多传统操作系统难以完成的任务,例如需要大规模运算的程序。因此在本系统中构建了一条基于分布式webapp的Hubot命令,这个webapp是一个计算密集型的程序,主要是通过上传两张脚部(正面和侧面)的照片,然后通过分布式集群计算出这只脚的长和宽。图3.7是该webapp的程序架构图:图 3.7 webapp框架3.4.1路由层nginx仲裁从图3.7可以看出,首先请求到来的时候,会先由nginx进行转发,nginx会根据请求来分发到不同的节点,不同的节点的权重不同,所以不同的节点接受到请求的次数也是不同的,权重越高的节点接收请求的次数越多,下面我以3台服务器为例,说明仲裁过程,假设有A、B和C三台机器,其配置为:A,B:CPU: 1核 内存:512MB 数据盘:0G 带宽:1MbpsC:CPU:2核 内存: 2G 数据盘:80G 带宽:5Mbps由于C的内存配置相对较高,那么就现在而言可以选择集群中C为nginx仲裁节点,由C这台服务器接收所有的请求然后进行分发。根据配置的不同可以设置当前三台机器的仲裁权重是C为2,A和B的权重为1,也就是说在4个请求中由2个会被分发到C,而剩余的两个会分别分发到A和B。当每台服务器接收到请求后就行开始运行计算程序。3.4.2计算节点的结构每个计算节点主要分为两个部分,Node服务和图像处理外部程序。整体的程序结构如图3.8所示:图 3.8 webapp的结构 当命令分发到webapp的时候,首先图片处理程序会先区分两张照片中哪一张是正面照,哪一张是侧面照,然后各自调用不同的图像处理外部程序,将程序得到的结果进行封装,并将数据进行返回。再由上层的程序进行处理,先将数据通过事件派发的方式传递给Hubot,再用异步的方式将数据存入分布式数据库。3.4.3存储节点的结构当数据计算完毕之后就涉及到了数据的存储部分,系统采用MongoDB作为分布式数据库,数据库的架构如图3.9所示:图 3.9 MongoDB集群架构MongoDB集群包括一定数量的mongod(shard分片存储数据)、mongos(路由处理)、config server(配置节点)、clients(客户端)。可以这样理解mongos, shards, config三样东西:1. shards是一些实际存数据的可以单独使用的数据库,他们能分配给任何config server,而且添加删除都很方便。2. 每个shard里有若干个地位平等的mongod,所以每个是一个Replica Set(副本集)3. 一个config节点下带领好几个shard,目的是负载和扩容,他们之间需要mongos来路由4. mongos是一个路由,可以路由一个或多个config servers,不需要很大的分配空间5. 每一个客户端的应用,每一张数据库表,最好对应一个config server和一个mongos如上面的结构所示,如果采用完全物理的形式,那么会有大量的资源浪费,因为只有shard节点是存储用户的数据的,而config节点与route节点并不存储实际的数据。所以将配置节点、路由节点以及分片节点都配置在一台机器上,那么就可以在三台机器上实现一个小型的MongoDB水平分片集群了,具体的配置方法请见实验环境配置章节。3.5底层文件系统底层的文件系统是基于网盘系统进行构建的,主要支持以下的命令:表3.1 文件系统支持的命令集 命令解释调用方式帮助命令获取当前可执行的命令help列表命令获取当前文件夹内容的列表ls移动命令移动文件或文件夹mv 文件标识符删除命令删除文件或文件夹rm 文件标识符下载命令下载一个文件到网盘wget url分享命令获取文件的下载链接get 文件标识符任务命令获取当前还在进行的任务jobs重命名命令重命名文件或文件夹rename 文件标识符状态命令获取当前文件的状态信息status 文件标识符权限查看查看当前的文件的权限watch 文件标识符3.5.1文件系统的架构部分个人云系统的原型系统的文件系统是基于百度个人云存储PCS的,如图3.10所示,就是文件系统的总体的运行结构。图 3.10 文件系统的工作流程当用户在Webshell中输入mount挂载命令的时候,需要输入用户名和密码,然后文件系统接受到当前用户的用户名和密码之后,采用登录页模拟、token获取等方式获取登录成功的cookie。此时文件系统的命令解析程序准备完毕,当用户在Webshell中输入文件系统的操作的时候,文件系统解析器会判断当前的命令是否为有效的命令,当命令为有效命令的时候,则调用底层的接口请求PCS接口,若指令命令不是有效命令则交由异常处理程序处理。构建文件系统的时候未采用Oauth2.0的方式,而是采用模拟登录的方式的原因在于,Oauth2.0的方式只能获得部分的权限,但是无法获得全部文件夹的权限,所以,为了保证网盘文件夹中的所有的文件都有权限进行修改,那么我们将会采用模拟登录的方式,而不是采用传统的Oauth2.0的方式进行登录。在下一个小结将会讲述如何利用模拟登录的方式构建网盘的api。3.5.2百度网盘的模拟登录由于网盘系统采用的是百度网盘,但是百度网盘提供的Oauth2.0的接入方式不能完全满足需求,所以本项目将会采用模拟登录的方式进行操作。模拟登录的方式有很多种,主要取决于需要验证身份的系统的复杂性,对于百度网盘系统来讲,验证过程较为复杂。验证过程分为以下几个步骤。1.首先要先通过login页,获取用户的用户名和用户的密码,然后将数据提交给后端做校验,如果校验通过,说明用户正确,如果校验失败,说明用户的密码或者用户名称有误。2.当完成login,会生成token,token的作用是唯一的身份标识,而token和用户名密码的方式的区别在于token具有时效性,唯一性。token的生成取决于加密的算法以及时效,token的时效通常都很短,对于网站来讲,每当session失效,token通常情况下需要重新生成。但是这并不代表我们每隔一段时间就必须要登录,因为token生成的cookie会随着每次的请求保留下来, 通常cookie的失效时间都比较长,这就可以解释为什么很多网站登录一次之后就不用每隔一段时间就登录了。3.当token获取完毕,会将获取到的token传递给后端,后端会在http的报文头中设置cookie,而这段cookie就是唯一的验证ID,可以持久存在。4.大型的网站为了方式DDOS或者僵尸注册的攻击,通常情况下会采用不同的方式进行阻止,常用的方式由手机验证码,图片验证码的方式,但是并不是每次登录都需要验证码,所以,后台的系统会判定单位时间内的登录次数是否会造成攻击,如果被认为是攻击,那么会进行登录限制,也就是用图片或这手机验证码的方式进行确认,如果验证码失败,则不能进行登录。5.当登录成功之后,此时只需请求接口即可,因为请求接口的请求报文头部包含了特定用户的cookie,所以,通过这种方式就可以获得当前用户的信息,从而判断用户的请求是否能够有足够的权限进行操作。3.5.3文件系统底层api设计 文件系统的底层api是由python编写的,这一部分是调用百度PCS(个人云存储)api的部分,具体的结构如图3.11所示图 3.11文件系统底层api结构当用户挂载文件系统的时候,首先进行登录验证,当验证成功后,此时Webshell中输入的命令将会交由文件系统的命令解析器进行解析,文件系统的每条命令都需要请求百度PCS api,当PCS接口返回数据后,将结果交由上层控制程序处理。上层的处理程序会把结果通过socket.io派发事件的方式传递给Webshell。 4.实验验证为了验证基于Hubot的个人云系统的功能与特性,实验将从这两个方向进行验证,分为功能验证和特性验证,功能验证主要将个人云原型系统实现的功能做一个基本的展示和验证;特性验证主要通过实例与数据的方式说明个人云系统的特性。4.1环境配置首先需要至少三台服务器作为集群的配置,因为做分布式数据库水平分片的集群的时候至少需要三台服务器才能进行搭建,本文的实现采用了三台阿里云ECS服务器,每台配置如下:CPU:1核 内存:512MB 数据盘:0G 带宽:1Mbps每台服务器都需要配置Node.js环境、MongoDB数据库等环境,具体的配置方式将在接下来的章节中详述。4.1.1配置Node.js1.首先先下载nvm(nvm是nodejs的一个版本管理安装器)2.安装完nvm之后,运行命令nvm install 0.10.243.此时打开命令行,输入nvm use 0.10.24,然后输入node –v图 4.1 验证结果4. 当命令行中出现如图4.1所示的v0.10.24的时候表示Node.js v0.10.24 已经安装完毕。4.1.2配置MongoDB1.从官网获取MongoDB的最新版本,下载并解压缩2.按照官网的制定方式进行安装3.在Terminal中运行mongod图 4.2 MongoDB配置结果4.当命令行出现如图4.2所示的MongoDB starting并且无报错信息的时候,即说明MongoDB已经安装完毕。 4.1.3从Github下载最新版本的项目代码 本课题采用github作为代码托管平台,所以,每次部署代码需要从github拉取最新的代码,在拉取最新的代码之后,需要安装相关的依赖。在命令行中运行命令npm install图 4.3 npm 安装过程当程序运行过程中出现如图4.3中的npm http GET的情况说明程序还在安装过程中图 4.4 npm 安装依赖完毕。当命令行的提示符重新出现,并且此时Terminal如图4.4所示无报错信息,那么代码的依赖就已经安装完毕了。4.1.4配置webapp1.配置nginx首先从官网下载最新的nginx,配置nginx,然后做负载均衡的配置,打开nginx.conf,基本的配置信息如图4.5所示。图 4.5 nginx conf文件配置将api.pedneedus.com映射到当前服务器的80端口,进行转发,负载均衡的ip为10.144.141.65:3000的服务以及10.144.161.172:3000的服务。由于10.144.141.65的服务器的配置比较好,所以在ip后面添加了weight字段,weight字段越高表示请求被分发到这个ip的可能性越大,可以通过这种方式获取更好的性能。2.配置PM2常用的node 管理工具例如supervisor缺少很多的功能,例如:有限的监控和日志功能;进程管理配置的支持差;不支持集群;代码库老化(意味着在升级Node.js时频繁的失败)。所以,我们需要配置pm2来做Node.js的服务管理,可以通过npm 安装pm2,具体的命令如下:npm install pm23.下载webapp的代码webapp的代码托管在github之上,首先下载代码,然后通过pm2 启动应用,当在Terminal中输入pm2 list得出如图4.6和4.7中的图片所示,status字段都为online的时候即可证明webapp已经运行起来了。图 4.6 pm2结果1图 4.7 pm2结果24.1.5配置分布式MongoDB MongoDB是时下流行的NoSql数据库,它的存储方式是文档式存储,并不是Key-Value形式。集群由三台服务器(假定ip地址为:serverA,serverB,serverC)组成,采用MongoDB的副本集+分片(Replica Sets+Sharding) 实现集群的高可靠/高可用以及数据读写的负载均衡。 三台机器分成两个副本集,两个副本集组成一个集群的两个分片(shard1和shard2)。具体如下: 1、ServerA的s1-1 / ServerB的s1-2 / ServerC的s1-3 组成一个3节点的副本集s1 2、ServerA的s2-1 / ServerB的s2-2 / ServerC的s2-3 组成一个3节点的副本集s2 3、副本集s1和s2 组成有两个片的分片集群 4、为确保配置信息高可用,集群采用3个配置节点存储集群配置信息: ServerA的c1 / ServerB的c2 / ServerC的c3 5、为对外服务提供高可用,集群采用3个路由节点对外提供服务:ServerA的mongos 1 / ServerB的mongos 2/ ServerC的mongos 3,也可以结合keepalive对外提供一个vip,本系统中的MongoDB集群逻辑结构如图4.8所示:图 4.8 MongoDB集群结构详细配置步骤如下:1、配置shard1用到副本集 s1:在serverA上:mongod --replSet s1 --port 27020 --dbpath=/data/mongo/s1_1/db --logpath=/data/mongo/s1_1/log/mongo.log --logappend –fork在serverB上:mongod --replSet s1 --port 27020 --dbpath=/data/mongo/s1_2/db --logpath=/data/mongo/s1_2/log/mongo.log --logappend --fork在serverC上:mongod --replSet s1 --port 27020 --dbpath=/data/mongo/s1_3/db --logpath=/data/mongo/s1_3/log/mongo.log --logappend --fork连接三个节点的任一个初始化副本集s1>use admin>config = {_id:'s1',members:[{_id:0,host:'serverA:27020',priority:1},{_id:1,host:'serverB:27020'},{_id:2,host:'serverC:27020'}]}>rs.initiate(config)>rs.status() 另外对副本集s1的所有节点都执行如下命令确保所有节点都能分担读取的压力>db.getMongo().setSlaveOk();2、配置shard2用到副本集 s2:在serverA上:mongod --replSet s2 --port 27021 --dbpath=/data/mongo/s2_1/db --logpath=/data/mongo/s2_1/log/mongo.log --logappend –fork在serverB上:mongod --replSet s2 --port 27021 --dbpath=/data/mongo/s2_2/db --logpath=/data/mongo/s2_2/log/mongo.log --logappend –fork在serverC上:mongod --replSet s2 --port 27021 --dbpath=/data/mongo/s2_3/db --logpath=/data/mongo/s2_3/log/mongo.log --logappend --fork 连接三个节点的任一个初始化副本集s2 >use admin>config = { _id:'s2',members:[{_id:0,host:'serverA:27021'},{_id:1,host:'serverB:27021',priority:1},{_id:2,host:'serverC:27021'}]}>rs.initiate(config)>rs.status()另外对副本集s2的所有节点都执行如下命令确保所有节点都能分担读取的压力>db.getMongo().setSlaveOk();3、配置三台Config Server:在serverA、serverB、serverC分别运行如下代码:mongod -fork --configsvr --dbpath /data/mongo/config/db --port 27018 --logpath /data/mongo/config/log/mongo.log –fork4、配置三台Route Server:在serverA、serverB、serverC分别运行如下代码:mongos -fork --logpath /data/mongo/route/log/mongo.log --configdb ServerA:27018,ServerB:27018,ServerC:27018 --port 270175、配置Shard Cluster:连接任一mongos进程执行以下命令:use admindb.runCommand({addShard:"shard1/serverA:27020,serverB:27020,serverC:27020"})db.runCommand({addShard:"shard2/serverA:27021,serverB:27021,serverC:27021"})db.printShardingStatus()6、激活数据库及集合的分片功能:连接任一mongos进程执行以下命令:db.runCommand({enablesharding:"testdb"}) db.runCommand({shardcollection:"testdb.collection_test",key:{_id:1}})7、登录mongos添加用户:use admindb.addUser("","")db.addUser("","",true) //添加只读用户8、关闭三台机器的全部mongod,mongos:sudo killall mongodsudo killall mongos9、生成keyfile:(每个进程的key file都保持一致)openssl rand -base64 753 >keyfile将生成的keyfile 拷贝到mongod/mongos 进程对应的文件夹并执行语句更改权限:sudo chmod 600 keyfile使用--keyFile参数指定前面生成的keyfile文件,重启三台机器全部mongod,mongos进程。在serverA上:mongod --replSet s1 --port 27020 --dbpath=/data/mongo/s1_1/db --logpath=/data/mongo/s1_1/log/mongo.log --logappend --fork --keyFile /data/mongo/s1_1/keyfile在serverB上:mongod --replSet s1 --port 27020 --dbpath=/data/mongo/s1_2/db --logpath=/data/mongo/s1_2/log/mongo.log --logappend --fork --keyFile /data/mongo/s1_2/keyfile在serverC上:mongod --replSet s1 --port 27020 --dbpath=/data/mongo/s1_3/db --logpath=/data/mongo/s1_3/log/mongo.log --logappend --fork --keyFile /data/mongo/s1_3/keyfile在serverA上:mongod --replSet s2 --port 27021 --dbpath=/data/mongo/s2_1/db --logpath=/data/mongo/s2_1/log/mongo.log --logappend --fork --keyFile /data/mongo/s2_1/keyfile在serverB上:mongod --replSet s2 --port 27021 --dbpath=/data/mongo/s2_2/db --logpath=/data/mongo/s2_2/log/mongo.log --logappend --fork --keyFile /data/mongo/s2_2/keyfile在serverC上:mongod --replSet s2 --port 27021 --dbpath=/data/mongo/s2_3/db --logpath=/data/mongo/s2_3/log/mongo.log --logappend --fork --keyFile /data/mongo/s2_3/keyfile 在serverA、serverB、serverC分别运行如下代码:mongod -fork --configsvr --dbpath /data/mongo/config/db --port 27018 --logpath /data/mongo/config/log/mongo.log --fork --keyFile /data/mongo/config/keyfile在serverA、serverB、serverC分别运行如下代码:mongos -fork --logpath /data/mongo/route/log/mongo.log --configdb ServerA:27018,ServerB:27018,ServerC:27018 --port 27017 --keyFile /data/mongo/route/keyfile通过上述的命令,当在命令行中三台机器全部出现starting的时候,怎表示构建的MongoDB集群配置成功。4.2功能验证4.2.1文件系统模块验证 文件系统测试可以通过模块的方式进行测试,网盘模块可以通过命令行的方式进行测试。下面开始测试:先如图4.9所示输入用户名和密码进行登录操作。图 4.9运行PCS模块通过help命令,可以查看支持的命令列表,并进行验证。图 4.10 运行help命令在命令行中输入help,此时可以得出图4.10中的可运行的命令列表。下面依次验证不同的命令:1.ls命令-获取当前的网盘的文件列表图 4.11网盘的文件列表在Terminal中运行ls命令,获得当前的文件列表图 4.12 ls命令的结果当出现如图4.12中的文件列表的情况的时候,此时对比图片4.11中的文件列表,发现文件一致,说明ls命令执行成功。2.rm 命令-删除网盘中的一个文件或文件夹先在Terminal中输入rm 品德.md图 4.13 rm命令的结果此时命令行中出现如图4.13所示的True,再运行ls命令图 4.14 再次查看文件列表结果发现如图4.14所示此时文件列表中已经没有品德.md文件了,此时再去检查网盘,确认是否真的删除成功。此时发现如图4.15中文件中没有品德.md文件,说明rm命令执行成功。图 4.15 查看网盘的列表3.验证mv操作-移动文件到另一个目录首先在Terminal中输入mv jing.fm.dmg code图 4.16 运行MV命令如图4.16所示,Terminal中显示true表示成功,此时到code目录之下进行检查图 4.17 运行ls命令查看文件系统在Terminal中输入ls命令查看当前文件的列表,如图4.17所示发现jing.fm.dmg已经出现在Code文件夹中,即可证明mv命令执行成功。4.验证pwd命令在Terminal中运行pwd,可以获取当前的路径图 4.18 验证pwd命令如图4.18所示,命令行提示此时在/code路径之下,此时在网盘中查看当前目录进行验证,此时出现的路径为/code,说明pwd命令执行成功。5.验证mkdir命令在Terminal中输入mkdir test(test为文件标识符)图 4.19 验证mkdir命令此时如图4.19Terminal返回结果save ok,此时查看code目录,发现存在test目录即可证明mkdir命令执行成功。6.验证rename 命令在Terminal中运行rename 文件夹1 文件夹2图 4.20 验证rename 命令此时如图4.20,Terminal返回True,当再次查看当前路径下的文件名称时发现test被重命名为test2,则rename命令执行成功。4.2.2webapp的验证验证webapp的最好方法就是通过服务器端进行直接验证,因为可以直接对接口进行测试从而减少了其他因素的干扰,首先通过如图4.21的一个测试页面进行测试。图 4.21 进入测试网页页面根据选项输入数据,点击提交,测试得到后台计算得到的数据{"code": "200","message": "ok","data": {"rightFootLength": "238.494186","rightFootWidth": "122.401779","rightFootTippedWidth": "125.594109","addon": [{"title": "侧面高度10%处","key": "rightSidePercentage0.1","value": "-0.960591"},{"title": "侧面高度20%处","key": "rightSidePercentage0.2","value": "-0.940887"},{"title": "侧面高度30%处","key": "rightSidePercentage0.3","value": "-0.921182"},{"title": "侧面高度40%处","key": "rightSidePercentage0.4","value": "-0.891626"},{"title": "侧面高度50%处","key": "rightSidePercentage0.5","value": "-0.778325"},{"title": "侧面高度60%处","key": "rightSidePercentage0.6","value": "-0.778325"}]},"netInterface": {"lo": [{"address": "127.0.0.1","netmask": "255.0.0.0","family": "IPv4","mac": "00:00:00:00:00:00","internal": true}],"eth0": [{"address": "10.144.141.65","netmask": "255.255.240.0","family": "IPv4","mac": "00:16:3e:00:1a:cf","internal": false}],"eth1": [{"address": "115.28.145.181","netmask": "255.255.252.0","family": "IPv4","mac": "00:16:3e:00:1b:0a","internal": false}]}}为了证明webapp的负责均衡,多做几次测试之后,我们可以来查看一下文件上传的图片数目,如图4.22中的每条字段都是一张图片:图 4.22 低权重的服务器文件数目上面是权重为1的节点,下面再来看一下权重为2的节点如图4.23所示图 4.23 高权重的文件数目由此可以看出的不同权重对不同的节点,可以接收的请求数目不同。从而可以证明分布式可以更高效的利用硬件资源,对于低运算能力的节点分配更少的任务,而高运算的节点会分配更多的任务。4.2.3Hubot与Webshell测试 首先在服务器上面启动系统前端集群的Webshell,可以通过在Terminal中运行 coffee bin/Hubot.coffee启动,当Terminal中出现如图4.24所示的socket.io started,则表示此时Hubot命令解析系统已经启动完毕。图 4.24 启动Hubot系统可以访问本地地址进行测试,在浏览器的地址栏中输入http://localhost:3000, 就进入了Webshell,此时Webshell的页面如图4.25所示,在顶部有一行欢迎的标语。图 4.25 启动后的页面下面来测试一下基本的几条Hubot命令获取服务器时间Hubot time 得到的结果如下图 4.26 运行Hubot time 命令当如图4.26所示服务器返回UTC时间戳的时候,则Hubot time命令执行成功。获取当前Terminal的版本图 4.27 运行Hubot version 命令当Webshell如图4.27所示出现1.0.0的版本号时,则说明Hubot version命令运行结果正常。翻译命令翻译命令可以将任何的语言翻译为任意的语言(默认翻译为英语)。例如如下,我们翻译‘我爱北京天安门’到英文。图 4.28 Hubot translate 命令 当webshell如图4.28所示出现I Love Beijing’s Tiananmen Square的时候则可以说明翻译命令执行成功。清理缓冲区和获取上一条命令每当你输入一条命令之后,可以通过向上箭头的方式,得到上一条命令,然后输入clear命令,缓冲区即可清空。图 4.29 Hubot clear 命令 当输入clear命令后,Webshell出现如图4.29的时候,则说明clear命令运行成功。获取一些建议在命令行中输入hubot how do you handle 毕业设计后图 4.30 Hubot advise 命令hubot会请求接口返回一段应答如图4.30中所示,当然这个并不具有指导意义,当出现一段英文的时候即可说明advise命令成功。4.3特性验证 与传统的集中式架构相比,分布式架构的最大好处在于分布式架构具有一致性和高容错性。而分布式数据库和传统的数据库相比具有可恢复性,基于Hubot构建的命令解析系统具有可扩展性,下面进行以上的特性的验证。4.3.1验证一致性 首先通过用作测试网页连续操作调用webapp多次,其中两次的结果(每次结果基本一直,出于篇幅此处摘取其中两条)如下:图 4.31 请求1的结果第二次的结果如下图 4.32 请求2的结果此时对比图4.30与图4.30中的字段可以发现,与脚部程序相关的数据都保存在data字段之中,而多次请求的结果基本一致(由于算法中有随机因素干扰,不能完全保证每次结果一模一样,但是可以保证结果是可预测的),因此一致性得以验证。4.3.2验证高容错性在上文中,已经可以通过ip结尾为181的节点得到结果,但是如果此时停止ip结尾为181的节点,那么此时节点中只剩下ip结尾为119的节点。下面来看下此时请求返回的内容。{"code": "200","message": "ok","data": {"rightFootLength": "238.494186","rightFootWidth": "122.401779","rightFootTippedWidth": "125.594109","addon": [{"title": "侧面高度10%处","key": "rightSidePercentage0.1","value": "-0.960591"},{"title": "侧面高度20%处","key": "rightSidePercentage0.2","value": "-0.940887"},{"title": "侧面高度30%处","key": "rightSidePercentage0.3","value": "-0.921182"},{"title": "侧面高度40%处","key": "rightSidePercentage0.4","value": "-0.891626"},{"title": "侧面高度50%处","key": "rightSidePercentage0.5","value": "-0.778325"},{"title": "侧面高度60%处","key": "rightSidePercentage0.6","value": "-0.778325"}]},"netInterface": {"lo": [{"address": "127.0.0.1","netmask": "255.0.0.0","family": "IPv4","mac": "00:00:00:00:00:00","internal": true}],"eth0": [{"address": "10.144.161.172","netmask": "255.255.240.0","family": "IPv4","mac": "00:16:3e:02:02:ad","internal": false}],"eth1": [{"address": "115.28.164.119","netmask": "255.255.252.0","family": "IPv4","mac": "00:16:3e:02:02:ae","internal": false}]}}由上图可以看出此时所有的请求都自动发向ip结尾为119的节点,也就是说在集群中任意一个节点都可以随时地加入集群,也可以随时离开集群,并且对于用户来讲,这一切都是透明的。从而提高了集群的可维护性。4.3.3验证可恢复性在MongoDB中的集群分片已经搭建完毕,先查看一下数据库中的数据。图 4.33 MongoDB的一个分片的数据如图4.33所示发现当前分片中有5条数据,然后手动关闭此分片。图 4.34 MongoDB 已经宕机的分片如图4.34所示,此MongoDB已经连接失败,说明已经宕机,在加入集群之前首先清空此分片的数据,然后将此分片再加入集群查看此时分片中的数据。图 4.35 MongoDB的恢复数据的分片发现此时数据已经从其他的冗余分片进行了恢复,如图4.35所示此时分片中的数据又恢复为原来的5条。可恢复性验证成功。4.3.4验证可扩展性 验证可恢复性的方法可以通过如下的方式验证。系统前端集群中包含了3个节点,首先停掉一台机器,在其Hubot的脚本文件夹中加入新的脚本,如图4.36所示。图 4.36 引入Hubot脚本此时重启Hubot系统,此时在命令行中输入如下命令: hubot image 北航此时部分的节点会无视此命令无任何的反应,而添加了此命令的Hubot节点则可以出现如图4.37所示的结果图 4.37 新命令image的运行结果然后依次替换集群其他的节点,当每次输入命令hubot image 北航 出现的结果都为图4.37所示的图片,即可得知hubot image命令已经加入Hubot系统,而且在整个系统的更新过程中并没有出现系统停机用户不可用的情况,节点的替换是依次进行的,当全部节点替换完毕后,整个系统就更新完毕了,因此可扩展性验证成功。4.4实验分析 总的来讲基于Hubot的个人云系统验证基本通过。在上面的实验中验证了如下的功能与特性:文件系统的基本命令集的可用性。webapp的基本功能可用新Webshell和Hubot的命令的可用性个人云系统的一致性、高容错性、可恢复性、可扩展性。通过上述的验证,基于Hubot的个人云的原型系统运行良好,达到了既定的目标。5总结与展望5.1总结 在本次毕业设计编写的过程中,无论是分布式的webapp还是Hubot命令集的构建,都是不停的在摸索中前行。有的时候问题的解决方案会在不经意间发现。而这种发现是让人感到鼓舞和骄傲的。 在本课题中,主要分为了四个部分,Webshell前端部分,Hubot解析命令集部分,分布式webapp部分,底层文件系统部分。 在Webshell中,采用AngularJS作为前端的开发框架,采用WebSocket作为前端和Hubot之间的通信协议,用这种方式可以进行实时的通信,从而达到实时更新。 在Hubot中采用异步加载的方式,加载监听脚本。这种方式使可以得到更快速的响应。 在分布式webapp中,采用分布式的架构,提供了高效性和高可用性的服务。 在底层的文件系统中,构建了操纵远程个人云存储系统的方式,这种方式可以很容易的将无法支持大规模存储系统的场景进行修复,特别是在手机或者移动端。 总的来讲,本课题开发的基于Hubot的个人云系统是一种对于个人云计算的尝试,这种尝试尽管作为商业产品还有一定的距离,但是这种方式是一种技术的尝试,是一种个人云系统的可行性方案的探索5.2工作展望 在本文中我们构建了基于Hubot的个人云系统,基本完成了本文之前定义的要求,但是还有很多的地方需要继续去做。首先是泛型的Terminal,泛型的Terminal有很多种,在本文中我们还是只在浏览器中进行了实现,但是其实还有很多的场景可以作为Terminal,比如微博,QQ等一切可以交互的场景。另外在本文中尚没有发挥文件系统的全部功能,在后续的工作中,文件系统的发展空间还很大,有很多接口都可以与文件系统相结合。这也是未来的工作之一。在构建Hubot的过程中尚未能支持自定义的命令,这个也是后续的一个工作重点。期待在今后的工作中能将个人云系统进一步的完善构建一个完善能够惠及大众的个人云系统。 致谢 在完成本科学位论文之际,我要向所有给予过我指导、帮助和关心的老师、同学和家人致以最衷心的感谢。首先,我要感谢我的毕业指导老师杨海燕老师。虽然杨海燕老师并不像很多同学的指导老师一样,并不是我一直以来的指导老师,但是杨老师是一个非常负责的老师,每当我倦怠的时候都会给我激励的鞭策。杨老师是我编译原理的老师,由于我在大学三年级开始就一直在外边实习,所以和杨老师的初识是我在检查编译大作业的时候。从前一直听说杨老师是一个很严厉的老师,当我在做编译原理的检查的时候,有一个测试点一直都有问题,杨老师很悉心的告诉我不要着急,时间还是有的。虽然最后我依然没有调试出来那个测试点,但是从那时起,杨老师和蔼可亲的形象就深深的植入了我的脑海里。同时我还要非常感谢在大三以来和我一起工作过的同事们,我先后在四家公司工作过。大二暑期的时候我在磊强科技做总经理的助理,这段经理让我初步认识了IT这个行业;大三的时候,我加入了北京精益汇智科技有限公司,在那里我初步进入了职场,有了自己的规划;后来我加入了微软亚洲研究院,参与了国家的973项目,在项目中我学习到了微软的严禁与飘逸;最后是我现在的公司,北京阿里巴巴云计算技术有限公司,在这里我学到了很多,也认识了我先在的校外导师,朱哲,在他的指导下,不仅仅是毕设,还有很多其他的方面我都学会了很多。我要由衷的感谢我的舍友和同学还有辅导员们,平时经常出差杭州,学校中的事情都是大家帮我打理的,真心很感谢你们,每次很晚从机场回到宿舍都会吵醒上铺的兄弟,在此真的想说声抱歉。最后,我还要感谢我的家人对我的支持和鼓励,父母的辛苦付出才让我有机会接受高等教育,才能成为一名仰望星空,脚踏实地的北航学子。参考文献[1]个人云计算的简介 http://zh.wikipedia.org/wiki/%E4%B8%AA%E4%BA%BA%E4%BA%91%E8%AE%A1%E7%AE%97[2]个人云存储的简介 http://zh.wikipedia.org/wiki/%E4%BA%91%E5%AD%98%E5%82%A8 [3]Dropbox https://www.dropbox.com/[4]Google Drive http://baike.baidu.com/view/1698594.htm?fr=aladdin[5]Chrome OS http://baike.baidu.com/view/2627636.htm?from_id=7918727&type=syn&fromtitle=Chrome+OS&fr=aladdin[6]全栈式开发的整体框架示意图 http://meanjs.org[7] Kyle Banker. MongoDB In Action[M],2011-12-01[8]MongoDB内部架构 http://software.cnw.com.cn/software-database/htm2012/20120501_246005.shtml[9]朴灵.深入浅出Nodejs.人民邮电出版社,2013-12-01[10] Lerner.The Complete Book on AngularJS.Fullstack IO,2013-12-29[11]AngularJS的Scope http://www.lovelucy.info/understanding-scopes-in-angularjs.html[12] Guillermo Rauch.了不起的Node.js.电子工业出版社 [13]分布式系统架构 http://www.topphp.cn/gaobiaozhun.htm[14]MongoDB副本集 http://blog.csdn.net/luonanqin/article/details/8497860[15]MongoDB分片集 http://www.uml.org.cn/sjjm/201204184.asp[16]Github https://github.com/19
基于Hubot的个人云系统的设计与实现,毕业设计论文
3995
来源:
Licence:
联系:
分类:
平台:
环境:
大小:
更新:
标签:
免费下载
×
温馨提示
请用电脑打开本网页,即可以免费获取你想要的了。