【编者按】 已经成为IaaS事实标准的OpenStack,仍然面临稳定性、易用性等一系列的难题,新近推出的IaaS开源项目ZStack,号称要借鉴IaaS先辈的经验,通过新的技术架构解决OpenStack难以解决的技术问题,并得到了OpenStack社区的关注。那么,ZStack有何特色?能否实现目标?ZStack的发起者和总架构师张鑫(Frank),撰文从架构层面全面介绍了ZStack的设计理念和技术实现,并就ZStack的市场目标和社区规划进行了解答。以下为文章内容:
ZStack作为一款新开源IaaS软件,自发布后就迅速引起了技术圈的关注,许多朋友都对它架构特点很感兴趣。虽然在 ZStack主页 有16篇博客详细介绍了它的主要架构特点,但仍要花一定时间进行阅读才能把握其设计要点。笔者作为ZStack的发起者和总架构师,希望通过这篇文章对所有架构要点进行一次梳理,围绕它要解决的问题出发,为读者进行一个详细的介绍。
ZStack从诞生之初没有急于实现各种炫目的功能,而是花了大部分精力做架构设计,希望从架构上解决四个问题:易用性,稳定性,高性能,以及扩展性。ZStack的所有的架构设计,全部围绕这四个方面展开:
在易用性方面,ZStack首先考虑的是软件的安装部署与升级,其次是在长期使用的过程中的营运和维护。对于安装和部署,ZStack是一个Java项目,在编译的完成后,所有的文件都会被打包到一个Java的WAR文件中。部署ZStack实际就是部署一个标准的Java WAR文件到Apache Tomcat这样的web container中。这种部署是Java web应用的标准部署方法,非常简单且广为熟知。即使没有IaaS经验的的用户,也可以很容易学会安装。同时ZStack对外部的依赖非常少,仅仅需要MySQL数据库,RabbitMQ消息总线,以及Ansible系统配置管理软件,这些都是Linux各个发行版提供的软件。一个单管理节点的ZStack部署如图所示:
如果把MySQL和RabbitMQ放到单独的机器,单管理节点的部署可以很容易扩展成多节点部署:
由于IaaS软件管理数据中心中大量的硬件,很多情况下需要安装agent到硬件上,例如安装agent到作为KVM计算节点的Linux机器。为了让用户从手动安装配置硬件的枯燥工作中解脱出来,ZStack跟Ansible无缝集成,当用户添加一个计算节点时,ZStack调用Ansible自动安装agent并配置系统,整个过程对用户透明。用户无需阅读冗长的文档去了解agent需要什么依赖包,需要怎么配置,这些全部由ZStack负责。用户只需调用一个API即可。类似的设计应用在所有需要安装agent的服务,例如负责提供网络功能的虚拟机(Virutal Router VM)。
KVM agent的Ansible的配置文件如图所示:
配置文件和KVM agent的Python包都包含在Java WAR文件中,在用户调用API添加一个计算节点时,ZStack会自动找到对应的配置文件并调用Ansible去部署agent,用户甚至都不知道这个过程的存在。此外,对于高级用户,可以通过扩展Ansible配置文件来实现运维过程中的系统维护和升级。例如为了升级KVM机器的某个安装包修复一个安全漏洞,用户只需要在KVM的配置文件中加上相关内容,再调用ZStack的ReconnectHost API,就可以自动实现升级功能。
在监控方面,ZStack目前提供对关键的系统资源比如物理机,虚拟机的状态进行监控,任何在ZStack控制外的状态变化,例如虚拟机的意外宕机,都会在一定的时间内被检测到并同步到数据库。此外ZStack还通过Java的JMX协议对外暴露监控自身的接口,例如监控当前系统运行的任务,系统正在处理的消息,消息的平均处理时间和最大处理时间等。让用户可以实时了解系统动态。
丰富的查询API是ZStack为用户运维提供的一个重要功能。ZStack的查询API提供超过400万单项查询条件,400万阶乘的组合查询条件。用户在API层面就可以完成数据库级别的资源查询。查询API带来的意义是可以打造真正企业级的UI。在优秀的企业软件中,例如微软outlook,JIRA中,用户都可以根据自己的需求创建不同的视图。在IaaS中也有同样的需求。用户可能需要视图显示所有在同一三级网络中的虚拟机,显示所有内存容量低于2G的物理服务器等。在没有完善的查询API支持下,UI就只能提供几个默认视图,而无法允许用户自定义视图。
ZStack的查询API的一个独特之处在于,查询框架在接收到API后可以自动生成SQL语句,无需编写代码。开发人员只要在数据库中定义了表,然后在Java程序中用annotation描述新表与其它表之间的foreign key,再为新表继承一个查询API的基础类,所有工作就完成了。用户使用新API时,查询框架可以自动感知,根据用户的查询条件生成单表SQL以及多表Join的SQL语句。
IaaS软件本身是个集成项目,管理了数据中心中大量的子系统,它实际上管理着所有子系统和所有设备的状态。加之IaaS中每一个任务的执行路径非常长,例如创建一个虚拟机就涉及到计算节点,网络节点,存储节点状态的变化,其中任何一个步骤都可能出错。一旦错误发生,由于当前IaaS缺乏回退机制,某些子系统会遗留在中间状态。比如一个虚拟机最后创建失败了,但它的DHCP信息却可能遗留在网络节点,导致将来可能的DHCP冲突。为此,ZStack设计了一个workflow引擎,将任务的每个操作都封装到flow中,一旦某个操作出错,workflow引擎会回退(rollback)所以已经执行的flow,保证不会系统遗留在中间状态。
例如在上图的创建虚拟机workflow中,假设任务在VmCreateOnHypervisorFlow这一步失败了,workflow引擎会回退前面已执行的6个flow,包括子workflow(图中计算节点分配workflow,创建网络节点虚拟机的workflow)。例如删除已创建的网络节点虚拟机,删除已创建的虚拟磁盘,归还已分配的计算资源到计算节点等。最大程度保证系统状态的完整性。
除了可以回退外,workflow引擎还可以允许开发人员通过XML文件来配置关键任务。例如在上图中,创建虚拟机的workflow包含一个创建网络节点虚拟机的子workflow(Creating Appliance VM sub-workflow)。这个子workflow跟创建用户虚拟机的workflow类似,只有分配网卡这个flow不同。ZStack通过配置XML文件替换掉该条flow(图中绿色部分),就实现了创建网络节点虚拟机的逻辑。这种通过XML文件配置workflow的方式被大量运用,例如计算节点分配器(host allocator),存储分配器(storage allocator),IP地址分配器(IP allocator)都是通过这种方式实现的。开发人员甚至不用写新代码,只需重新组合一些flow的顺序就可以实现新的业务逻辑。例如计算节点分配器里的一些实现,就是通过组合已有的flow实现的。这种方式使ZStack的组件复用度非常高,帮助整个架构实现了松耦合。
除了workflow,ZStack在设计最初期就引入了一个类似于Eclipse的插件系统,所有核心功能都是以小插件的形式搭建起来的,保证无论是添加新功能还是移除旧功能,都不会修改已有代码,从而保证在快速实现新功能的同时,整体系统可以保持稳定。这个插件系统的核心是扩展点(extension point)。每个组件都可以定义自己的扩展点允许其它组件接入,从而扩展业务逻辑。
例如上图所示的安全组(security group)功能,它需要在虚拟机的不同生命期对防火墙规则进行编程。但对于虚拟机本身来说,安全组只是一个附加功能,所以并不应该实现在虚拟机自身的逻辑当中。基于ZStack的插件系统,安全组通过虚拟机模块,网络模块等定义的扩展点插入到了虚拟机生命期,网络配置等业务逻辑中,在不修改任何已有模块的情况下,实现成一个单独的Java JAR文件。也就是说,安全组本身不会对现有功能造成任何影响,即使删除安全组对应的JAR文件,整个系统也只是失去了这个功能而已。通过插件系统,ZStack本身架构完全实现了松耦合。
Tag system也是ZStack一个创新。虽然很多IaaS软件也有tag的概念,但大多只是帮助用户管理资源。ZStack定义一种称为system tag的概念,插件可以通过定义system tag,在不修改已有数据库表的情况下,实现为现有表添加新的字段。例如在虚拟机表中并不存在一个字段叫hostname,ZStack的一个插件通过定义一个vm::hostname的system tag,为虚拟机表增加了这个字段,从而允许用户在创建虚拟机时指定它的hostname。通过这种方式,插件在扩展已有功能时,无需对现有数据库表格式进行修改,从而减轻了软件升级过程中数据库迁移的负担。
Workflow引擎,插件系统,system tag设计的核心思想是最大程度的松耦合架构,保证已有系统在快速添加新功能的情况下也能保证整体架构稳定,避免因实现新功能而反复修改已有代码,导致产品始终没有一个稳定内核的情况。
最后,ZStack从诞生开始就是测试驱动的。在ZStack中验证功能点的唯一方法就是写测试用例。我们有三个全自动化的测试系统:Integration testing system, System testing system,以及Model-based testing system来保证整个项目的质量。其中Model-based testing system可以随机组合API生成测试用例,测试出很多正常使用情况下无法触及的死角。为了能够快速重现Model-based testing system发现的死角,我们还开发了一个回放工具,它能读入Model-based测试用例产生的日志而生成一个新测试用例,通过回放失败用例来产生一个供开发人员调试的环境,避免了人工手动重试数千个API来重现失败用例(因为Model-based测试用例可能随机执行数日,产生数以千计甚至万计的API调用)。下面是测试系统运行过程中的一个截图:
ZStack是目前开源软件中,唯一一款号称能够以单管理节点管理几十万物理机器,数百万虚拟机,以及响应数万并发API调用的软件。通过我们的软件模拟器,我们测试过管理10万物理机,通过1万到3万并发API创建百万虚拟机的情况。此外我们还进行了虚拟机创建的性能测试,数据如下表:
在测试中我们只使用了单网络节点,发现DHCP/DNS软件Dnsmasq成为了性能的瓶颈。在跟Dnsmasq社区沟通后,通过打补丁的Dnsmasq,我们能将创建10000虚拟机的时间缩短到11分钟。在使用多网络节点(多租户)的环境下,我们相信这个数据还可以进一步的提高。
ZStack的高性能受益于三个架构设计: 全异步架构,无状态服务架构,无锁架构。
全异步架构保证一个任务从API调用开始,到最后在外部设备上执行的过程都是全异步的,从而任何线程都不会因等待一个操作完成而阻塞。在我们的压力测试中,单管理节点响应10000 API调用只用了1000个线程就可以完成。ZStack的全异步架构由三部分组成:异步消息,异步函数调用,异步HTTP调用。其中异步消息是服务之间调用时使用的。宏观上看,ZStack的功能划分成了多个独立的服务,服务之间通过消息通信,连API都是以消息的形式实现。例如有虚拟机服务,网络服务,存储服务等。在服务的内部存在许多组件,他们协作完成一个服务的功能。这些组件之间的调用使用的是传统的函数调用方式,通过回调函数(callback)实现异步。最后,服务与外部agent通信时采用的是异步 HTTP调用。例如在创建KVM虚拟机时,虚拟机服务将请求提交给KVM agent后就返回了。KVM agent在虚拟机创建完成后,会通过回调HTTP链接通知虚拟机服务。
无状态服务是指通过一致性哈希环(consistent hashing ring),服务本身可以和它所管理的具体资源分离开来,服务相互之间也无需交换所管理资源的信息。例如在多管理节点部署中会存在多个虚拟机服务,他们共同管理系统中的所有虚拟机。但每个服务自身是不需要知道哪些虚拟机是自己管理的,哪些是其它人管理的。当其它服务向虚拟机服务发送请求时,会用虚拟机的UUID通过一致性哈希环算出管理这个虚拟机的服务,从而保证无论请求在哪个管理节点发起,最终都会被发送到相同的服务去处理。
得益于无状态服务,ZStack的所有业务逻辑无需通过锁相互竞争资源,资源竞争完全通过队列控制。由于一致性哈希环会把针对某一个资源的操作全部转发到同一个服务,ZStack允许每个服务在内存中创建FIFO队列,以请求到达的顺序响应。对于所有操作只能顺序执行的资源,例如虚拟机,服务可以创建并发度为1的队列,保证同一时间只有一个操作在执行。
对于允许并发操作的资源,例如物理服务器可以允许同时执行多个操作,可以创建并发度大于1的队列。
通过基于队列的无锁架构,ZStack即实现了对关键资源的操作同步,又实现了对操作并发度的控制,在提高系统的吞吐性同时,又保证了系统在大吞吐量时的稳定性。例如物理服务器(host)资源的默认并发度是10,在系统大负荷的情况下,ZStack保证物理服务器最多响应10个请求,多的请求排队,避免了过多的请求造成资源的崩溃。当然,资源的并发度完全是可配置的,用户可以通过API配置例如物理服务器的并发度,根据系统的负荷调整参数。
ZStack在设计之初就考虑到了不同的用户对云的使用模式的差异性。例如公有云提供商,服务提供商,倾向于亚马逊的模式。而传统企业用户,则更喜欢VMWare的企业虚拟化模式(Enterprise Virtualization)。基于插件系统,ZStack将每个功能实现成小插件,默认是亚马逊的EC2模式,也就是各种资源池化。然后在这个基础上,通过一些辅助插件,ZStack可以在EC2的模式上组合出VMWare这种以虚拟机为中心的模式。这样不同的用户就可以根据自己的需求选择相应的模式。并且两种模式还可以互通,比如以虚拟机为中心的模式也可以使用EC2模式所提供的安全组(security group),弹性IP(EIP)这样的网络服务。
除了插件系统外,ZStack也认识到很多IaaS的功能可以实现成单独的服务,并且允许开发者用他们熟悉的语言来实现。这种创建单独服务的方法在ZStack中称为进程外插件(out-of-process plugin)。开发者可以根据自己的喜好选用自己喜欢的语言,创建与ZStack管理节点进程分离的服务。如果服务本身功能单一,可以订阅ZStack管理节点组播到消息总线的事件(canonical events),例如账单系统就可以监听各种资源的创建和销毁事件,完全实现独立开发。对于功能复杂的服务,例如需要访问数据库的服务,可以通过写一个轻量级的插件安装在管理节点中,然后跟进程外服务通信。第二种方式有点类似应用程序通过在操作系统中安装驱动,来实现对内核的访问。ZStack的web UI就是以这种进程外插件的方式实现的。
基于插件系统和进程外服务,ZStack可以在持续创新,开发出各种适应用户需求的应用场景的同时,保持架构的稳定和松耦合。
ZStack的整个架构并非离散的功能点的组合,而是在经过精密设计后相辅相成的。例如要实现查询API自动化,数据模型就必须预先定义完备;又比如要实现无锁架构,就必须要有无状态服务的基础。通过对架构的缜密思考,ZStack有信心解决当前IaaS行业面临的困难,为用户提供一款优秀的开源软件。
CSDN:OpenStack生态已经比较成熟,公有云私有云的成功案例都有了,我们为何还需要ZStack项目?
张鑫: IaaS领域是时候需要新鲜血液了。
自亚马逊2006年发布EC2公有云以来,IaaS(基础架构即服务)领域持续创新,先后出现了Eucalyptus, CloudStack,OpenNebula这样的开源软件。到2010年OpenStack出现,整个创新达到了一个高潮。从业者都认为云计算的春天来了,认为传统企业可以很快的从上个世纪的IT架构中解脱出来,迅速迁移到由软件定义的数据中心。但让人大跌眼镜的是,5年过去了,Eucalyptus, CloudStack,OpenNebula已渐渐淡出人们的视线,OpenStack一统天下,却迟迟打不开企业软件的市场。就在去年,OpenStack的发起者Rackspace,宣布不再以纯IaaS提供商的身份进入市场,而是转向专注于核心业务“为客户管理服务”,在跟以亚马逊为首的公有云巨头的竞争中败下阵来。最近,著名OpenStack公司Nebula倒闭,给出的理由是“市场不成熟”,更是给整个IaaS产业浇了一盆冷水。一时间各种悲观论调四起,例如认为企业云市场根本不存在,又例如公有云最终统治世界,企业不再需要自己维护数据中心。
我于2010年加入Cloud.com,作为CloudStack前核心开发人员,一直紧密的关注整个产业以及各个开源IaaS软件,深深感到市场的需求是巨大的,但当前的产品离市场的要求差距很远。随着时间的推移,这个鸿沟越来越大,丝毫没有减小的迹象。
当前开源IaaS软件的痛点可以概括为四个方面:易用性差,不稳定,性能差,难扩展。而这四个方面又是阻碍市场接受IaaS软件的至关重要的因素。根据我多年来对各个项目的观察,认为导致目前状况的原因,并不是开源社区缺乏有才能的开发人员,而是这些项目起源太早,缺乏对市场的足够理解。这些项目早期都是盲目模仿亚马逊EC2模式,在快速开发功能的同时自然生长,用俗话说就是“摸着石头过河”,导致了在架构设计方面思考过少,累积了大量欠账。而前述的几个方面,又正是不从架构入手重新设计,就不能解决的问题。但我们又不能期望像OpenStack这样拥有几百万行代码的项目从底部推到重来。基于这样的现实,我认为不重新设计一款IaaS软件是无法解决已有的问题的。在退出了原来CloudStack的工作后,我跟搭档一起建立了ZStack,希望从根源上解决当今IaaS软件遇到的各种问题,为整个行业带来一款真正能打开企业市场的软件
张鑫: ZStack的最终目的,并不是为喧闹的云市场添加更多的噱头,而是解决数据中心管理的一个刚需:即面对越来越多的硬件,如何管理它们,以及如何自动化这个管理的过程。我们相信终有一天,传统企业会摆脱人工手动配置或写脚本这种上个世纪的技术,将自身的IT架构迁移到完全通过API管理的,软件定义的数据中心中。此外,随着企业软件技术的不断创新,最终会是以SaaS(软件即服务)的方式在IT设施中部署。到那个时候,企业软件再不是为某个操作系统所设计的单机程序,而是为某个云设计的分布式程序。IaaS以及之上的PaaS就是这些企业软件的入口。依托ZStack的插件架构,我们完全相信我们可以逐步完善成一个涵盖IaaS和PaaS的平台,并且由于我们是IaaS和PaaS高度集成,提供的用户体验也必然优于同类软件间的第三方集成,从而成为未来企业软件的部署入口。
ZStack是一个开源项目,并且会一直坚持开源。我从2006年加入XEN社区到现在,就一直在开源领域工作,经历过不少成也开源败也开源的例子。例如OpenStack发迹于社区,但现在遇到了很多困难也源于社区。对于ZStack,我们欢迎任何形式的,基于Apache 2.0许可证的贡献。同时我们会负责维护ZStack核心稳定,对于提交到核心服务的代码进行严格控制。这样的代码会是少量的,因为在插件架构下,大部分功能会是以单独的插件方式实现。我们会推出两个目录:plugins和contribs。凡是ZStack自己的测试架构可以保证质量的插件,我们会放到plugins目录去,由我们承诺质量。对于测试架构无法保证的插件,例如需要特殊外设配合的插件,我们会放到contribs目录,表示用户在使用时需要自担风险。
总而言之,ZStack是个年轻的项目,是IaaS领域的一个新兵。但我们继承了先行者的经验,学到了先行者的教训,所以相信我们能比先行者走的更远。对于现有的IaaS项目,我们也不是扮演一个挑战者,而是为这个领域提供多一个选择。用我搭档的话说:我们不是蚂蚁与大象跳舞,我们是站在大象背上的蚂蚁,所以能看得更远。
编辑点评: 作为“站在大象背上的蚂蚁”,ZStack的插件式架构设计确有可圈可点之处。根据初步测试者的评价,ZStack也沿承了CloudStack的一些亮点。只是目前OpenStack的社区生态已经很成熟,虽然遇到各种难题,OpenStack还是在不断的实践中得到进步,被应用于各种公有云、私有云之中。例如金山云合伙人宋伟将在“ 2015 OpenStack技术大会 ”上分享“ Openstack 在公有云中的运用 ”, 分享金山云解决了哪些问题以及如何解决 。已经将OpenStack应用在生产环境中的用户,不太可能改换门庭。这意味着,虽有机遇,ZStack的初期发展同时还是会遇到很大的挑战。但正如张鑫所说,为这个领域提供多一个选择,总是一件好事。祝ZStack好运!(责编/周建丁)