热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

openstack查看虚拟机在那个项目_从消息队列看OpenStack

点击上方“腾讯云TStack”关注我们获取最in云端资讯和海量技术干货本文作者:鹏飞专注于OpenStack计算、Python。热爱大海、雪山。以往介绍opensta

点击上方“腾讯云TStack”关注我们

获取最in云端资讯和海量技术干货

36665296c998fe6a3a2d6d0a0fd48cc2.png54cfa8e3ba64b4f1c4670f6b8587eff7.png

本文作者:鹏 飞

专注于OpenStack计算、Python。

热爱大海、雪山。

以往介绍openstack的文章通常都是从各个组件的整体角度来进行介绍,并没有深入的介绍组件内部服务究竟是如何通信的。

本文这次将换一个角度,从消息队列的角度来看openstack。文章将以pike版本中的nova组件为例进行介绍,由于openstack中所有组件内部服务的通信方式都是一致的,因此下面的内容也同样适用于其它组件,如neutron、cinder等。

4992f6312b92b442b16474f7bdc8ce19.gif

Nova整体架构

ec1d2e5c6fd6654376c7ba64120da562.gif下面这个图只画出了nova组件中最核心的4个服务,即nova-api、nova-conductor、nova-scheduler和nova-compute。服务之间通过消息队列,即图中的mq进行通信(这里的mq几乎默认都是rabbitmq)。其中api、conductor、scheduler服务都可以配置多进程、多副本以实现服务的高可用和高并发,而compute服务的数量则可能多达上千个。54303af40a1e3a5053ebff56582338d7.png386330aa2e66f1bdbb839e8cfcf8b015.png在nova组件的众多功能中,创建虚拟机功能应该是最能够说明nova组件内部协作的功能了。创建虚拟机时,nova-api服务接收到来自用户的http请求,在进行一些必要的处理之后,通过消息队列将创建流程转交给nova-conductor,之后nova-api会给用户返回响应,而不会等待虚拟机创建完成,虚拟机创建将进入后台运行阶段。nova-conductor服务从消息队列中收到虚拟机创建请求后,将会进入一个长时间的虚拟机创建流程。首先nova-conductor将会通过消息队列调用nova-scheduler,为虚拟机选择一个可用的计算节点;之后又会通过消息队列将创建请求发送给nova-compute服务。nova-compute服务在收到虚拟机创建请求后,会执行一系列的虚拟机创建操作,其中还包括更新数据库。但更新数据库并不是由nova-compute自己实现,而是会通过消息队列将更新数据库操作委托给nova-conductor,由nova-conductor代理完成。以上就是虚拟机创建流程的一个简要说明,从创建流程中可以看到,消息队列对于openstack至关重要。再举一个虚拟机启动的例子,启动虚拟机时nova-api服务将收到来自用户的http请求,之后nova-api将会通过消息队列将虚拟机启动请求发送给虚拟机所在的计算节点,对应计算节点上的nova-compute服务将会收到启动请求,并将指定的虚拟机启动。但有时候可能会遇到这样的问题,就是通过nova service-list命令看到某个计算节点上的nova-compute服务明明是up的(这表明计算节点上的nova-compute服务是正常运行的,同时还能够正常的上报数据到nova数据库中),但是执行虚拟机启动操作时却没有任何效果,观察nova-compute服务日志找不到任何相关的记录,同时虚拟机卡在启动状态中。对于此类问题,仅仅通过前面的介绍是无法知道根本原因的,必须要进入到消息队列层面才能够明白为什么会发生这类问题。4992f6312b92b442b16474f7bdc8ce19.gif4992f6312b92b442b16474f7bdc8ce19.gif

从MQ来看Nova

ec1d2e5c6fd6654376c7ba64120da562.gif注: 在openstack中,默认使用的消息队列是rabbitmq,因此下面的内容全部基于rabbitmq,关于rabbitmq的基础知识可以在官方文档:https://www.rabbitmq.com/getstarted.html中找到。打开rabbitmq management页面,在Exchanges标签页下面可以看到很多的rabbitmq exchange,如下图所示(由于篇幅限制,图中只过滤显示了部分exchange)。其中与openstack相关的exchange主要分为3类:
  • 以nova、neutron、openstack等命名的exchange;
  • 以reply开头的exchange;
  • 以fanout结尾的exchange;
下面会依次说明这3类exchange的作用。另外还有一些以amq开头的exchange,这些是rabbitmq默认的exchange,在openstack中不会使用,因此不用关注。865f7c37e55f52979e84fbcc082efcff.png4992f6312b92b442b16474f7bdc8ce19.gif

nova exchange

ec1d2e5c6fd6654376c7ba64120da562.gif以组件名称命名的exchange是各个组件内部服务之间通信的核心。下面这个图显示了一个controller节点(控制+计算融合节点)和一个单独的compute节点组成的openstack环境中nova exchange的具体内容。54303af40a1e3a5053ebff56582338d7.png072f9fb6ee7d3370ae13f6aef38debd8.png图中第1部分定义了当前exchange的名称,不同的openstack项目,其exchange的名字不同,但通常和项目的名称一致(cinder默认的exchange名称为openstack,可以通过cinder.conf进行修改;但对于nova和neutron这两个项目,则都是在代码中写死的)。对于nova项目,可以在nova/config.py中找到默认的exchange名称定义。第2部分指明了nova exchange的type为topic类型(即主题交换机)。rabbitmq支持3种类型的交换机,分别是direct、fanout和topic,关于这三种交换机类型可以从rabbitmq的官方文档中找到详细的说明,在后面的内容中也将简要的说明这几种交换机的特点。第3部分则展示了当前连接到nova exchange上的所有队列。其中To所在列表示当前连接到nova交换机的所有队列名称,Routing key则指明了nova交换机与指定队列之间的关联关系。当客户端发送消息给nova exchanges时:
  • 如果指定了路由关键字为compute.controller,则消息将被发送到compute.controller队列中;
  • 如果指定了路由关键字为scheduler.controller,则消息将被发送到scheduler.controller队列中;
还可以点击图中的队列名称,进一步查看队列的详细信息,下图是scheduler.controller队列的部分信息,其中包括当前在队列中的消息数量,向队列中添加消息的速率以及消费速率等信息。红框部分则表明了当前连接到队列的消费者,该消费者来自192.168.60.211节点,对应40054端口的进程。通过命令ss -pn | grep 40054可以看到该进程实际上就是nova-scheduler服务进程。8592d60cfba65ad8d64f277724326de9.png通过前面观察rabbitmq中的exchange以及队列等信息,我们可以画出生产者、消息队列、消费者之间的简要关系。图中最左边部分画出了集群中部分nova服务进程,此处这些nova服务进程的作用是作为生产者向rabbitmq发送消息;中间灰色线框部分是rabbitmq;最右边部分也是集群中的nova服务进程,它们和左边的生产者实际上是相同的进程,只不过在此处它们作为消费者接收并处理指定队列中的消息。(nova组件中的服务即是生产者,也是消费者)54303af40a1e3a5053ebff56582338d7.png0600c4a19fa0beaffa26587fd938c776.png以上一章节中提到的虚拟机启动为例,根据这里的消息队列模型再看一下虚拟机的启动流程,按照上图红色部分从左向右。首先controller节点上的nova-api服务进程收到来自用户的虚拟机启动请求;nova-api查询到虚拟机位于计算节点compute上,因此构造rpc请求消息,将消息发送给nova exchange,并指定routing keycompute.compute;消息将根据路由键被发送到compute.compute队列中;最终绑定并消费该队列的nova-compute服务(计算节点compute上的进程)将获取到消息,并调用相应的函数执行虚拟机开机操作。相关的rpc调用代码可以在nova/compute/rpcapi.py中找到

# 1. nova-compute服务默认的rpc topicRPC_TOPIC = "compute"@profiler.trace_cls("rpc")class ComputeAPI(object): def __init__(self): super(ComputeAPI, self).__init__() # 2. 所有nova-compute服务都默认将消息发送到compute topic target = messaging.Target(topic=RPC_TOPIC, version='4.0') #... # 3. 启动虚拟机涉及的rpc调用方法 def start_instance(self, ctxt, instance): version = '4.0' # 4. _compute_host(None, instance)将会返回虚拟机所在计算节点主机名,因此最终消息将会发送 # 给compute.队列,如果不指定server参数,则消息将被发送给compute队列 cctxt = self.router.client(ctxt).prepare( server=_compute_host(None, instance), version=version) # 5. 此处cast表明是异步rpc调用,即只是将消息发送给nova-compute服务,不等待计算节点执行完成 cctxt.cast(ctxt, 'start_instance', instance=instance)4992f6312b92b442b16474f7bdc8ce19.gif

replay exchange

ec1d2e5c6fd6654376c7ba64120da562.gif在前面虚拟机启动相关的rpc调用函数中提到cctxt.cast方法是用于异步rpc调用的,即不会等待被调用方执行完成。在openstack中,还有另外一种rpc调用,即同步rpc调用,对应的方法为cctxt.call,该方法被执行后,将会等待被调用方执行完成。下面的代码同样来自nova/compute/rpcapi.py文件,该方法用于获取计算节点的运行时间。

# 获取计算节点的运行时间def get_host_uptime(self, ctxt, host): version = '4.0' # 通过server参数,指定将rpc调用请求发送给哪个队列,相应的计算节点将会收到消息并处理 cctxt = self.router.client(ctxt).prepare( server=host, version=version) # 同步rpc调用`cctxt.call`会等待被调用方执行完成并返回结果 return cctxt.call(ctxt, 'get_host_uptime')将查询主机运行时间的rpc消息发送给指定的计算节点,这一过程与前面一节是完全一样的。不同点在于同步rpc调用与异步rpc调用,同步rpc调用由于需要获取远端方法的执行结果,因此需要有一种方法能够将远端方法的执行结果返回给调用者。关于这一过程的实现原理可以参考rabbitmq官方文档: https://www.rabbitmq.com/tutorials/tutorial-six-python.html用通俗易懂的方式来说就是,同步rpc调用时,客户端在发送给服务端的请求中,还会附加一个队列的名字,该队列用于告诉服务端,在方法执行完成后将执行结果发送到我给你的队列里面。而客户端在发送了rpc调用请求后,则会一直监听用于返回结果的队列,直到有结果返回或者响应超时。(在返回结果时,原来的服务端变成了消息的生产者,客户端变成了消息的消费者。)在这里提到的用于返回函数执行结果的队列,就是那些以reply开头的队列,后面跟着一个随机生成的uuid。这些队列不是绑定到nova exchange上的,而是为这些reply队列创建了同名的exchange,这些exchange的类型为direct类型。并且在服务第一次调用call方法时会生成该队列,之后在服务重启之前会一直使用该队列作为reply队列。至此,同步rpc调用的简要流程可以通过下面这个图简要的表示出来8bbdb2a3df97263459dc3472fb1219e8.png4992f6312b92b442b16474f7bdc8ce19.gif

fanout exchange

ec1d2e5c6fd6654376c7ba64120da562.gif以fanout结尾的exchange的作用是对所有相关的服务进行广播,以nova-scheduler服务为例,当有多个nova-scheduler服务进程时,每个nova-scheduler进程都会生成一个队列并绑定到scheduler_fanout exchange上。在通过这个scheduler_fanout进行消息广播时,所有的nova-scheduler进程都将接收到消息。下图是在一个控制节点上启动了3个nova-scheduler进程时,与scheduler_fanout exchange绑定的队列0f1633fcd838affc134bf200d451f24c.png54303af40a1e3a5053ebff56582338d7.png使用广播给服务发送消息的方式,在nova中主要用于通知nova-scheduler服务更新缓存信息,比如通知所有的nova-scheduler服务进程更新主机可用域信息。在用户调用nova-api接口修改主机所在可用域的时候,nova-api服务就会通过广播的方式将计算节点的可用域信息广播给所有的nova-scheduler服务进程,使得nova-scheduler服务能够及时的更新内存中缓存的可用域信息,以便于正确的完成虚拟机调度。下面的代码来自nova/scheduler/rpcapi.py文件,其作用就是通过广播的方式通知所有nova-scheduler服务进程完成内存数据的更新

def update_aggregates(self, ctxt, aggregates): # 通过fanout参数指定操作为广播操作 cctxt = self.client.prepare(fanout=True, version='4.1') cctxt.cast(ctxt, 'update_aggregates', aggregates=aggregates)这里同样使用一个图来简要的表示一下fanout exchange与nova服务之间的关系。下面这个图展示了在有两个控制节点,且每个控制节点上都有两个nova-scheduler进程时的scheduer_fanout exchange及其绑定的队列信息。从图中可以看到,每个nova-scheduler服务都会有一个队列连接到scheduler_fanout exchange上。因此nova-api在进行广播消息时,每个scheduler_fanout_队列里面都将收到消息,所有的nova-scheduler服务进程都能够处理消息。54303af40a1e3a5053ebff56582338d7.pnga76e53ba20024900056be6f9a8d88a88.png4992f6312b92b442b16474f7bdc8ce19.gif

Nova高可用

ec1d2e5c6fd6654376c7ba64120da562.gifnova组件的高可用分为两种,一种是以暴露端口对外提供http调用的服务,比较典型的是nova-api服务,另外还有像placement服务和nova-novncproxy服务;第二种就是像nova-scheduler、nova-conductor这样的服务,这些服务是通过消息队列来接收和处理请求的。对于nova-api这样通过http对外提供接口的服务,高可用可以借助keepalived+haproxy这样的组合来完成服务的高可用和横向扩展。但本文的主要目的是从MQ来看openstack,因此nova-api这样的服务的高可用并不是本文的重点,这里想要介绍的是nova-scheduler、nova-conductor这些服务的高可用和横向扩展是如何实现的。下面将以nova-scheduler服务为例进行介绍。nova-scheduler服务是用于虚拟机调度的组件,如果仅在一台主机上进行部署,则很容易出现单点故障。在实际的部署中,通常会将其部署在3台不同的物理主机上,以实现服务的高可用,同时还能提高虚拟机调度的并发性能(python进程cpu使用率不能超过100%,对于以计算为主的nova-scheduler服务,会严重限制其并发处理性能,必须通过多进程的方式实现高并发)。在前面介绍nova exchange时提到有一个scheduler队列,该队列会被所有的nova-scheduler服务进程消费,如下图所示fb0cbb8b5d9f69b9533c789ce242a7d5.pngcontroller01~03节点上的nova-scheduler服务进程都会消费scheduler队列,当有消息被发送到scheduler队列中时,将会由一个进程获取到该消息并进行处理。当controller02节点上的nova-scheduler服务发送异常时,消息将会由controller01或controller03节点上的nova-scheduler服务消费。这就是nova-scheduler服务的高可用实现,同时由于有3个nova-scheduler进程在同时消费scheduler队列中的数据,因此消息的处理速度也得到了很大的提升,从而提升了虚拟机调度的并发性能。下面的代码来自nova/scheduler/rpcapi.py,其功能就是通过rpc同步调用nova-scheduler完成虚拟机的调度

# 1. 通过rpc同步调用nova-scheduler完成虚拟机调度,通常由nova-conductor服务发起调用def select_destinations(self, ctxt, spec_obj, instance_uuids): version = '4.4' #... # 2. 注意这里prepare方法没有指定server参数,因此消息将被发送给scheduler队列。 # 如果指定了server=controller01,则消息将被发送给scheduler.controller01队列,此时 # 虚拟机调度请求消息将只能被controller01节点上的nova-scheduler服务进程获取并处理。 cctxt = self.client.prepare(version=version) # 3. rpc同步调用,等待虚拟机调度结果 return cctxt.call(ctxt, 'select_destinations', **msg_args)4992f6312b92b442b16474f7bdc8ce19.gif

Nova健康检查

ec1d2e5c6fd6654376c7ba64120da562.gif最后介绍一下如何去判断nova服务是否在正常运行。同nova高可用部分一样,这里对nova的健康检查也分为两种情况,一种是提供http接口的服务,这类服务可以简单地通过curl等命令进行服务状态检查,比如通过curl命令访问8774端口,然后检查一下返回的状态码即可知道nova-api服务是否正常运行;另外一种就是nova-scheduler、nova-conductor这样的内部服务。对于通过消息队列才能访问到的nova-schduler等服务来说,是没有办法通过curl命令检查其健康状态的。要检查这些服务的健康状态,需要发送rpc同步调用请求,如果目的节点上的指定服务能够正常响应,则说明对应节点上的nova服务运行正常。下面以检测计算节点compute01上的nova-compute服务为例进行说明。根据nova exchange部分的说明可以知道,compute01节点上的nova-compute服务将会消费两个队列,一个是compute队列,另外一个是compute.compute01队列。由于compute队列会被所有的nova-compute服务消费,所以如果将消息发送给compute队列(即prepare方法不指定server参数),则消息可能被任意一个nova-compute服务进程消费,即使要检测的nova-compute服务已经无法正常功能,检测仍然会成功。因此在发送消息时,必须指定server参数为目的计算节点compute01,此时消息将被发送到compute.compute01队列中,同时该队列仅被compute01节点上的nova-compute服务消费,如果此时该服务异常,则消息将不会被消费,直到客户端等待响应超时,就可以知道compute01节点上的nova-compute服务出现了异常。4992f6312b92b442b16474f7bdc8ce19.gif

参考资料

ec1d2e5c6fd6654376c7ba64120da562.gif1、https://www.rabbitmq.com/getstarted.html2、https://opendev.org/openstack/openstack-helm/src/branch/master/nova/templates/bin/_health-probe.py.tpl

往期精彩内容回顾

1

S3请求来了,该怎么处理?

2

初探Docker的网络模式

3

OpenStack Policy鉴权大解密!

6f8ce6230719263db7ec8cd80c3adf0a.png

听说长得好看的人都点了赞和在看!59ddb76457c33c58e746ca1dcc0cb5e3.gif



推荐阅读
  • 修复一个 Bug 竟耗时两天?真的有那么复杂吗?
    修复一个 Bug 竟然耗费了两天时间?这背后究竟隐藏着怎样的复杂性?本文将深入探讨这个看似简单的 Bug 为何会如此棘手,从代码层面剖析问题根源,并分享解决过程中遇到的技术挑战和心得。 ... [详细]
  • 作为140字符的开创者,Twitter看似简单却异常复杂。其简洁之处在于仅用140个字符就能实现信息的高效传播,甚至在多次全球性事件中超越传统媒体的速度。然而,为了支持2亿用户的高效使用,其背后的技术架构和系统设计则极为复杂,涉及高并发处理、数据存储和实时传输等多个技术挑战。 ... [详细]
  • 智能制造数据综合分析与应用解决方案
    在智能制造领域,生产数据通过先进的采集设备收集,并利用时序数据库或关系型数据库进行高效存储。这些数据经过处理后,通过可视化数据大屏呈现,为生产车间、生产控制中心以及管理层提供实时、精准的信息支持,助力不同应用场景下的决策优化和效率提升。 ... [详细]
  • Python作为当今IT领域中最受欢迎且高效的语言之一,其框架能够显著加速Web应用程序的开发过程。本文推荐并对比了十大顶级Python Web开发框架,其中CubicWeb以其卓越的代码重用性和模块化设计脱颖而出,为开发者提供了强大的支持。 ... [详细]
  • 当前,众多初创企业对全栈工程师的需求日益增长,但市场中却存在大量所谓的“伪全栈工程师”,尤其是那些仅掌握了Node.js技能的前端开发人员。本文旨在深入探讨全栈工程师在现代技术生态中的真实角色与价值,澄清对这一角色的误解,并强调真正的全栈工程师应具备全面的技术栈和综合解决问题的能力。 ... [详细]
  • 2019年后蚂蚁集团与拼多多面试经验详述与深度剖析
    2019年后蚂蚁集团与拼多多面试经验详述与深度剖析 ... [详细]
  • 如果你对项目管理和系统架构感兴趣,欢迎关注微信订阅号“softjg”,加入我们这个PM和架构师的大家庭。本文将探讨编写高质量软件架构文档的重要性及其优势。良好的架构文档不仅能够促进不同利益相关者之间的沟通与理解,还能为项目的长期维护和扩展提供坚实的基础。通过详细记录系统的设计决策和关键组件,架构文档能够确保团队成员在项目周期内保持一致性和高效协作。 ... [详细]
  • 本文详细介绍了HDFS的基础知识及其数据读写机制。首先,文章阐述了HDFS的架构,包括其核心组件及其角色和功能。特别地,对NameNode进行了深入解析,指出其主要负责在内存中存储元数据、目录结构以及文件块的映射关系,并通过持久化方案确保数据的可靠性和高可用性。此外,还探讨了DataNode的角色及其在数据存储和读取过程中的关键作用。 ... [详细]
  • 本文提供了 RabbitMQ 3.7 的快速上手指南,详细介绍了环境搭建、生产者和消费者的配置与使用。通过官方教程的指引,读者可以轻松完成初步测试和实践,快速掌握 RabbitMQ 的核心功能和基本操作。 ... [详细]
  • 深入RTOS实践,面对原子操作提问竟感困惑
    在实时操作系统(RTOS)的实践中,尽管已经积累了丰富的经验,但在面对原子操作的具体问题时,仍感到困惑。本文将深入探讨RTOS中的原子操作机制,分析其在多任务环境下的重要性和实现方式,并结合实际案例解析常见的问题及解决方案,帮助读者更好地理解和应用这一关键技术。 ... [详细]
  • # 运维小白的成长日记第七天OSI七层传输层/应用层精讲!
    运维小白的成长日记第七天-OSI七层传输层应用层精讲!1、IP提供了点到点的连续接,通过IP地址可以找到目标主机。但是目标主机有很多应用,服务器到底使用哪个应用来响应客户端?通过端 ... [详细]
  • MiriamPena在可伸缩,高性能,高并发性和高可用性系统方面拥有10多年的经验。她是旧金山AdRoll的一名工程师,负责设计其实时出价 ... [详细]
  • 背景最近面试面得心力交瘁,由于没有高并发架构的实际项目经验,经常是在场景设计的面试题目上面栽跟头。上次就被问到了关于秒杀系统的设计,竟无 ... [详细]
  • 一文了解消息中间件RabbitMQ
    消息中间件---RabbitMQ1消息中间件的作用2.常用的消息中间件3消息中间件RabbitMQ3.1RabbitMQ介绍3.3RabbitMQ的队列模式3.3RabbitMQ的 ... [详细]
  • SpringCloud之Bus(消息总线)
    说明:关于SpringCloud系列的文章中的代码都在码云上面地址:https:gitee.comzh_0209_javaspringcloud-ali ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有