ZStack是下一代开源的云计算IaaS(基础架构即服务)软件。它主要面向将来的智能数据中心,经过提供灵活完善的APIs来管理包括计算、存储和网络在内的数据中心资源。用户能够利用ZStack快速构建本身的智能云数据中心,也能够在稳定的ZStack之上搭建灵活的云应用场景,例如VDI(虚拟桌面基础架构)、PaaS(平台即服务)、SaaS(软件即服务)等。html
上期5分钟和你们分享了ZStack的核心架构设计特色,本期重点介绍:ZStack 核心架构设计特色之可拓展性秘密武器2—无状态的服务。算法
前言数据库
每个ZStack服务都是无状态的,简单的开启一个富余的服务实例而后使之负载均衡,就能实现服务的高可用和可横向拓展;此外,ZStack把全部服务封装进一个称为管理节点的进程中,使得部署和管理服务变得尤为简单。api
动机网络
在“ZStack的可拓展性秘密武器1:全异步架构”中,咱们论述了异步的架构使得单一的ZStack管理节点足以承担大多数云的负载量;然而当用户想要去建立一个高可用的生产环境或处理很是大的并发工做负载,一个管理节点是不够的。解决方案是创建一个负载均衡的分布式系统,这种经过添加新节点来拓展整个系统的能力的方法被称为横向拓展。架构
问题并发
设计一个分布式系统不是一件简单的事情。一个分布式系统,特别是一个有状态的系统,必须处理一致性(consistency)、可用性(availability)和分区容忍性(partition tolerance)(CAP理论)的问题,每个问题都是很是复杂的。与之相反,一个无状态的分布式系统必定程度上下降了复杂度。第一,由于节点不用分享状态,整个系统的一致性是能够保证的。第二,由于节点都是类似的,对于分区问题系统一般是能够容忍的。所以,一般把一个分布式系统设计为无状态的而不是有状态的。可是设计一个无状态的分布式系统一般比设计一个有状态的分布式系统可贵多。利用消息代理和数据库的优势,ZStack创建了一个包含各类无状态服务的无状态分布式系统。负载均衡
使整个系统无状态的基础是无状态的服务,在讨论什么是无状态的服务以前,咱们首先理解什么是“状态”。在ZStack中,主机、虚拟机、镜像和用户等资源是被一个个服务管理的。当整个系统的服务实例不止一个的时候,资源会被分发到不一样的服务实例中。假设有10000台虚拟机和两个虚拟机服务实例,理想状态下每一个实例会管理5000台虚拟机。less
由于有两个服务实例,在向一个虚拟机发出请求前,请求者必须知道哪一个实例管理哪一个虚拟机,不然,他将不知道向哪一个实例发出请求。相似“哪一个服务实例管理哪一个资源”的信息就是咱们所说的状态。若是一个服务是有状态的,每一个服务维护本身的状态。请求者必须能够获取到当前的状态信息。当服务实例的数量改变的时候,服务须要去改变状态。异步
状态的改变是危险且易错的,这一般限制了整个系统的可拓展性。为了使整个系统的可靠性和横向拓展性加强,把状态和服务分离开,使得服务无状态是比较理想的解决办法(参考Service Statelessness Principle)。无状态的服务使请求者不须要询问向哪里发送请求,当新添一个新的服务实例或者删除一个旧的服务实例的时候,服务之间也不用交换状态。
备注:在如下文档中,为了简便,“服务”和“服务实例”是能够互换的。
服务和管理节点
经过中心消息代理-- RabbitMQ彼此通讯的服务,在ZStack中是一等公民。
与典型的microservice架构不一样,典型的microservice架构中每一个服务一般运行在不一样的进程或者不一样的机器上,ZStack则把全部服务封装在一个被称为管理节点的进程中。文章“进程内的microservice架构”解释了咱们这么作的缘由。
每一个管理节点都是一个功能齐全的ZStack软件。由于包含的服务是无状态的,管理节点不共享任何状态,但仍然须要维护和其余节点的心跳记录,和一个一致性哈希环,咱们接下来将详细介绍哈希环。心跳用来监视管理节点是否正常运行,一旦一个管理节点中止更新本身的心跳一段时间后,其余的管理节点将会驱逐它而后接管他所管理的资源。
无状态的服务
针对ZStack的业务逻辑,实现无状态服务的核心技术,是一致性哈希算法。当系统启动的时候,每个管理节点将被分配一个version 4 UUID(管理节点UUID),这个UUID将和服务名称拼在一块儿在消息代理上注册一个服务队列。(举例代码详见阅读原文)
备注:你应该已经注意到全部的队列都是以一个相同的管理节点的UUID结尾的。
主机,磁盘,虚拟机等资源也有特定的UUID。和资源相关的消息一般在服务之间传递,在发送一个消息以前,发送者必须基于资源的UUID选择一个接收服务,一致性哈希算法这时候就发挥做用了。
一致性哈希是一种较特别的哈希,当一个哈希表的大小发生变化时,只有一部分键须要被从新映射。深刻了解一致性哈希,请阅读http://www.tom-e-white.com/2007/11/consistent-hashing.html,在ZStack中,管理节点组成了一个一致性哈希以下:
每个管理节点维护了一份包含系统中全部管理节点的UUID的环拷贝,当一个管理节点添加或删除的时候,一个生命周期事件将经过消息代理广播到其余的管理节点,这将致使这些节点拓展或者收缩环去描述当前系统的状态。当发送一条消息时,发送者将使用资源的UUID哈希得出目标管理节点的UUID。例如,当VM的UUID是932763162d054c04adaab6ab498c9139时发送一个StartVmInstanceMsg,(伪代码详见阅读原文)
有了哈希环,资源UUID相同的消息将被映射到特定管理节点的相同服务中,这点是ZStack的无锁架构的基础(详见下期5分钟:ZStack的可拓展性秘密武器3:无锁架构)。
当环收缩或者拓展的时候,由于哈希环的固有特性,仅有小部分节点将被影响。
由于使用一致性哈希环,发送者不须要知道哪一个服务实例将处理这条消息,由于服务实例将被哈希计算出来。服务也不用维护、交换他们管理的资源信息,而且由于选择正确的服务实例能够由哈希环完成,服务只须要单纯的处理消息。所以,服务变得极其简单且无状态。
除了包含资源UUID的消息(例如StartVmInstanceMsg, DownloadImageMsg)之外,有一种不包含资源UUID的消息,这种消息一般是创造性的消息(例如CreateVolumeMsg)和不进行资源操做的消息(例如AllocateHostMsg),由于这些消息能够被发送到任意管理节点的服务中,他们就被发送到本地的管理节点,由于发送者和接收者在同一个节点上,接收者在发送者发送消息时必定是可用的。
对于API消息(如APIStartVmInstanceMsg),有一个特别的处理方法是他们常常和一个重要的服务ID api.portal绑在一块儿发送。在消息代理中,一个称为zstack.message.api.portal的全局的队列被全部管理节点的API服务共享,带有api.portal的消息将经过一致性哈希环把消息映射到正确的服务中,从而实现负载均衡。经过上面这种方式,ZStack隐藏了API客户端消息选路的实现,减小了ZStack API客户端代码。(代码详见阅读原文)
总结
本文演示了ZStack是如何经过构建一个无状态的分布式系统来进行横向拓展的。由于管理节点共享的信息很是少,创建一个庞大的拥有几十或上百个管理节点的集群是很是容易的。然而,在现实中,对于私有云,两个管理节点足够知足高可用性和可拓展性的需求。对于公有云,管理者能够依据负载量大量建立管理节点。由于异步架构和无状态架构,ZStack可以处理现有的IaaS软件处理不了的很是大的并发任务。
以上,就是本期的架构篇补习啦,对架构感兴趣的小伙伴欢迎参考如下步骤自行到官网探索更多ZStack架构相关噢~
产品下载请戳:
https://www.zstack.io/help/product_manuals/maintenance_manual/2.html#c2_1
产品手册:
https://www.zstack.io/help/product_manuals/
Question Time
问题答案都在今日的小课堂中,补习完成记得带着答案到官微(ZStack云计算)后台回复,咱们会随机抽取5位爱学习的小伙伴送上一点当心意~
阅读原文包含文中代码噢,须要的小伙伴点击进入官网‘知识库-技术汇-可拓展性秘密武器2:无状态的服务’自取便可!