1. 问题现象与初步诊断
上周五凌晨2点,监控系统突然告警显示某OpenStack集群的compute-03节点出现异常。具体表现为:新建虚拟机时若指定该节点,任务会卡在"调度中"状态长达15分钟后失败,但该节点上已有虚拟机运行完全正常。这种"服务半死不活"的状态,正是典型的nova-compute服务假死现象。
通过SSH登录问题节点后,我首先检查了服务状态:
bash复制systemctl status openstack-nova-compute
发现服务显示为active(running),但实际已失去响应。尝试重启服务:
bash复制systemctl restart openstack-nova-compute
结果服务无法正常启动,journalctl -xe查看日志发现报错:
code复制ERROR nova.compute.manager [req-xxx] Instance xxx could not be found in the database
2. 故障根因分析
2.1 数据库与hypervisor状态不一致
深入分析日志后发现,核心问题在于Nova数据库中的instances表记录与底层KVM的虚拟机状态出现了不一致。具体表现为:
- 数据库中标记为active的实例,在libvirt中不存在
- 或者libvirt中存在的虚拟机,在数据库中无对应记录
这种状态不一致会导致nova-compute服务启动时执行资源同步检查失败,进而引发服务崩溃。根据多年运维经验,这类问题通常由以下场景导致:
- 虚拟机被手动通过virsh命令删除但数据库未更新
- Nova服务异常终止导致事务未提交
- 存储后端异常导致元数据写入失败
- 集群脑裂场景下的数据不一致
2.2 典型故障场景还原
以我们遇到的Case为例,故障产生过程如下:
- 用户尝试删除一个名为test-vm的实例
- 删除过程中网络闪断导致API超时
- Nova执行了libvirt层销毁但数据库回滚失败
- 最终状态:
- 数据库:instances表中test-vm记录仍存在,状态为active
- 计算节点:libvirt中已无该虚拟机定义
这种脏数据会像"定时炸弹"一样,在下一次服务重启时爆发。
3. 故障处理全流程
3.1 确认不一致实例
首先通过nova客户端查询问题实例:
bash复制nova show <instance_id>
同时检查libvirt中的定义:
bash复制virsh list --all | grep <instance_name>
virsh dumpxml <instance_name>
当确认是状态不一致导致的问题时,需要根据实际情况选择修复方案:
场景1:数据库有记录但libvirt不存在
code复制nova reset-state --active <instance_id>
nova delete <instance_id>
场景2:libvirt存在但数据库无记录
bash复制virsh destroy <instance_name>
virsh undefine <instance_name>
3.2 数据库强制修复
对于复杂的脏数据情况,可能需要直接操作数据库:
- 连接nova数据库:
bash复制mysql -uroot -p nova
- 查询问题实例:
sql复制SELECT * FROM instances WHERE uuid='<instance_uuid>' \G
- 根据实际情况更新或删除记录:
sql复制UPDATE instances SET deleted=1 WHERE uuid='<instance_uuid>';
DELETE FROM instance_extra WHERE instance_uuid='<instance_uuid>';
警告:直接操作数据库存在风险,务必先备份数据!
3.3 服务恢复验证
完成修复后,重启服务并验证:
bash复制systemctl restart openstack-nova-compute
nova service-list | grep compute-03
创建测试实例验证功能恢复:
bash复制nova boot --image cirros --flavor m1.tiny --availability-zone nova:compute-03 test-vm
4. 预防措施与最佳实践
4.1 日常运维建议
-
部署状态监控系统,检测以下指标:
- nova-compute进程存活状态
- 服务心跳时间间隔
- 节点资源使用率
-
定期执行一致性检查脚本:
bash复制#!/bin/bash
# 对比数据库和libvirt的实例列表
nova list --all-tenants | awk '/running/{print $2}' > db_instances
virsh list --all | awk '/running/{print $2}' > libvirt_instances
diff db_instances libvirt_instances
4.2 自动化修复方案
对于大型集群,建议实现自动化修复:
python复制# 示例:自动检测并修复状态不一致
from novaclient import client
import libvirt
nova = client.Client(...)
conn = libvirt.open()
db_instances = {i.id: i for i in nova.servers.list(search_opts={'all_tenants': 1})}
libvirt_instances = {dom.UUIDString(): dom for dom in conn.listAllDomains()}
# 对比处理不一致情况
for uuid in set(db_instances) - set(libvirt_instances):
print(f"Missing in libvirt: {uuid}")
db_instances[uuid].delete()
for uuid in set(libvirt_instances) - set(db_instances):
print(f"Orphan in libvirt: {uuid}")
dom = libvirt_instances[uuid]
dom.destroy()
dom.undefine()
4.3 关键配置优化
在nova.conf中添加以下配置可减少问题发生:
code复制[default]
resume_guests_state_on_host_boot = true
heal_instance_info_cache_interval = 60
5. 深度问题排查技巧
当遇到复杂情况时,可以启用debug日志获取更详细信息:
code复制nova.conf:
[DEFAULT]
debug = true
常见错误日志分析:
-
ResourceProviderSyncFailed:
表示资源同步失败,通常需要检查placement服务 -
ComputeHostNotFound:
计算节点未正确注册,检查nova-scheduler日志 -
InstanceNotFound:
实例状态不一致,按本文方法处理
对于难以定位的问题,可以使用nova-compute的--debug参数启动服务:
bash复制/usr/bin/nova-compute --config-file /etc/nova/nova.conf --debug
我在实际运维中发现,这类问题往往不是孤立出现的。建议建立完整的故障处理流程:
- 收集日志(nova, libvirt, 数据库)
- 确定不一致的具体对象
- 评估影响范围
- 选择最小影响的修复方案
- 验证修复效果
- 记录案例并更新应急预案