ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OpenStack设计与实现—读书笔记

OpenStack设计与实现—读书笔记 OpenStack 设计与实现OpenStack 体系结构云计算”中所谓的“云”可以简单被理解为任何可以通过互联网访问的服务,那么根据所提供服务的类型,云计算就有3种落地方式。●IaaS (基础架构即服务):通过互联网提供“基础的计算资源”,包括处理能力、存储空间、网络等,用户能从中申请到硬件或虚拟硬件,包括裸机(Bare Metal)或虚拟机,然后在上面安装操作系统或其他应用程序。●PaaS (平台即服务):把计算环境、开发环境等平台作为一种服务通过互联网提供给用户。用户能从中申请到一个安装了操作系统以及支撑应用程序运行所需要的运行库等软件的物理机或虚拟机,然后在上面安装其他应用程序,但不能修改已经预装好的操作系统和运行环境。●SaaS(软件即服务):通过互联网,为用户提供软件及应用程序的一种服务方式。应用软件安装在厂商或者服务供应商那里,用户可以通过网络以租赁的方式来使用这些软件,而不是购买。比较常见的模式是提供一组账号密码。PaaS 和SaaS并不一定需要底层有虚拟化技术的支持,但 IaaS 一般都是建立在虚拟化技术基础之上的。OpenStack 以及它一直在跟随的榜样AWS 都是属于IaaS 的范畴。本质上,IaaS系统其实就是一个用户层的软件系统,它包含多个服务和应用程序,这些服务或程序被部署到多台被管理的物理主机上,这些物理主机通过网络相连从而形成一个大的分布式系统。IaaS 系统要解决的问题就是如何自动管理这些物理主机上虚拟出来的虚拟机,包括虚拟机的创建、迁移、关闭,虚拟存储的创建和维护,虚拟网络的管理,还包括监控计费、负载均衡、高可用性、安全等。这里不提供任何虚拟化服务的裸机(Bare Metal)也被视为虚拟机的一种特例,对它的管理也属于虚拟机管理的范畴。在单个主机上,这些都可以通过简单的命令和操作完成,有些问题,比如高可用性或负载均衡等根本不存在。但是,如果在大规模网络上或数据中心里,将有成千上万台物理主机,仅仅靠运维人员来完成这些管理任务是不现实的,这时候就需要软件系统来自动辅助运维人员管理和维护系统的运行,给用户提供虚拟机服务。这就是 IaaS 系统产生的初衷,也是 AWS和OpenStack,以及其他 IaaS 产品和开源项目要实现的功能。OpenStack与AWS无论是否情愿,我们都不得不承认,与亚马逊的 AWS 相比,OpenStack 只是处于一个跟随者的位置。Bezos 颁布那份充满系统架构智慧的法令之后,到2006年,亚马逊推出了 AWS产品,正式开启了云计算的新纪元。AWS由一系列服务组成,去实现 laaS 系统所需要的功能。如图1-4所示,AWS 架构由5层组成,自下而上分别是 AWS 全球基础架构、基础服务、应用平台服务、管理和用户应用程序。而就服务类型本身而言,AWS 主要提供6类服务:计算和网络、存储和内容分发、数据库、分析、部署管理和应用服务。计算和网络服务中涵盖了负责虚拟机调度和管理的弾性计算云EC2、用于计算资源自动扩容缩容的Auto Scaling服务、负载均衡服务 ELB、虚拟桌面管理服务 WorkSpaces、保证企业在公有云上搭建安全私有云的虚拟私有云服务VPC、高可靠且可扩展的域名系统 Web 服务Route 53 以及为企业定制的专属网络连接Direct Connect 等。在存储和内容转发服务中涵盖了简单存储服务S3、Amazon Glacier、块存储 EBS、AWS存储网关、AWS 导入导出以及Amazon 云前端。其中S3 提供AWS 永久存储服务,而 EBS提供的是块存储服务。在数据库服务里,包括关系数据库服务 RDS、NoSQL数据库服务 DynamoDB、缓存和数据仓库服务 RedShift。在分析服务里,AWS包括用于大数据的弹性 MapReduce (EMR)、用于大规模实时流数据处理的Kinesis 和数据管道。在部署管理服务里,AWS 包括验证访问管理IAM、日志管理 CloudTrail、监控 CloudWatch、用于轻松部署Web应用和服务的 Beanstalk、建立和管理 AWS 资源的CloudInformation、为运维人员配备的应用管理服务OpsWorks 和安全服务 CloudHSM。在应用服务里,AWS 包括应用程序流(AppStream)、简单队列服务(SQS)、简单消息服务(SNS)、简单工作流服务(SWF)、简单邮件服务(SES)、用于云搜索的 CloudSearch,以及用于流媒体转码的Transcoder。AWS的功能十分强大,而且目前还在不断发展之中,OpenStack 从诞生之初就一直向AWS模仿和学习,同时,OpenStack也提供开放接口去兼容各种 AWS 服务。比如,AWS 中最为核心的EC2模块,负责计算资源的管理,以及虚拟机的调度和管理,在OpenStack 中对应的就是Nova 项目;AWS 中的简单存储服务S3,在 OpenStack 中有Swift项目与其功能相近;AWS 中的块存储模块EBS,对应 OpenStack的 Cinder 项目;AWS 的验证访问管理服务IAM,对应 OpenStack 的KeyStone 项目;AWS的监控服务 CloudWatch,对应OpenStack 的Ceilometer 项目;AWS 有CloudInformation, OpenStack 则有Heat 项目:AWS支持关系数据库RDS和 NoSQL 数据库DynamoDB, OpenStack也支持 mySQL、postgre 和NOSQL 数据库 MongoDB。OpenStack的发展既然 OpenStack 可以通过Kubernetes 等容器云技术来部署和管理控制面服务,那 OpenStack 则可以被看作是Kubernetes 容器云中的一个云原生的应用,随之而来的就是如云原生应用般的灵活管理,而直接面对裸机资源的 Kubernetes 又可以通过集成Ceph、Swift、Cinder、Neutron 等项目来完善对网络和存储资源的池化管理。更加彻底的资源池化云计算概念中被大家所熟知的一个就是资源的池化,包括技术资源的池化、网络资源的池化(SDN)和存储资源的池化(SDS),总括来说就是所谓的 SDI (Software DefinedInfrastructure,软件定义基础架构)。众所周知,主流的服务器硬件配置基本上是固定的,但以 Intel 主导的RSD(Rack ScaleDesign)整机柜服务器技术,则可以做到动态调配整个机柜中的 CPU、内存、存储、网口等硬件资源,灵活地组成不同配置的服务器。此项技术把资源池化的概念实现得更加彻底,所带来的好处也不言而喻。OpenStack 代码质量保证体系比尔·盖茨说:“用代码行数来衡量编程的进度,就如同用航空器零件的重量来衡量航空飞机的制造进度一样。”所以,相对于代码的数量,我们通常更乐意去关注代码本身的质量,也因此,在开源社区里,除了某些特殊的目的,我们也更愿意去关注一个人被接受 patch 的数目,而不是这些 patch 里代码的行数。总之,将“代码质量”定义清楚是一件足够复杂的事情。幸好,笛卡儿很有预见性地在17世纪的某一天,闲极无聊写了这么一本书,书名就叫《方法论》。在这本目前来说绝大部分人都不知道的书里将方法上升到了理论的高度。笛卡儿在他的这本书里将研究问题的方法归纳为简单的一句话,就是“复杂问题要简单化”。遵循这个方法论,我们这里尝试去解释一下代码质量。代码一是给计算机读,二是给人读,给维护这份代码的人读。给计算机读比较简单,只要遵守语言的规则,计算机就能将它编译成最后的结果。给人读就比较麻烦,我们去读别人编写的代码的时候,都是希望这个代码写得比较简单,函数很短,命名能够让人望文生义,读起来就像读小说、故事会一样,我们希望的就是我们自己编码的时候应该要做到的目标,这就是站在通俗角度简单化了的代码质量。这个简单化了的定义强调更多的是代码的可读性,“代码应该是写给其他人来读的,而能让机器运行的仅仅是附带着的。”大牛们如是说。可读性是其他一切代码质量指标,包括可维护性、可靠性、可扩展性、性能等的基石,一般来说,干净整洁的代码,往往运行起来更快。而且即使它们运转速度不快,也可以很容易地让它们变快。正如人们所说的,优化正确的代码比改正优化过的代码容易多了。但是对于一个蓬勃发展、前景无限可期的开源项目来说,它的代码质量却不能只是这么简单地给个通俗定义,而是必须有一套行之有效的体系与工具来保证。统一编码规范:可读性与可维护性的前提就是一个统一的编码规范。静态代码检查:代码的开发完成以后,接着要进行的工作就是测试。而从计算机理论的角度来说,测试又被划分为静态测试与动态测试。其中,动态测试指的就是通常意义上我们所说的测试,它会去运行测试代码或直接运行被测试的软件来发现存在的问题。静态测试则是指应用其他手段实现测试目的,比如属于人工范畴的代码评审(Code Review)与计算机辅助进行的静态代码检查。代码的静态检查主要是指利用静态分析工具对代码进行特性分析,以便检查程序逻辑的各种缺陷和可疑的程序构造,比如不符合编码规范、潜在的死循环等编译器发现不了的错误。之所以称之为静态代码检查,是因为只是分析源代码或者生成的目标文件,并不实际运行源代码生成的文件。它的目的是帮助我们尽可能早地发现代码中存在的问题并及时修复,将其消灭在萌芽状态,就能为后续工作节省大量的花在测试与调试上面的时间。单元测试。持续集成。持续集成(CI, Continuous Integration)是利用一系列的工具、方法和规则,通过自动化的构建(包括编译、发布、自动化测试等)尽快发现问题和错误,来提高开发代码的效率和质量。代码评审与重构。代码评审可以帮助发现静态代码检查过程中无法发现的一些问题,比如代码的编写是否符合编码规范,代码在逻辑上或者功能上是否存在错误,代码在执行效率和性能上是否有需要改进的地方,代码的注释是否完整正确,代码是否存在冗余和重复。通过代码评审发现的问题要通过代码及时解决掉。本节接下来的内容将会对照上述的代码质量保证步骤,总结 OpenStack 使用的工具与采取的措施。程序员最讨厌的4件事应该是:写注释、写文档、别人不写注释、别人不写文档。那么对于这样一个貌似很不好相处的群体,有人说,如果莎士比亚生活在当下,他会是一名科技作家,而且他的座右铭也会变成:“消灭世界上所有的程序员。”对于C、C等编译型语言来说,因为可以与编译器进行比对,理解代码静态检查会更为容易一些。编译器与代码静态检查工具都能检查代码中的潜在问题。一般地,编译器最重要的作用是生成可执行文件,所以对于词法语法的分析相对局部一些,即在检测错误时,前后查看的代码较少。这也是基于编译器的性能来考虑的。所以说,尽管编译器擅长发现一些错误,但通常会考虑速度而放弃了对一些较难发现的条件的检查。这样一些原本可以发现的错误,经常会被遗漏而成为应用中的 bug,比如未成功释放已分配的内存、死循环等。持续集成Jenkins根据《重构一改善代码既有的设计》作者Martin Fowler 大师在《持续集成》一书中的定义,“持续集成是一种软件开发实践。在持续集成中,团队成员频繁集成他们的工作成果,一般每人每天至少集成一次,也可以多次。每次集成会经过自动构建(包括自动测试)的检验,以尽快发现集成错误。许多团队发现这种方法可以显著减少集成引起的问题,并可以加快团队合作软件开发的速度。”通俗地说,持续集成(CI)需要对每一次代码提交走一次从代码集成到打包发布的完成流程,以判断提交的代码会对这整个流程带来什么影响。而这个过程中所使用的手法严重依赖于团队成员的多少、目标平台和配置的不同等因素。比如,只有一个人单干,同时只面向一个平台,那么每次有一个 commit时,手工跑一下测试基本就知道结果,也就完全不需要其他更为复杂的工具与手段。但是对于OpenStack 这样的项目来说,显然没有这么简单,涉及一个使用版本控制软件来维护的代码仓库,自动的构建过程,包括自动编译、测试、部署等,以及一个持续集成服务器。虚拟化对云计算而言,特别是提供基础架构即服务的云计算,更关心的是硬件抽象层上的虚拟化。因为,只有把物理计算机系统虚拟化为多台虚拟计算机系统,通过网络将这些虚拟计算机系统互联互通,才能够形成现代意义上的基础架构,即服务云计算系统。OpenStack 通用技术OpenStack 遵循这样的设计原则:项目之间通过 RESTful API进行通信;项目内部,不同服务进程之间的通信,则必须要通过消息总线。这种设计思想保证了各个项目对外提供服务的接口可以被不同类型的客户端高效支持,同时也保证了项目内部通信接口的可扩展性和可靠性,以支持大规模的部署。RESTful 是目前流行的一种互联网软件架构。REST (Representational State Transfer,表述性状态转移)一词最早由 Roy Thomas Fielding 在他2000年的博士论文中提出,定义了他对互联网软件的架构原则,如果一个架构符合 REST原则,就称它为 RESTful 架构。RESTful 架构一个核心的概念是“资源”(Resource)。从 RESTful的角度来看,网络里的任何东西都是资源,它可以是一段文本、一张图片、一首歌曲、一种服务等,每个资源都对应一个特定的URI(统一资源定位符),并用它进行标识,访问 URI就可以获得这个资源。目前己有多种消息总线的开源实现,OpenStack也对其中的部分实现有所支持,比如RabbitMQ、Qpid等。基于这些消息总线类型,oslo.messaging 库通过以下两种方式来完成项目内部各服务进程之间的通信。(1)远程过程调用( Remote Procedure Call, RPC)。通过远程过程调用,一个服务进程可以调用其他远程服务进程的方法,并且有两种调用方式: call 和cast。通过 call的方式调用,远程方法会被同步执行,调用者会被阻塞直到结果返回;通过 cast的方式调用,远程方法会被异步执行,结果并不会立即返回,调用者也不会被阻塞,但是调用者需要利用其他方式查询这次远程调用的结果。(2)事件通知(Event Notification)。某个服务进程可以把事件通知发送到消息总线上,该消息总线上所有对此类事件感兴趣的服务进程,都可以获得此事件通知并进行进一步的处理,处理的结果并不会返回给事件发送者。这种通信方式,不但可以在同一个项目内部的各个服务进程之间发送通知,还可以实现跨项目之间的通知发送。Ceilometer 就通过这种方式大量获取其他OpenStack 项目的事件通知,从而进行计量和监控。NovaNova由多个提供不同功能的独立组件组成,对外通过REST API通信,对内使用 RPC进行通信,使用一个中心 DB来存储数据,如图5-1所示。每个组件都可以部署一个或者多个来实现横向扩展。这样的架构也是被大部分OpenStack 项目所采用。API是进入 Nova 的HTTP接口,可以通过部署多个来实现横向扩展。API 依据请求是长时任务或者是短时任务,将请求发送给 Conductor 或者 Compute。长时任务请求被发送到Conductor, Conductor 负责对其全程跟踪和调度。对于新建虚拟机或者迁移类需要调度的请求,Conductor 会向Scheduler请求一台符合要求的计算节点,随后 Conductor 会把请求最终发送到合适的计算节点上。Conductor 除了长时任务还负责代理其他节点的DB访问。这主要是为了安全问题和实现在线升级功能。最终对于虚拟机操作的请求都会发送到 Compute组件,Compute负责与 Hypervisor进行通信,实现虚拟机的生命周期管理以创建虚拟机为例,首先用户执行 novaclient提供的用于创建虚拟机的命令,API服务监听到novaclient 发送的HTTP 请求并且API将它转换成 AMQP消息,通过消息队列(Queue)调用Conductor服务,Conductor服务通过消息队列接受到任务之后,做一些准备工作(例如汇总虚拟机参数等),再通过消息队列告诉Scheduler去选择一个满足虚拟机创建要求的主机,Conductor 拿到Scheduler提供的目标主机之后,会去要求 Compute 服务创建虚拟机。并不是所有的业务流程都像创建虚拟机那样需要所有的服务,对于一些短时任务,比如删除虚拟机时,不需要 Scheduler服务,API通过消息队列告诉 Compute 删除指定虚拟机,Compute 通过Conductor 更新数据库即完成业务的流程。TASKFLOW通过TaskFlow 库可以更容易地控制任务Task的执行。代码库在 https://github.com/openstack/taskflow,项目主页是 http://aunchpad.net/taskflow文档在 http://docs.openstack.org/developer/taskflow/•我们利用下面的示例来了解 TaskFlow 中几个最基本的概念一——task、flow 和engine。这个示例首先定义了3个 task: CallJim、CallJoe 和CallSuzzie。在 TaskFlow库中,task是拥有执行(execute)和回滚(revert)功能的最小单位 (TaskFlow 中的最小单位是atom,其他所有类包括 Task 都是Atom 类的子类)。在 TaskFlow库中,task是拥有执行(execute)和回滚(revert)功能的最小单位 (TaskFlow 中的最小单位是atom,其他所有类包括 Task 都是Atom 类的子类)。在 Task类中,允许开发者定义自己的 execute 函数和revert函数,分别用来执行 task 和回退task 到之前一次的执行结果。然后新建一个线性流flow,并在其中顺序加入上述3个task 对象。TaskFlow 中的流flow用来关联各个task,并且规范这些 task 之间的执行和回滚顺序。nova调度系统整个调度子系统主要由 Nova的四大子服务组成,即 nova-api、nova-conductor、nova-scheduler 和nova-compute服务。当用户发起一个新的请求时,该请求首先在nova-api 中处理。nova-api会对请求做一系列检查,包括请求是否合法、配额是否足够、是否有符合要求的网络、镜像及虚拟机类型等。当检查通过后,nova-api 就会为该请求分配一个唯一的虚拟机ID,并在数据库中新建对应的项来记录虚拟机的状态。然后,nova-api 将请求发送给nova-conductor 处理。nova-conductor作为一个协调者角色,主要管理服务之间的通信和任务处理。它在接收到请求之后,会为 nova-scheduler 创建一个RequestSpec对象,用来包装调度相关的所有请求资料,然后远程调用 nova-scheduler 服务的select destination 接口。nova-scheduler 则会通过接收到的RequestSpec 对象,根据数据库中最新的系统状态作出调度决定,告诉 nova-conductor 把该请求调度到合适的计算节点上。nova-conductor 在得知调度器的决定后,会把请求发送到对应的 nova-compute 服务。个nova-compute 服务都运行有独立的资源监视器(Resource Trakcer)来监视本地主机的资源使用情况。当计算节点接收到请求时,资源监视器能够检查主机是否有足够的对应资源。如果资源足够,nova-compute 就会允许在当前主机中启动请求所要求的虚拟机,并在数据库中更新最新的虚拟机状态,同时将最新的主机资源情况更新到数据库中。若当前主机不符合请求的资源要求时, nova-compute 则会拒绝启动虚拟机,并将请求重新发送到nova-conductor服务,来重试整个调度过程。整个调度过程可以分为3个主要阶段:预调度阶段主要进行安全检查,并为将要进行的调度过程准备相应的数据项和请求对象;在调度阶段 Nova可能会进行超过一次的调度决策,最终将确定系统是否有能力创建相应的虚拟机,以及该创建在哪个主机上;当调度决策完成后,nova-compute 会在选择的主机上真正消耗资源,启动虚拟机和对应的网络存储设备。在冷迁移、热迁移、Resize、Rebuild和 EvacuateScheduler选择一个虚拟机在哪个主机上运行的调度方式有很多种,目前 Nova 中实现的可以在setup.cfg 文件中找到以下几个调度器。FilterScheduler(过滤调度器):默认载入的调度器,根据指定的过滤条件以及权重挑选最佳节点。CachingScheduler:与 FilterScheduler功能相同,在其基础上将主机资源信息缓存在本地内存中,然后通过后台的定时任务定时从数据库中获取最新的主机资源信息。ChanceScheduler(随机调度器):从所有 nova-compute 服务正常运行的节点中随机选择。FakeScheduler(伪调度器):用于单元测试,没有任何实际功能的调度器。FilterScheduler工作的核心,即缓存更新、Filetering(过滤)与 Weighting(权重计算与排序)。nova-scheduler在进行调度决策前需要从数据库中得到各个主机的资源数据,这些数据的收集与存储都由 nova-compute 负责。nova-compute对数据的更新是即时更新到数据库的,并有周期性任务保证资源数据的准确性。同时,由于 nova-scheduler无法更新数据库,所以在选择最佳主机时,要在内存中保存先前决策情况,这是通过在调度器内存中单独维护了一份缓存实现的。缓存里面包含了最近一次读取的数据库情况以及最近调度器决策导致的资源变化。这部分工作是由nova.scheduler.host_manager.HostState 完成的。由于调度器会同时处理多个调度请求,所以更新共享资源 HostState 时需要加锁(utils.synchronized)来保证数据的一致性。HostState 会从数据库和缓存中更新主机数据(compute),服务状态(service),主机聚合/分组信息(aggregates)和所有相关的虚拟机状态(inst_dict)。在更新主机数据时,如果数据库中某个主机数据的更新时间“ updated_at ”小于nova-scheduler 所维护数据的更新时间(self.updated),则说明该条数据已经过时了,此时不需要从数据库中更新。Weighting经过各种过滤器过滤之后,会得到一个最终的主机列表,保存了所有通过指定过滤器的主机。由于列表中可能存在多个主机,所以调度器还需要在他们当中选择最优的一个nova常见工作流其实热迁移并不是业务不中断,只是在迁移的最后时刻,虚拟机会有短暂挂起,快速完成最后一次内存复制。Hypervisor 中挂起虚拟机本质上就是改变VCPU的调度,暂时不给虚拟机可用的物理CPU时间片。给用户的感觉是虚拟机瞬间无响应。虚拟机热迁移的性能指标包括以下3个方面。整体迁移时间:从源主机开始迁移到迁移结束的时间。停机时间:迁移过程中,源主机、目的主机同时不可用的时间。对应用程序的性能影响:迁移对于被迁移主机上运行服务性能的影响程度,数据复制会冲高主机CPU 和网络流量。Neutron 体系结构类似于各个计算节点在Nova 中被泛化为计算资源池。OpenStack 所在的整个物理网络在Neutron 中也被泛化为网络资源池,通过对物理网络资源的灵活划分与管理, Neutron 能够为同一物理网络上的每个项目提供独立的虚拟网络环境。虚拟机的网络功能由虚拟网卡(vNIC)提供,Hypervisor 可以为每个虚拟机创建一个或多个vNIC,站在虚拟机的角度,这些 vNIC等同于物理的网卡。为了实现与传统物理网络等同的网络结构,与NIC一样 Switch 也被虚拟化为虚拟交换机(vSwitch),各个 vNIC 连接在vSwitch的端口上,最后这些 vSwitch 通过物理Server 的物理网卡访问外部的物理网络。
返回列表