
1. Nova是什么先搞明白它在OpenStack里的位置如果你是第一次接触OpenStack跑完一套环境比如PackStack或者DevStack之后第一个让你觉得这东西有点东西的组件大概率就是Nova。运维圈子里流传着一句话OpenStack的虚拟化能力、实例管理能力、调度能力和配额控制能力全部由Nova提供。换句话说Nova是OpenStack的计算核心你要是能把它看明白云平台的大半边天基本就清楚了。从历史沿革来看Nova其实是从NASA的Nebula项目孵化出来的前身是亚马逊EC2风格的云计算组件。后来和RackSpace的Swift对象存储项目合并才一起组成了OpenStack这个大家庭。所以Nova的代码里至今还保留着大量跟AWS EC2 API兼容的影子像nova client里那些ec2开头的配置项就是这段历史的活化石。现在OpenStack的版本都已经迭代到了2024.2代号类似于CaracalNova仍然是其中最核心、最不可替代的一个子项目。那么Nova到底能做什么我们用一个最简单的场景来理解你在公有云上点一个按钮创建一台虚拟机这个动作背后那一连串复杂的流程——找一台物理主机、检查资源够不够、给这台机器分配IP、调用底层虚拟化软件把VM拉起来、再把这个实例的元数据记录下来——这些活儿全部由Nova承接。如果你考过或做过OpenStack运维你一定遇到过nova list、nova show、openstack server create这类命令这些命令的背后就是Nova的API、Scheduler、Conductor、Compute这一整套组件在协同工作。这篇文章适合谁看一种是刚接触OpenStack、还停留在能装能跑阶段的初学者你需要把Nova的组件关系串起来知道创建一台虚拟机时消息是怎么流转的另一种是在用官方文档或者社区教程但文档讲得太零散总感觉每个单词都认识、连起来不知道在说什么的同学。我尽量不说废话直接拆架构。1.1 Nova是OpenStack的计算大脑Nova在OpenStack里的定位非常清晰它是一个可以管理大规模计算实例虚拟机的生命周期的控制器。官方文档里管它叫OpenStack Compute负责的事情包括但不限于实例的创建、删除、启动、暂停、挂起、恢复、迁移、调整规格Resize、重建Rebuild、快照管理等等。你可能会问那其他组件是干嘛的打一个生活化的比方。假设整个OpenStack是一家公司Nova是公司里的项目经理负责统筹计算资源的整体调度Neutron是网络管理员负责给每个新入职的员工虚拟机配交换机、分IP、弄防火墙规则Cinder是仓库管理员负责提供各种规格的硬盘卷Glance则是资料室负责保存操作系统镜像模板。这几个角色不是各自为战而是通过API互相调用。Nova在创建一个实例的时候会去Glance要镜像去Neutron要网络端口去Cinder挂卷最后再调用计算节点上的虚拟化驱动把这一堆资源拼装成一台能开机、能远程操作的虚拟机。可以说Nova是OpenStack所有组件中合作对象最多的一个牵一发而动全身。也正因为如此Nova的架构设计经历过多次大调整。从早期单体进程到现在的分布式消息队列协作从直接访问数据库到引入nova-conductor隔离层再到后来分离出独立的Placement资源追踪服务每一次改动都是为了解决一个非常实际的问题节点规模大了、并发请求多了老架构扛不住。理解了这条演进路线你看到新版Nova里那些多出来的组件就不会觉得莫名其妙。1.2 从一个问题入手创建虚拟机到底谁负责想象你执行了openstack server create --flavor m1.small --image cirros myfirstvm这条命令。在你按下回车的那一瞬间你的CLI工具先通过Keystone拿到一个认证Token然后把这个请求发到Nova的API Endpoint上通常是http://控制器节点IP:8774/v2.1。但从API接收请求到虚拟机真正确认创建成功中间隔了好几个角色。Nova并不是一个单体程序一口气干完所有事而是分成若干独立进程每个进程可能有多个副本各自负责一段职责进程之间通过消息队列默认是RabbitMQ异步通信。这样设计的好处显而易见某一个进程挂了可以单独重启如果你在控制节点上执行systemctl restart openstack-nova-api调度器和计算节点的服务不会受影响需要扩展的时候也可以单独增加某个组件的实例数量。那么这个谁负责什么的问题就是我下面要拆解的核心内容——Nova的五大组件各个角色的分工与合作。2. Nova的五脏六腑核心组件逐个拆解Nova架构经过这么多版本迭代主要角色固定下来了分别是nova-api、nova-scheduler、nova-conductor、nova-compute还有一个不得不提的nova-placement在比较新的版本中Placement已经独立成单独的项目。先看一张核心组件职责速查表再逐个展开。组件运行位置核心职责类比nova-api控制节点接收所有OpenStack Compute API请求校验参数、绑定路由、响应结果公司前台接待nova-scheduler控制节点决定新实例放在哪台计算节点上执行过滤和权重算法人力资源分配师nova-conductor控制节点代理数据库读写操作避免compute直连数据库同时处理一些协调逻辑数据库守门员nova-compute计算节点实际管理虚拟机生命周期通过驱动调用底层Hypervisor一线车间工人nova-placement控制节点跟踪每个资源提供者的资源库存、用量和分配情况资产台账管理员2.1 nova-api对外的大门你不会直接在每台计算节点上装nova-api它几乎永远是运行在控制节点上的。它的首要任务就是让外部用户有一条通道可以操作Nova。这条通道是标准的RESTful API支持OpenStack Compute API 2.1版本更老的2.0早已淘汰新装环境千万别用旧客户端去对接。可能有人觉得API层就是个转发的没啥技术含量。其实大错特错。nova-api在处理每个请求时要做的事情非常多首先去Keystone验证Token是否有效、是否过期、用户是否有对应权限然后解析请求参数把JSON/XML格式的数据转换为Nova内部的object接着判断这个请求是需要立刻返回结果还是要发到消息队列里去异步执行。举个例子你执行openstack flavor list的时候nova-api直接查数据库马上返回结果这是一条同步链路。但你执行openstack server createnova-api把请求包装成一个RPC消息扔进消息队列然后就返回了HTTP 202Accepted开头实际创建过程的持续轮询是你通过nova list或者openstack server list看到的。理解这个同步/异步的区别对排查为什么命令半天没反应特别有帮助——很可能请求已经出发了只是后端还没跑完。2.2 nova-scheduler决定虚拟机跑在哪台机器上Nova里最能体现架构设计智慧的组件之一就是scheduler。它的任务就是一句话从一堆计算节点里选出一台最合适的去跑这个新实例。但实现这个最合适的判断过程涉及两层算法先过滤Filter再打分Weighing。先过滤是什么意思就是把明显不满足条件的节点淘汰掉。例如我要求新实例必须落在availability_zone: prod这个可用域里那不满足的物理节点直接出局再比如我要求必须有至少4GB的可用内存内存不够的节点也出局。经过多轮过滤后剩余的就是候选主机名单。再打分又是怎么回事因为符合条件的不止一台机器总得挑一个最优解。打分器Weigher会给候选机器打一个分数比如CPU剩余多的权重高、内存剩余多的权重高。Nova默认把ram_weight_multiplier设为1.0也就是内存多的机器更可能被选中。这两步走完后scheduler把选中的主机变成一条消息发回消息队列通知该主机上的nova-compute干活。有很多新人在配置scheduler的时候有个误区以为只要调度器选好主机那么实例就一定会跑在那边。实际上负责任地告诉你如果nova-compute在最后一步执行的时候因为某种原因失败了实例有可能会被重新放置或者直接变ERROR状态。这个最后一步的失败调度器是帮不上忙的需要结合计算节点日志往上查。2.3 nova-conductor数据库操作的代理层Nova架构早期nova-compute是直接读写数据库的。听起来好像也没什么毛病但真出了问题就后怕了计算节点通常分布在各机房如果你只把数据库的账号密码分发到几十台计算节点上那么任意一台机器被攻破整个数据库的数据都保不住。这是一个巨大的安全隐患。所以从Grizzly版本开始Nova引入了nova-conductor作为所有数据库操作的中间代理。计算节点上的nova-compute再想查数据库不再直连MySQL/MariaDB而是把自己的请求封装成RPC消息发给conductor由conductor去执行数据库操作再把结果返回。这样一来数据库账号只需要存在于控制节点上计算节点彻底跟数据库隔离了。除了安全考虑conductor还承担了一部分重量级的逻辑操作比如在实例迁移migration的时候许多协调性工作是在conductor里完成的。所以如果某一天你发现创建实例卡在某一步、日志里大量出现nova-conductor超时或者DBError别急着一顿乱查先看conductor是不是活着、数据库连接池是不是被耗尽了。这个守门员一旦罢工全流程直接瘫痪。2.4 nova-compute真正干活的角色终于轮到最一线的工人了。nova-compute跑在每一台计算节点上它是唯一一个直接操作Hypervisor比如KVM、QEMU、Xen、VMware ESXi的组件。它通过驱动架构屏蔽底层差异对KVM来说它的驱动是libvirt通过libvirt的API去创建domain、管理生命周期对Xen来说用的是XenAPI对VMware来说用的是VMwareVCDriver。你可以理解为一个工厂里不管车间里用的是哪种型号的机床工人手里都有一套标准化的操作面板。nova-compute就是那个操作面板driver是这个面板底下接的各个型号机床的适配器。在进行nova-compute的配置时最关键的一句配置是compute_driverlibvirt.LibvirtDriver如果你换成了别的驱动整个计算节点管理的虚拟化方式就变天了。特别提醒一下nova-compute确实是干活的人但它并不是所有事情都能自己拍板。它经常需要向conductor查询数据库比如查flavor的规格、查镜像的信息也需要把自己收集到的资源变化情况上报给Placement服务。所以你会发现即使计算节点和数据库不直连它的消息队列连接也绝对不能断——一旦RabbitMQ的某个队列堆积起来实例创建的即时反馈会变得非常糟糕。3. 一场虚拟机创建之旅Nova内部的消息流讲完组件我们把整个创建流程串一遍。这里我用的是最常见、也是新装环境默认的RabbitMQ消息队列模式其他消息中间件如Kafka、ZeroMQ原理类似。作为运维你能把这套消息流描述清楚面试和排障都够用了。3.1 从API到数据库请求进入Nova的大门第一步客户端比如openstack命令行工具向Keystone发起认证请求拿到一个Scoped Token。然后带着Token去请求nova-apiPOST /v2.1/serversBody里带着flavorRef、imageRef、networks等参数。如果你用的是较新版本的OpenStack这里其实还会带上用户直接指定的availability_zone和scheduler_hints。nova-api收到请求后做的第一件事是验证Token它会调用Keystone提供的验证接口确认这个Token对应的用户、项目租户是否合法。验证通过后nova-api把请求里的参数组装成RequestSpec对象再调用api层的create()方法把数据库记录如实例表instances的状态先写成BUILDING同时把一条RPC消息扔进消息队列这条消息的目的地是conductor因为很多数据库写入逻辑需要conductor代理完成。这里有个十分重要的启动参数在配置文件中scheduler_availability_zone和default_schedule_zone这些值会影响后续调度。nova-api会把请求里没有显式指定的默认值补全。也就是说如果你在request里没指定可用域那么默认你认为的要去哪个可用域就取决于配置文件这个配置往往就是你踩的第一个坑。3.2 调度器如何挑肥拣瘦Filter Weight机制消息从nova-api进入RabbitMQ后会进入一条调度队列通常叫conductor或者scheduler相关队列nova-scheduler和nova-conductor都是消息队列的消费者。调度的主流程可以这么描述conductor收到请求调用scheduler_client的select_destinations()方法把RequestSpec传给scheduler。scheduler开始过滤它会向Placement服务查询所有计算节点资源提供者的当前资源状态再结合自己的Filter链逐一淘汰。scheduler进行打分剩余的节点按权重排序选出得分最高的那个如果有多个默认从高分队列里选一个。scheduler返回目标主机列表conductor收到后再将结果作为RPC消息发给对应主机上的nova-compute。很多人觉得调度器没啥好优化的默认配置跑得很好。但真要大规模部署的时候Filter顺序和Weigher参数是需要反复调的。比如你有两套宿主机一套是普通机械盘、另一套是NVME SSD如果按默认的调度策略新实例可能随机落在两套上导致性能差异不均。这时候就要利用AggregateInstanceExtraSpecsFilter配合主机聚合Host Aggregates来做区分给SSD那组打一个ssdtrue的metadataflavor的extra_specs里也声明ssdtrue调度器就会把该flavor的实例全部赶到SSD组去。关于Filter和Weigher的具体清单和调优思路下一节我会单独展开。3.3 从调度到创建nova-compute的执行链路nova-compute收到RPC消息后不是马上创建虚拟机而是先做一连串预检和回源操作查询数据库作为消费者它会调用conductor的RPC接口把flavor信息、镜像信息、实例的uuid等元数据查出来获取网络信息它调用Neutron的API为这个实例创建或绑定一张虚拟网卡Port获取卷信息如果需要挂Cinder卷它会调用Cinder的API去attach卷准备镜像把Glance里镜像通过glanceAPI拉取到本地缓存如果是本地存储的话或者从共享存储的镜像文件中直接拷贝生成XMLnova-compute基于这些信息通过driver生成要给libvirt执行的XML定义文档如果底层是QEMU/KVM这个文档里包括CPU型号、内存、磁盘、网卡以及各种超线程/NUMA/CPU pinning参数等执行创建driver调用libvirt的virDomainDefineXML把VM定义到Hypervisor上再调用virDomainCreate启动它。这里每一个环节出错的概率都不低。最常见的是网络步骤卡住——比如Neutron的DHCP Agent没起来或者子网网段跟物理环境冲突实例就会一直卡在BUILDING状态最终变成ERROR。这时候你去查看/var/log/neutron和/var/log/nova/nova-compute.log能发现非常明确的报错线索。4. Nova的调度策略详解Filters与Weights的协同调度是Nova核心中的核心值得单独用一整节来深挖。Nova默认使用的调度器是FilterScheduler配置项是scheduler_driver filter_scheduler.FilterScheduler。它会把所有候选主机先过一遍Filter链剩下的再用Weigher排序。如果这两个阶段都没调明白你的云平台可能在某次大促销/大扩容时直接翻车。4.1 常用Filter与排序器速查阶段名称作用FilterAvailabilityZoneFilter只保留匹配请求可用域的主机FilterComputeFilter过滤掉已禁用、不在线、不处于服务状态的主机FilterComputeCapabilitiesFilter根据flavor的extra_specs匹配主机能力FilterRAMFilter过滤掉可用内存不足的主机防止超分过高FilterNUMATopologyFilter指定NUMA拓扑需求时过滤掉不匹配物理拓扑的主机FilterAggregateInstanceExtraSpecsFilter配合主机聚合的metadata做精确能力匹配WeigherRAMWeigher剩余内存越多权重越高默认multiplier重1.0WeigherMetricsWeigher根据采集的metricsCPU负载等打分需另配插件WeigherServerGroupAntiAffinityWeigher尽量把同组实例散开到不同主机你安装完OpenStack后nova.conf里的[filter_scheduler]段一般长这样[filter_scheduler] enabled_filters AvailabilityZoneFilter,ComputeFilter,ComputeCapabilitiesFilter,ImagePropertiesFilter,CoreFilter,RAMFilter available_filters nova.scheduler.filters.all_filters这个配置的意思就是只启用这些过滤器其它过滤器不启用。工程上常需要按情况调整顺序和启用项。例如你启用了CoreFilter它默认检查物理主机的超配比例如果cpu_allocation_ratio16你允许一台32核的机器超配到512个vCPU。一旦某台机器已经塞了超过500个vCPU新实例就不会再放上去。经验之谈刚开始搭建环境时很多人想通过调大cpu_allocation_ratio来增加创建的虚拟机数量这本身没问题但一定要同时调好ram_allocation_ratio和磁盘的overcommit参数。如果不设置好调度器看起来有资源真到创建的时候Hypervisor要么内存不够、要么磁盘写满一堆实例处于ERROR状态排查起来非常麻烦。4.2 多可用域与主机聚合的调度可用域Availability Zone和主机聚合Host Aggregates是两个看起来相似、语义上却完全不同的概念。可用域是用户可见的API参数里可以显式指定主要用于高可用场景比如让客户把业务分散到多个故障域主机聚合则通常是管理员自己定义的资源池带特殊的metadata比如上文的ssdtrue。实际架构里我们经常把主机聚合跟可用域混着用。比如在双机房的场景中我们可以为A机房的所有计算节点创建聚合az-a并为B机房创建聚合az-b。然后在调度时通过AvailabilityZoneFilter去保证新实例落在指定机房再通过AggregateInstanceExtraSpecsFilter去保证只有满足特定spec比如shared_storagetrue的主机才会被纳入候选。调度器级的多级过滤设计让Nova可以在一个云平台里同时服务多种差异巨大的业务需求——对CPU绑定敏感的HPC任务对真实内存大小敏感的数据库任务对性能均衡要求高的Web集群。几乎所有场景都能通过Filter和Weigher的组合切分清楚。但反过来如果你不规划好集群里所有机器都会变成一锅烩——没法精细分片之后在运维层面补也是亡羊补牢。5. Nova架构演进Placement服务与Cells v2很多新人在看新版本Nova的架构图时会愣住怎么多了一个叫Placement的东西其实在Nova刚诞生的时候资源追踪都是靠数据库里一套叫compute_nodes的表格来记录的。nova-compute启动时会把自己的总资源量和已用量写入这张表调度器来查询。这套机制在规模小的时候还行但到了几百个计算节点后资源冲突、并发更新的问题就开始出现了。5.1 为什么新增Placement服务Placement这个项目最早的原型出现在N版Newton到O版Ocata和P版Pike不断强化最后在 Queens 版本中把它从Nova代码库里彻底独立成了一个单独的项目单独打包成openstack-placement-api之类的包。它的核心职责就是保存资源提供者Resource Provider的信息。一个资源提供者可以是一台物理机、也可以是一个资源池。它记录的内容包括这个提供者拥有多少资源比如vCPU总量、内存总量、磁盘总量已经用掉了多少以及各类资源当前被哪个消费者比如哪个实例占用。调度器在做Filter和Weighing时首先会调Placement的API来获取实时的、全量的资源视图。这种方式比老旧的数据库表靠谱多了。首先Placement的API设计是RESTful的任何组件都能调用其次它把资源追踪这块逻辑跟计算调度彻底解耦Nova可以随时查询而不用关心这些数据到底存在哪。你在部署中如果能单独重启placement-api服务而不影响nova-api这在老架构里是不可想象的。运维提示升级到新版本后别忘了先跑一遍placement-manage db sync初始化数据库否则placement-api会一直报401或者500。另外平常可以用openstack resource provider list、openstack resource provider inventory list rp_uuid这类命令来查看资源账本排查调度不准确的问题。5.2 Nova-compute直连的局限与Cells v2除了PlacementNova还经历了另一次大手术——Cell V2。老时代Nova就是一个大数据库、大消息队列所有nova-compute节点都连着同一个bus。这在早期几十台节点的规模下没问题可一旦扩展到上几千台物理机单一数据库的写入压力、双边消息队列的队列堆积、故障内容同步的一致性问题都会集中爆发。于是社区推出了Cells架构第一代是Cell V1比较复杂后来废弃了一直到N版引入了Cell V2并且在P/T版中把它做成唯一的部署模式。Cell V2把Nova的架构分成两层全局层global和单元层cell。全局层包括API、Scheduler、Placement、整个环境的共享数据库单元层则包含一个独立的消息队列、一个独立的数据库、一个或多个Conductor和Compute节点。每个Cell有自己的Cell数据库存的是这个Cell内部的实例信息和计算节点信息全局数据库只存放跨越所有Cell的元数据比如Cell的映射关系、实例和Cell的对应关系。这是典型的分库分表思路。创建这台VM时全局API和Scheduler先把实例映射到某个Cell现在通常是cell0以外的一个或几个cell然后把创建请求路由到该Cell内部的消息队列由该Cell的conductor和compute去执行。你可能会觉得这会增加排查复杂度。确实如此。排障的时候你先要查这个请求被调度到了哪个cell直接看placement的allocation就能看到然后去那个cell的消息队列和数据库里查实例的状态不能只看全局数据库。我记得有次生产环境有个实例创建老是卡住全局库里明明查到实例状态是BUILDING但具体卡在是哪个环节必须登录对应的cell-conductor日志才看得到。这个观念不转变玩转新版Nova是空谈。6. Nova与周边组件的关系一张联动网络只盯着Nova内部组件看是不够的因为OpenStack是一个整体。Nova是中心调度者它时时刻刻在和Keystone、Glance、Neutron、Cinder交互。下面我把交互关系梳理清楚。6.1 Nova与Keystone、Glance的交互Keystone是身份认证服务。所有OpenStack CLI和API请求都必须先通过Keystone获取Token。Nova收到请求后用这个Token去Keystone校验用户信息和授权范围。如果你给某个用户只授予了member角色那么他创建实例没问题如果只有reader角色那么创建请求会被拒绝。Glance则负责镜像管理。Nova在创建实例时会把镜像一个接一个地下载到计算节点如果用的是本地存储或者通过共享存储路径直接引用镜像。Glance的API地址由Nova的配置文件[glance]段指定如api_servers http://controller:9292。如果镜像损坏或者权限不足Nova会直接报ImageNotFound或Forbidden。这里有一个运维小技巧如果你发现创建虚拟机特别慢且日志里频繁出现Image is not in active state可能不是网络问题而是Glance镜像没有上传完成。另外在Nova的[glance]配置里可以设置allowed_direct_url_schemes来让计算节点直接从共享存储拷贝镜像文件而不是每次都走HTTP下载效率提升明显。6.2 Nova与Neutron、Cinder的交互网络这块绑定得很紧密。Nova实例的每一张网卡本质上都是Neutron里的一个Port。在创建实例的时候Nova会调用Neutron的API先创建Port拿到这个Port的MAC地址、IP地址和所属网络信息然后把它塞给libvirt的domain定义中相当于把虚拟机的网线插好。一旦Neutron的plugin/agent比如Open vSwitch或Linux Bridge挂了你创建的VM表面上已经启动但网络不通这个坑特别容易让人误以为是Nova的问题。卷存储也一样。Nova创建实例时如果不指定--block-device-mapping默认是本地盘ephemeral如果指定了Cinder卷启动Nova会调用Cinder的API将卷attach到计算节点上。这个attach过程用到了os-brick库它会根据底层存储类型iSCSI、FC、NFS、Ceph RBD等来执行对应的连接操作。RBD在Ceph环境下一般不需要额外装驱动但如果是iSCSI你得确保计算节点上有正确的multipath和iscsi-initiator-utils工具。很多新手在Ceph挂卷失败时日志里只看到Failed to connect to volume实际上问题往往出在计算节点缺少依赖包或缺少到存储网络的互通路由。7. 常见架构问题排查与运维实操经验架构理解了能不能用到排障上才是检验标准。我挑几个实际运维中反复出现的Nova架构问题配合排查思路展开。7.1 经典排障思路从API层往里逐层推进排查Nova问题时我建议遵循一条铁律从用户请求链路的最前端开始逐层往后查不要跳层。比如一个实例创建失败报错ERROR或一直BUILDING。我的排查顺序通常是# 1. 先看全局日志锁定大致阶段 tail -f /var/log/nova/nova-api.log tail -f /var/log/nova/nova-scheduler.log # 2. 查数据库里的实例状态确认调度结果 mysql -u nova -p -h controller nova -e select uuid, vm_state, task_state, host, node from instances where uuidinstance_uuid\G;如果实例的host字段是空的说明调度没完成问题出在scheduler或Placement如果host字段已经填了某台计算节点但实例状态还是BUILDING那问题大概率在nova-compute与底层hypervisor之间。第二步去计算节点上看nova-compute的日志sudo tail -n 500 /var/log/nova/nova-compute.log | grep -E ERROR|Error|Exception看到Nova报LibvirtError或者oslo_messaging超时再对症下药。比如virDomainDefineXML频繁超时常见原因是被当成宿主的这台机器上libvirtd服务卡死或者libvirt连接达到上限。遇到这种立即在计算节点执行systemctl status libvirtd看看是不是活着必要时重启libvirtd但注意这会短暂中断该节点的虚拟机热迁移能力。7.2 架构演进中的运维避坑记录我在多套OpenStack环境上做运维的几年里踩过非常多跟Nova架构直接相关的坑挑三个最常见的分享。坑一Placement同步不一致明明节点上资源已经释放了但Placement里还是显示已分配。这种情况通常是因为腾讯/虚拟机删除失败或者nova-compute上报资源发起了RPC但没有成功。旧做法是去数据库里硬改allocations表——我极其不建议用这种方式因为Placement有缓存和一致性校验。正确做法是用openstack resource provider allocation delete先清理异常allocation再在计算节点上跑nova-manage resource重刷资源。等新版中nova-manage placement audit这类工具更完善之后尽量用工具别手写SQL。坑二RabbitMQ队列堆积导致假死一场大型创建任务比如几百台VM同时起RabbitMQ里的队列消息量会瞬间飙升。在很多默认配置里nova-api到nova-scheduler之间的RPC调用都是同步等待的一旦消息处理不过来CLI命令会一直卡在那里。这时候你在控制节点执行rabbitmqctl list_queues能看到某些队列的消息数上万。最粗暴的解法是增加scheduler/conductor的并发数但前提是底层数据库扛得住。另一个需要注意的点是在配置文件里给oslo_messaging_rabbit段设置rabbit_max_retries和rabbit_retry_interval避免客户端长时间死等。坑三跨Cell迁移导致实例找不到Cell V2架构下如果你用旧方式直接改数据库把实例从一个Cell迁到另一个Cell实例在全局会查不到映射导致openstack server show找不到这个实例。遇到这台情况不要瞎折腾。在所有Cell中做全量搜索去导出的数据库备份里查找instance_mappings和cell_mappings表确认实例原本归属于哪个Cell再想办法降级回该Cell处理。任何跨Cell的高级操作迁移、跨AZ疏散等一定先看官方文档确认当前版本是否支持不要自己脑补。7.3 日常巡检Nova架构的几个关键点最后整理一下我日常巡检Nova时一定会看的点做个简单的checklist供大家抄作业控制节点上的nova-api、nova-scheduler、nova-conductor服务状态是否健康用systecmctl和curl到8774端口探活。所有计算节点的nova-compute与libvirtd是否在线nova计算机节点的状态是否up通过openstack compute service list查看。RabbitMQ和MySQL的连接数是否正常。特别是RabbitMQ的unicast队列数量、MySQL每秒QPS如果在高峰期异常飙高要考虑扩容或者调整超时。Placement的资源账面是否跟物理资源一致定期用openstack resource provider list对照实际宿主机数量。实例的vm_state和task_state有没有异常。大量实例卡在migrating或resizing说明协调层可能有积压优先看conductor日志。8. 最后聊点Nova架构的感觉写到这里Nova架构的核心内容基本都覆盖了。回头看这个过程我最大的体会是Nova这个组件其实像极了一个微服务化的调度系统。它把一整个创建虚拟机的流程拆成一个事件流水线每个服务只负责自己那块消息队列负责传输数据库负责最终状态确认。这种架构一开始理解起来有点绕尤其是习惯了单体应用、函数直接调用的人会困惑为什么一个创建请求还要经过API - Scheduler - Compute - Conductor - DB这么漫长的路程。但等你真正做过一次几千节点的超大集群你就能体会到这套设计背后的良苦用心每个组件可以独立扩展单个组件的故障不会拖垮全局计算节点分布式部署却不需要暴露数据库账号。调度器、API、Compute之间的松耦合让Nova既有足够的弹性去应对大规模资源池又有清晰的边界去划分每个运维人员的排查范围。最后再分享一个小技巧当你遇到Nova问题百思不得其解的时候把脑子里这是不是业务/镜像/网络问题的预设先放一边回到架构里去分析这条消息现在应该在哪一环节哪个服务可能已经挂了。这套顺着消息流查架构的思路比背任何API文档都有用。Nova版本更新得再快底层这套角色分工和消息流转的骨架都没有变过。你先把这个骨架烂熟于心再看任何一篇官方架构文档、任何一个社区排障帖速度都会快很多。