2.ZStack的伸缩性秘密武器:无状态服务

Wesley13
• 阅读 700

每个ZStack服务都是无状态的,让服务高可用以及横向拓展(scale out)可以很简单,只需要启动剩余的服务实例,然后进行负载均衡即可。此外,ZStack将所有的服务打包到名为管理节点(management node)的单个进程,它让部署和管理变得超级简单。

动机

在ZStack的伸缩性秘密武器——一、异步架构(ZStack's Scalability Secrets Part 1: Asynchronous Architecture)一文中, 我们已经详细解释了异步架构,它让单个ZStack管理节点能胜任大多数的云端工作负载。然而,当用户希望建立高可用的生产环境,或者处理超级大的并发工作负载的时候,一个管理节点是不够的。解决方案是,构建一个分布式的系统,这样工作负载可以延展到每一个单一管理节点。这种增加新节点来拓展整个系统的容量的方式称为 横向拓展(scale out).

问题

设计一个分布式的系统并不容易。一个分布式的系统,特别是一个有状态的系统,必须处理一致性,可用性,以及分区容忍性(请查看 CAP理论(CAP theorem)),所有这些都很复杂。相反,一个无状态的分布式系统,在某种程度上摆脱了这种复杂性。首先,因为在节点之间无需状态共享,系统自然保持了一致性;其次,由于节点之间是类似的,当系统遇到一个分区问题通常也是OK的。鉴于此,一个分布式的系统,通常更倾向于保持无状态而不是有状态。但是,设计一个无状态的分布式系统也是很困难的,同时,常常比设计有状态的分布式系统更加困难。提升了消息总线(message bus)和数据库优势的ZStack,构建了一个包含了无状态服务的无状态分布式系统。

由于无状态服务是保证整个系统无状态的根基,在讨论它是什么之前,让我们先了解下什么是“状态”。在ZStack里面,资源,如主机,虚拟机,镜像,以及用户,都是由单个服务管理的;当系统中存在多余一个服务实例的时候,资源会被划分为不同的实例。例如,假如有10,000个虚拟机和两个虚拟机服务实例,理想的情况下,每个实例将会管理5000个虚拟机:

2.ZStack的伸缩性秘密武器:无状态服务

由于存在两个服务实例,在向虚拟机发送请求之前,请求者必须知道哪一个实例正在管理虚拟机;否则,它将无法知道将请求发往何处。像 ”哪个服务实例正在管理什么资源“ 的认知,正是我们正在谈论的状态。如果服务是有状态的,状态也就显现在服务之中。请求者需要在某个地方咨询这些状态。当服务实例的数目发生变化的时候,服务需要交换状态,例如,当一个新的服务实例加入,或者当前的服务实例脱离的时候。

2.ZStack的伸缩性秘密武器:无状态服务

状态交换是让人担忧的,它很容易导致错误,常常会限制系统的可拓展性。为了让系统更可靠,同时更易于横向拓展,理想的方式是,通过彼此分隔状态来让服务保持无状态(查看 服务无状态原则(Service Statelessness Principle)。 有了无状态的服务,请求者不再需要询问何处发送请求;当新的服务实例加入,或者旧的服务实例脱离的时候,服务也不再需要交换状态。

注意:在接下来的内容中,为了简单起见,术语“服务”和“服务实例”交换着使用。

服务和管理节点

服务,通过中央消息总线(central message bus)--RabbitMQ,来彼此通讯,它们是ZStack中的“第一等公民”。

2.ZStack的伸缩性秘密武器:无状态服务

不像通常的微服务架构,其每个服务都在单独的进程或单独的机器上运行,ZStack将所有的服务打包到一个名为管理节点的单一进程。对于这个号称 进程中的微服务(in-process microservices)架构,我们有充分的理由,你可以参看进程中的微服务架构(The In-Process Microservices Architecture)。

一个管理节点是一个完整功能的ZStack软件。由于包含了无状态服务,管理节点没有共享状态,但是有心跳记录,以及一致性哈希算法环(consistent hashing ring)--接下来我们将详细介绍。 心跳用来监控管理节点的“健康”(译者注:即此管理节点是否存活,是否正常运转),只要一个管理节点在给定的间隔内停止更新心跳,其它的管理节点将会驱除它,同时开始接管它所管理的资源。

2.ZStack的伸缩性秘密武器:无状态服务

无状态服务

实现无状态服务的核心技术,特别是对于ZStack的业务逻辑,就是一致性哈希算法(consistent hashing algorithm)。在启动的时候,每个管理节点都会被分配一个 版本4UUID(version 4 UUID)(管理节点UUID),它会和服务名一起,在消息总线上注册一个服务队列。例如,管理节点可能注册如下所示的服务队列:

zstack.message.ansible.3694776ab31a45709259254a018913ca
zstack.message.api.portal       
zstack.message.applianceVm.3694776ab31a45709259254a018913ca     
zstack.message.cloudbus.3694776ab31a45709259254a018913ca        
zstack.message.cluster.3694776ab31a45709259254a018913ca
zstack.message.configuration.3694776ab31a45709259254a018913ca   
zstack.message.console.3694776ab31a45709259254a018913ca
zstack.message.eip.3694776ab31a45709259254a018913ca     
zstack.message.globalConfig.3694776ab31a45709259254a018913ca    
zstack.message.host.3694776ab31a45709259254a018913ca    
zstack.message.host.allocator.3694776ab31a45709259254a018913ca  
zstack.message.identity.3694776ab31a45709259254a018913ca        
zstack.message.image.3694776ab31a45709259254a018913ca   
zstack.message.managementNode.3694776ab31a45709259254a018913ca  
zstack.message.network.l2.3694776ab31a45709259254a018913ca      
zstack.message.network.l2.vlan.3694776ab31a45709259254a018913ca
zstack.message.network.l3.3694776ab31a45709259254a018913ca      
zstack.message.network.service.3694776ab31a45709259254a018913ca
zstack.message.portForwarding.3694776ab31a45709259254a018913ca  
zstack.message.query.3694776ab31a45709259254a018913ca   
zstack.message.securityGroup.3694776ab31a45709259254a018913ca   
zstack.message.snapshot.volume.3694776ab31a45709259254a018913ca
zstack.message.storage.backup.3694776ab31a45709259254a018913ca

说明:你应该注意到,所有队列都以同样的UUID结尾,那是管理节点的UUID。

资源,如主机,容量,虚拟机,也是通过UUID来标识的。消息,常常和资源相关联,是在服务间传递的。在发送消息之前,发送者必须选择基于资源的UUID的接收者服务,这时,一致性哈希算法就开始登场了。

2.ZStack的伸缩性秘密武器:无状态服务

一致性哈希(Consistent hashing)是一种特别的哈希,当哈希表调整大小的时候,就会用到一致性哈希,其中只有一部分键(key)需要重新映射。关于一致性哈希的更多内容,更详细的请参阅 这里。在ZStack之中,管理节点由一致性哈希环组成,如下所示:

每个管理节点都维护一份一致性哈希环的拷贝,这个环包含了系统中所有管理节点的UUID。当管理节点加入或者脱离的时候,生命周期事件(lifecycle event)就会通过消息总线广播到其它节点,这样使得这些节点扩展或者收缩环,以呈现当前系统的状态。当发送消息的时候,发送者服务将使用资源的UUID,通过哈希的方式得出目标管理节点的UUID。例如,发送VM的UUID为932763162d054c04adaab6ab498c9139的StartVmInstanceMsg,伪代码如下:

msg = new StartVmInstanceMsg(); destinationManagementNodeUUID = consistent_hashing_algorithm("932763162d054c04adaab6ab498c9139"); msg.setServiceId("vmInstance." + destinationManagementNodeUUID); cloudBus.send(msg)

如果有一个稳定的环,那么包含同样资源UUID的消息就总是会路由到某个管理节点上同样的服务,这就是ZStack无锁架构的基础(参阅 ZStack的伸缩性秘密(第三部分):无锁架构(Stack's Scalability Secrets Part 3: Lock-free Architecture)。

2.ZStack的伸缩性秘密武器:无状态服务

当一致性哈希环收缩或释放的时候,由于一致性哈希的特性,只有少数节点受到轻微影响。

由于一致性哈希环,发送者无需知道哪一个服务实例即将处理消息;取而代之的是,这将会被处理掉。服务无需维护和交换,关于它们正在管理什么资源的信息;它们所需要做的就是,处理即将到来的消息,因为环能够保证消息找到正确的服务实例。这就是服务如何变得超级简单和保持无状态的。

除包含资源UUID的消息之外(如 StartVmInstanceMsg, DownloadImageMsg),也有一类无资源UUID的消息,通常是创建型的消息(如 CreateVolumeMsg)和非资源消息(如 AllocateHostMsg)--它们不会操控单独的资源。考虑到这些消息可以发送到任意管理节点的服务,它们可能被故意发送到本地的管理节点,由于发送者和接收者在同样的节点,当发送者发送消息的时候,接收者当然也是可达的。

对 API 消息(例如:APIStartVmInstanceMsg)来说,有一个特殊的处理,它们总是发送一个众所周知的服务 ID api.portal 。在消息总线上,一个全局的队列被叫做 zstack.message.api.portal ,它被所有的管理节点 API 服务所共享,消息服务 ID api.portal 将会自动对其中的一个API服务做负载均衡,这个服务还会路由转发消息到正确的目的地,并使用了一致性哈希环(consistent hashing ring)。通过这种做法,ZStack 隐藏了来自 API 客户端消息路由转发的细节,并简化了写一个ZStack API 客户端的工作。

msg = new APICreateVmInstanceMsg()
msg.setServiceId("api.portal")
cloudBus.send(msg)

2.ZStack的伸缩性秘密武器:无状态服务

摘要

在这篇文章中,我们证明了Zstack 构建伸缩性的分布式系统。因为管理节点共享的信息比较少,很容易建立一个大的集群,可能有几十个甚至几百个管理节点。然而实际上,在私有云方面,两个管理节点可以有很好的扩展性;在公共云方面,管理员能根据工作量创建一个管理节点。依靠异步架构和无状态的服务,Zstack能够处理大量的并发任务,现有的IaaS软件则不能处理。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Android蓝牙连接汽车OBD设备
//设备连接public class BluetoothConnect implements Runnable {    private static final UUID CONNECT_UUID  UUID.fromString("0000110100001000800000805F9B34FB");
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这