ZStack 的伸缩性秘密(第一部分)异步架构

ZStack 核心架构设计使得 99% 的任务异步执行,因此确保了单个的管理节点能够管理十万级的物理服务器,百万级的虚拟机,数万级的并行任务。

架构的创新动力

对于要管理大量的硬件和虚拟机的公有云,伸缩性是IaaS软件要解决的主要问题之一。一个中等规模的数据中心,可能会有50.000台物理服务器,大约1,500,000的虚拟机,举例来说,同时分属于10000用户。虽然,用户不太可能象刷新Facebook页面一样开/关虚拟机,但是IaaS 系统还是会在某个时刻被数千任务拥塞,这些任务有来自API的,还有来自内部组件的。在某些更糟糕的情况下,一个用户可能会等一个小时才能创建虚拟机,就是因为系统线程池只有1000,而等待处理的任务有5000个。

问题

首先,我们明确反对某些文章中的观点,针对 IaaS 伸缩性问题归结于,其声称 “支撑基础,特别是数据库和消息代理是 IaaS 伸缩性的问题的罪魁祸首”。 这完全是错误的!首先,就数据库的规模来讲,其顶多算是小型和中型;像 Facebook 和 Twitter 这样的互联网巨头,还在拥 MySQL 作为其主数据库。IaaS 的数据难道超过了 Facebook 或 Twitter 吗?完全不可能,他们是十亿级,IaaS 只有百万级(超级数据中心)。其次,相较与 Apache Kafka 或者 ZeroMQ 此类的消息代理服务器,ZStack 所应用的 RabbitMQ 只能算是一个中等伸缩性的代理。但是,其依然可以保持每秒 50.000 的消息处理量。(参考,RabbitMQ 性能测试 , part 2)。难道这在 IaaS 软件系统中做通信还不够吗?完全足够。

其实,IaaS 伸缩性问题的根源在于:任务处理慢。确实是,在 IaaS 软件系统中任务处理非常慢,慢到要有几秒甚至是几分钟才能完成。因此,当系统中全是这种慢慢处理的任务时候,当然就带来了新任务的巨大的延迟。而这种慢处理的任务源于任务路径过长。举例说明,创建虚拟机,一般要经过以下路径 身份服务(service)-->规划器(scheduler)-> 图象服务(service)->存储服务->网络服务->系统管理(Hypervisor); 每个服务都会花费几秒甚至几分钟来操作外部硬件,这就导致了超长的任务处理时长。

同步 vs 异步

传统的 IaaS 软件系统同步处理任务;其往往是基于线程池机制。在此机制下,线程分配给每一个任务,只有当前任务结束后,下一个任务才能被处理。因为,任务处理缓慢,在遇到并行任务的峰值时, 系统由于超过了线程池的极限所以变的很慢,新来的任务只能缓存排队。

解决之道,直观的认为要增加线程池的容量;不过,现在操作系统虽然可以允许程序启动数万的线程,但是调度效率很低。因此,人们就开始做横向扩展,把处理任务分布在类似软件程序上,这些程序驻留在不同操作系统上;因为每个程序拥有其独有的线程池,从而最终增加了整个系统的线程池的容量。但是,以上横向扩展的方案带来了成本问题,其加大了管理的难度,并且,从软件设计的角度讲,集群软件本身也还是不小的挑战。最后,虽然其他的包括数据库,消息代理和外部系统(例如,成千的物理服务器)在内的基础设施有足够的能力来服务于更多的并行任务,但是IaaS软件系统本身变成了云系统的瓶颈。

ZStack 通过异步架构来解决这个问题。如果,我们考虑 IaaS 软件系统和数据中心其他设施的关系,IaaS 软件系统其实是一个中间人的角色。其协调外部系统但不做时实的任务;例如,IaaS 不作具体工作,而是存储系统创建物理卷,镜像系统下载模板,虚拟机由虚拟管理系统创建。那么,IaaS 实际的工作任务就是决定如何分发子任务(sub-tasks)给外部系统。例如,对 KVM,子任务就包括了准备逻辑卷,网络和创建虚拟机,这些子任务都是 KVM 主机实施的;这个过程可能花费5秒钟,其中 IaaS 软件 0.5s, 其余 4.5s 被 KVMz 主机占用。根本上,ZStack 的异步架构确保了不用等这 4.5s,而是仅仅用0.5s 来选择执行的 KVM 主机,然后把任务分发出去。一旦,KVM 主机完成了指定的任务,它就会通知 IaaS 管理软件。以异步架构的方式,一个 100 线程的线程池就能轻松处理数千的并行任务。

ZStack 的异步方式

异步操作在计算机世界很普遍;异步 I/O, AJAX(Asynchronous Javascript And XML 异步的(Javascript 和 XML)是广为人知的例子。然而,要构建异步的全业务逻辑,特别象是 IaaS 这样的集成软件,仍然由很多挑战 。

最大的挑战在于,不是部分,而是全部的组件都要实现异步;例如,如果只是构建一个异步存储服务,但其他相关服务都是同步。那么,整个系统还是没有多少优势。这是因为,要调用存储服务,即使它是异步的,调用方的服务还是不得不等待其结束,那么整个工作流依然是同步的。

图:线程中,业务流程服务要调用存储服务,直到存储服务返回了,线程才能结束。 虽然,存储服务通过异步方式和外部存储系统交互。

ZStack's 异步架构包含三部分: 异步消息,异步方法,异步 HTTP 调用。

1. 异步消息

ZStack 使用 RabbitMQ 作为消息总线以便连接各个服务。当某个服务调用另一个服务时,源服务发消息给目的服务并注册一个回调函数,然后马上返回;一旦目的服务完成了任务,它就会通过触发回调函数来回复任务结果。

AttachNicToVmOnHypervisorMsg amsg = new AttachNicToVmOnHypervisorMsg();
amsg.setVmUuid(self.getUuid());
amsg.setHostUuid(self.getHostUuid());
amsg.setNics(msg.getNics());
bus.makeTargetServiceIdByResourceUuid(amsg, HostConstant.SERVICE_ID, self.getHostUuid());
bus.send(amsg, new CloudBusCallBack(msg) {
    @Override
    public void run(MessageReply reply) {
        AttachNicToVmReply r = new AttachNicToVmReply();
        if (!reply.isSuccess()) {
            r.setError(errf.instantiateErrorCode(VmErrors.ATTACH_NETWORK_ERROR, r.getError()));
        }
        bus.reply(msg, r);
    }
});

单个服务也可以发送一串消息给其他服务 ,并异步的等待回复。

final ImageInventory inv = ImageInventory.valueOf(ivo);
final List<DownloadImageMsg> dmsgs = CollectionUtils.transformToList(msg.getBackupStorageUuids(), new Function<DownloadImageMsg, String>() {
    @Override
    public DownloadImageMsg call(String arg) {
        DownloadImageMsg dmsg = new DownloadImageMsg(inv);
        dmsg.setBackupStorageUuid(arg);
        bus.makeTargetServiceIdByResourceUuid(dmsg, BackupStorageConstant.SERVICE_ID, arg);
        return dmsg;
    }
});

bus.send(dmsgs, new CloudBusListCallBack(msg) {
    @Override
    public void run(List<MessageReply> replies) {
        / do something /
    }
}

更进一步,也能发送具有一定并行性的消息串。 比如,一串十个的消息,能够两两发送,第三,第四个消息只有第一,第二个消息收到后在一起发出。

final List<ConnectHostMsg> msgs = new ArrayList<ConnectHostMsg>(hostsToLoad.size());
for (String uuid : hostsToLoad) {
    ConnectHostMsg connectMsg = new ConnectHostMsg(uuid);
    connectMsg.setNewAdd(false);
    connectMsg.setServiceId(serviceId);
    connectMsg.setStartPingTaskOnFailure(true);
    msgs.add(connectMsg);
}

bus.send(msgs, HostGlobalConfig.HOST_LOAD_PARALLELISM_DEGREE.value(Integer.class), new CloudBusSteppingCallback() {
    @Override
    public void run(NeedReplyMessage msg, MessageReply reply) {
        / do something /
    }
});

2. 异步方法

ZStack 服务,就像以上段一所示,它们之间通过异步消息通信; 对于服务内部,一系列的互相关联的组件,插件是通过异步方法调用来交互的。

protected void startVm(final APIStartVmInstanceMsg msg, final SyncTaskChain taskChain) {
    startVm(msg, new Completion(taskChain) {
        @Override
        public void success() {
            VmInstanceInventory inv = VmInstanceInventory.valueOf(self);
            APIStartVmInstanceEvent evt = new APIStartVmInstanceEvent(msg.getId());
            evt.setInventory(inv);
            bus.publish(evt);
            taskChain.next();
        }

        @Override
        public void fail(ErrorCode errorCode) {
            APIStartVmInstanceEvent evt = new APIStartVmInstanceEvent(msg.getId());
            evt.setErrorCode(errf.instantiateErrorCode(VmErrors.START_ERROR, errorCode));
            bus.publish(evt);
            taskChain.next();
        }
    });
}

同样, 回调也能包含返回值:

public void createApplianceVm(ApplianceVmSpec spec, final ReturnValueCompletion<ApplianceVmInventory> completion) {
    CreateApplianceVmJob job = new CreateApplianceVmJob();
    job.setSpec(spec);
    if (!spec.isSyncCreate()) {
      job.run(new ReturnValueCompletion<Object>(completion) {
          @Override
          public void success(Object returnValue) {
            completion.success((ApplianceVmInventory) returnValue);
          }

          @Override
          public void fail(ErrorCode errorCode) {
            completion.fail(errorCode);
          }
      });
    } else {
        jobf.execute(spec.getName(), OWNER, job, completion, ApplianceVmInventory.class);
    }
}

3. 异步HTTP调用

ZStack 使用了很多代理来管理外部系统。 例如: 管理 KVM 主机的代理,管理 Console Proxy 的代理,管理虚拟路由的代理等等。这些代理都是构建在 Python CherryPy 上的轻量级的 Web 服务器。因为,没有类似 HTML5 中的 Web Sockets 技术就不能实现双向通信,ZStack 就为每个请求,放置了一个回调 URL 在 HTTP 的包头 。这样,任务结束后,代理就能够发送应答给调用者的 URL。

RefreshFirewallCmd cmd = new RefreshFirewallCmd();
List<ApplianceVmFirewallRuleTO> tos = new RuleCombiner().merge();
cmd.setRules(tos);

resf.asyncJsonPost(buildUrl(ApplianceVmConstant.REFRESH_FIREWALL_PATH), cmd, new JsonAsyncRESTCallback<RefreshFirewallRsp>(msg, completion) {
    @Override
    public void fail(ErrorCode err) {
        / handle failures /
    }

    @Override
    public void success(RefreshFirewallRsp ret) {
        / do something /
    }

    @Override
    public Class<RefreshFirewallRsp> getReturnClass() {
        return RefreshFirewallRsp.class;
    }
});

通过这三个异步方式,ZStack 已经构建了一个分层架构,保证所有组件能够实现异步操作。

总结

此文,我们阐述了 ZStack 的异步架构,此架构解决了由于并行任务慢而导致的 IaaS 伸缩性问题。在测试中,使用模拟器,在单 ZStack 管理节点中,1000 线程就能轻易处理创建 1,000,000 虚拟机的10.000 个并行任务。除了单节点具有足够伸缩性处理大部分云系统负载的优点外,想要支持高可用行(High Availability)或者朝大规模负载(比如,100,000 并行任务),就必须安装多个管理节点。请参考 ZStack's stateless service in ZStack's Scalability Secrets Part 2: Stateless Services。

文章转载自 开源中国社区[https://www.oschina.net]

时间: 2024-10-31 19:26:17

ZStack 的伸缩性秘密(第一部分)异步架构的相关文章

BrnShop开源网上商城第一讲:架构设计

原文:BrnShop开源网上商城第一讲:架构设计 首先在此感谢大家对BrnShop项目的支持和鼓励!我们在发布BrnShop以前曾推测项目会受到不少园友的支持,但没想到园友们的支持大大超过我们的预测.4天6000次浏览,140个推荐,170个评论,8000次下载.看到这些数据后我们内心除了激动外,更多了一份责任.无论将来遇到多大的困难,我们一定要坚持把BrnShop坚持到底!! 如果你还不知道BrnShop是什么或还没有下载源码的可以点此下载,如果下载源码后发现商城有bug,也可以点此下载(什么

《软件架构模式》-第一章分层架构(上)

第一章 分层架构 最通常的架构模式就是分层架构模式,即所谓的N层架构.这种模式对大部分JAVAEE应用程序来说是标准模式,因此被大部分架构师.软件设计师.开发者广泛知晓.由于分层架构模式和公司里传统的IT沟通以及组织结构非常类似,使得它成为大多数商务应用开发最自然的选择. 模式描述 在分层架构模式中,它将应用分成多个水平层,每个水平层在应用中担任一个专门的角色(比如表现层或者业务逻辑).尽管分层架构模型并没有指定必须的层次个数以及类型,但大部分这种模型都由4个标准层次构成:表现层.业务层.持久层

第一章——计算机系统架构介绍

1 介绍 计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决. 计算机系统u燃机系统结构的层次结构设计如下:   每个层次之间都需要相互通信,既然需要通信就必须有一个通信的协议,也就是接口.一般接口的下面那层就是接口的提供者,接口由它定义:接口的上层就是接口的使用者,它使用该接口来实现需要的功能. 例如,从整个层次结构来看,开发工具与应用程序属于同一层次,它们都是要运行库提供的接口,也就是应用程序编程接口.应用程序接口的提供者就是运行库,什么样的运行库提供什么样的API.而对于操作系统

架构师速成-架构目标之伸缩性\安全性

为满足伸缩性,所需的架构模式包含: 分布式,这个前面有单独的章节进行了讲解,分布式是互联网时代的主旋律. 负载均衡,前面已经有讲解. 服务拆分,按照业务进行系统服务的拆分并单独部署. 为满足伸缩性,需要的支撑系统: 运维系统: 自动扩容,缩容 监控系统 监控流量,确定何时伸缩 为满足安全性,所需的架构模式包含: 数据加密,密码的加密存储.关键数据的加密传输,才有https. 数据校验,数据传输时,同时传递明文和密文校验数据未被篡改.前端及后端进行数据的有效性校验,比如数字.日期等. 为满足安全性

交互设计师怎样理解信息架构?

  今天分享一篇交互设计高级教程,关于产品信息架构的思考,这方面是交互设计师成长的一个关键点,也是交互设计大局观的锤炼基石,文章很有深度,值得用心学习. 这篇适合交互设计或者对交互设计感兴趣的小伙伴们看.所以我就不解释信息架构是什么了.今天写一下产品信息架构的思考. 任何产品都有信息架构,或繁杂或简单.在文中讨论的时候,我大致把信息架构分为两种来例证.一种是比较简单的信息架构,例如大多ToC产品,微信.QQ音乐.腾讯视频等;一种是比较复杂的信息架构,例如大多ToB产品,运维类产品.客户关系管理系

深度解读:ZStack混合云如何实现网络互联互通?

近年来,得益于SDN的快速发展,数据中心建设不再与用户业务绑定,而将网络互联的任务交给IaaS服务商来完成.ZStack做为IaaS云服务商中的一员,从ZStack 1.8版本开始,ZStack云路由就开始承担起日益复杂的网络建设任务.随着越来越多的用户将业务迁移云上,ZStack也开始支持越来越多复杂的网络功能.  部署混合云,网络打通是难点 从当前市场趋势以及Gartner.IDC等权威调研机构的研究显示,已经有越来越多的企业将目光从私有云转向混合云.然而,部署混合云意味着业务将面临更加复杂

实施微服务架构的关键技术

大家都在提微服务架构,微服务架构到底是什么?它有哪些特点和设计模式?我们在打造微服务架构过程中,这些设计模式在实战当中如何应用?数据的一致性应该如何保证?今天我将针对上述疑问分享一下我的思考. 微服务架构特点 什么是微服务架构?看下图的这段英文,这是Martin Fowler 在2014年提出来的,微服务架构是一种架构模式,既然是架构模式,那么,它就必然需要满足一些特点.他提到,微服务架构是一系列小的微服务构成的组合,那么,什么是"小的微服务"?可能每个人的理解都不一样,大家都应该都知

从零到百亿互联网金融架构发展史---架构变迁

回想起从公司成立敲出的第一行代码算起到现在也快三年了,平台的技术架构,技术体系也算是经历了四次比较重大的升级转化(目前第四代架构体系正在进行中),临近年底也想抽出时间来回顾一下,一个小公司从最开始的零交易到现在交易量超过百亿背后的技术变迁.   总体介绍 在互联网金融行业一百多亿其实也算不上大平台,也就是二级阵营吧,其实每次的架构升级都是随着业务重大推进而伴随的,在前一代系统架构上遇到的问题,业务开发过程中积累一些优秀的开发案例,在下一代系统开发中就会大力推进架构升级.一方面可以平滑过度,一方面

针对架构设计的几个痛点,我总结出的架构原则和模式

[编者的话]本文来自Firat Atagun的<架构演化中的软件设计原则>,文中给出了软件架构演化过程中出现的4种经典架构,就每种架构,分析了其主要特点并在几个度量维度给出结论.在文章的最后,Firat Atagun给出了4种架构的多维对比.本文的完整演讲稿是架构演化中的软件设计原则. 1 分层架构 分层架构是最常见的架构,也被称为n层架构.多年以来,许多企业和公司都在他们的项目中使用这种架构,它已经几乎成为事实标准,因此被大多数架构师.开发者和软件设计者所熟知. 分层架构中的层次和组件是水平