ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

OpenStack卷分离异常处理实战:detaching卡死排查与Ceph强制清理

OpenStack卷分离异常处理实战:detaching卡死排查与Ceph强制清理 凌晨两点半监控告警把我从床上拽起来。客户反馈一台生产实例的数据盘一直卡在detaching状态等了二十分钟还是没动静。我第一反应是“卷分离又出幺蛾子了”。说实话在OpenStack环境里跑久了卷分离这个问题就像家里水管偶发渗水——平时没事一出事就是麻烦事因为涉及Nova和Cinder两个组件的配合还牵扯底层存储的状态一个环节卡住整条链路就僵在那里。这篇内容就是围绕OpenStack卷分离异常问题展开的实战记录。我会把排查思路、常见故障点、强制处理手段和后续预防措施都梳理出来。不管你是刚搭好OpenStack环境在测试卷生命周期的小白还是已经被生产环境折磨到麻木的运维老手这套从现象到根因再到处理的完整链路应该都能给你省下不少折腾时间。1. 先搞清楚卷分离的完整链路请求到底经过了哪些环节处理任何OpenStack异常最忌讳的就是两眼一抹黑直接看日志。你得先知道一条正常的卷分离请求要经过哪些环节才能在异常发生时准确判断“卡在哪一层”。这是排查的基础也是很多新手最容易跳过的关键步骤。1.1 一次正常的卷分离请求是怎么走完的从用户视角看分离一个卷就是调用接口或者控制台点一个按钮但从架构视角看它是一条相当长的调用链。第一步用户发起请求后由Nova API接收然后转发给Nova Conductor再由Conductor调用Nova Compute。Nova Compute是真正干活的组件它会通过驱动调用底层虚拟化层比如libvirt/KVM把卷从虚拟机里摘下来。第二步Nova Compute在摘除设备的同时会调用Cinder的API通知Cinder Volume服务去终止这个卷和实例之间的连接。Cinder Volume拿到请求后会调用具体存储后端的驱动比如Ceph、LVM或者商业存储的驱动去删除或者释放主机与卷之间的映射关系。第三步Cinder Volume确认底层连接已经断开后会更新数据库里卷的状态把它从in-use改回available。与此同时Nova Compute也会更新自己的数据库记录把实例和卷的关联关系解除。至此一次完整的卷分离才算结束。我用一个生活化的类比说明一下。卷分离就像你从电脑上拔U盘。第一步相当于你点了任务栏里的“安全删除硬件”按钮第二步相当于鼠标指针变成忙状态、系统正在把缓存刷入U盘第三步相当于系统告诉你“可以安全拔出了”你才能真正把U盘从USB口里拔出来。OpenStack的卷分离也一样关键不只是“拔”这个动作而是拔之前和拔之后的连接处理。1.2 为什么理解这条链路对排查异常至关重要很多人一遇到卷分离失败就习惯性地去翻cinder-volume.log但问题很可能出在Nova侧或者底层存储侧Cinder日志里只能看到“连接终止失败”这种通用报错真正的根因藏在其他组件里。理解了完整链路你就有了排查地图。卷卡在detaching状态你首先要判断的是Nova已经完成摘除设备的动作了吗Cinder是否收到了终止连接的请求底层存储的映射关系是否已经清理然后针对每一层去验证而不是漫无目的地抓日志。排查思路在脑子里要像这样过一遍请求到Nova这一层没有看nova-api.log和nova-compute.log确认有没有收到detach请求。Nova执行结果如何看有没有异常报错报错是发生在libvirt调用阶段还是Cinder调用阶段。Cinder是否收到通知看cinder-volume.log里有没有对应的volume id日志。底层存储处理是否成功看cinder-volume日志里驱动执行结果或者直接在存储节点执行查询命令确认映射关系。只有把这个链路刻在脑子里后面的排查步骤才会有方向感。我见过太多人拿着日志从头翻到尾翻了半小时还是没定位到问题就是因为他根本不知道自己在找什么。2. 最常见的两类异常表现卡在detaching状态与报错信息解析卷分离异常在用户侧的感知通常只有两类一类是任务一直挂着卷状态停留在detaching不变化另一类是请求直接失败API返回错误信息。这两种情况对应的排查方向完全不同我把它们分开讲。2.1 第一类卷长时间卡在detaching状态这类现象最容易让人焦虑。从OpenStack控制台看实例的运行状态是正常的但卷始终处于detaching像是什么东西把它卡住了。卡在detaching的本质原因通常是Nova已经摘除了设备但在调用Cinder终止连接时出错了或者Cinder调用存储驱动的过程长时间没有返回结果。还有一种常见情况是Nova侧已经完成了自己的任务但Cinder侧因为某种原因比如数据库记录不一致、驱动执行报错一直没能把状态更新为available。遇到这种情况我的建议是先看时间节点。查一下nova-compute.log看看卷对应的detach请求是什么时候下发的。如果Nova日志里显示设备摘除动作已经成功那就把注意力转移到Cinder侧。如果Nova日志里都没有detach相关的记录那问题出在更早的环节可能是nova-conductor调度异常或者API层就没有把请求正确传递。另外要注意一个细节有时候实例所在的计算节点是宕机或者网络不通的状态。Nova和Cinder之间的RPC通信依赖消息队列如果计算节点失联Cinder发出的调用会一直停滞直到超时。这种情况下卷会一直卡在detaching。我在生产环境里确实遇到过因为计算节点假死、但实例还在跑导致的卷分离卡死。2.2 第二类API直接返回错误信息这类异常的优势在于错误信息多多少少会透露一些线索。最常见的错误提示包括VolumeInUse这个最直接Cinder认为卷还在被某个实例使用中。通常是数据库里的volume_attachment记录没有删干净Nova和Cinder之间的状态不同步导致的。Failed to detach volume: Unable to detach from instance这种通常是libvirt层的调用失败比如设备在虚拟机XML定义里和实际状态不一致或者Hypervisor层面拒绝了这个操作。Connection refused / timeout这通常是Nova调用Cinder API时网络层或服务层出了问题。不同的错误信息对应的是不同的排查路径别急着猜先看完整报错。这里我多说一句有些错误信息极具迷惑性。比如提示“VolumeInUse”实际上底层存储连接早就断开了纯粹是数据库残留记录造成的误判。如果你拿着错误信息去存储侧找问题那就白费功夫了。2.3 日志查询路径与关键字日志是排查卷分离异常的核心依据但前提是你会查、知道去哪里查。先按组件把日志文件对应关系理清楚nova-api.log记录API层请求能确认请求是否到达Nova。nova-conductor.log记录Nova内部调度和RPC转发情况。nova-compute.log记录计算节点执行动作包括libvirt调用结果。cinder-api.log记录Cinder API层请求能确认Nova的调用是否抵达。cinder-volume.log记录卷操作的执行情况是最常需要翻的日志。拿卷卡在detaching这件事举例我会在nova-compute.log里先搜卷的UUIDgrep -i 卷UUID /var/log/nova/nova-compute.log看到detach相关记录后顺着时间戳往下翻几条日志看后续有没有报错。然后在cinder-volume.log里同样搜索卷的UUIDgrep -i 卷UUID /var/log/cinder/cinder-volume.log如果发现Cinder日志里完全没有对应记录说明Nova到Cinder的调用链路出了问题去查网络配置或者消息队列状态。如果Cinder日志里显示驱动执行失败那就顺着驱动报错继续往下查。日志排查的关键在于沿着时间线和调用链逐层验证而不是漫无目的地乱翻。3. 不同故障场景下的隐患归类为了让你在遇到问题时能快速套用经验我把实际生产环境中常见的卷分离异常场景整理成了一张表格你可以把它当作排查前的一个快速对照表。结合每种场景的典型根因和排查方法能省去一大半从零开始排查的时间。故障场景典型影响常见根因排查优先级卷卡在detaching实例运行正常用户无法分离卷、无法重建实例Cinder驱动调用超时、数据库状态不一致高卷分离立即报VolumeInUse操作直接被拒绝volume_attachment残留记录、Nova/Cinder状态不同步高分离时实例内IO繁忙底层存储无法释放连接实例内进程未停止读写、未提前卸载文件系统中底层Ceph RBD映射未清理卷显示已分离但存储侧连接存在驱动执行中断、主机崩溃后残留映射中Nova与Cinder版本/配置不一致API调用报错或行为不符合预期版本差异、配置项不匹配低这里的表格并不是标准答案但它能帮助你在面对具体异常时快速确定排查方向。举个例子如果你看到卷显示已available但存储侧还有映射关系存在那就要走底层Ceph的清理流程而不是在OpenStack层反复重试。4. Ceph后端最实用的强制分离三板斧如果你用的是Ceph作为Cinder后端生产环境里这几乎是标配卷分离异常的处理手法会比其他后端更具体。Ceph的架构决定了它的清理流程有自己的一套逻辑我把我在生产环境里验证过有效的方法整理成了三个步骤按顺序执行基本能拆解掉绝大多数Ceph场景下的卷分离卡死问题。4.1 第一板斧先确认实例侧已经没有IO很多人一上来就直接到存储层去做清理动作结果发现实例还在持续读写这块盘强制操作下去很可能引发数据不一致。这是很多人容易忽略的顺序问题。我的做法是先确认实例内的状态。如果你能登录进实例执行下面几个操作# 查看该卷对应的设备还有没有进程占用 lsof D /挂载点路径 # 查看挂在实例上的块设备 lsblk # 确认当前挂载关系 df -h | grep 挂载点路径如果实例还能登录最好先在实例内正常卸载文件系统umount /挂载点路径如果umount提示device is busy那说明还有进程在使用用lsof或fuser排查并终止相关进程后再次执行umount。这一步做完底层存储的连接释放就有了基础条件强制操作的风险也会大幅降低。有些情况下你根本登录不进实例比如实例假死这时候就直接进入第二步。4.2 第二板斧在OpenStack层执行强制分离操作实例侧已经停掉IO之后接下来在OpenStack层面处理。这一步的目的是让Nova和Cinder尽快完成它们各自的状态更新尽量把残留清理干净。在计算节点上检查该实例对应的libvirt domain是否还挂载着目标卷# 列出当前实例的块设备信息 virsh dumpxml 实例名 | grep -A 5 disk如果能看到对应的卷先尝试正常detachvirsh detach-disk 实例名 目标设备名 --persistent --live如果detach报错需要在Cinder侧先看一下卷的状态和关联信息# 查看卷的详细信息包括attachment信息 openstack volume show 卷ID # 如果状态仍为in-use可以尝试强制重置状态 openstack volume set --state available 卷ID openstack volume delete --force 卷ID这里有一个重要的提醒openstack volume delete --force是一个危险操作它只应该在底层数据已经确认不需要、或者已经有备份的情况下使用。如果数据还要用就不要在这个步骤里这样操作。你真正需要做的是让OpenStack层面的状态和底层存储的实际状态尽量一致。如果实例已经完全不可用比如实例都删不掉你可能需要从Nova侧清掉实例记录# 强制删除实例谨慎操作 openstack server delete --force 实例ID做完这一步后再次查看卷的状态。如果卷已经回到available说明OpenStack层的状态已经刷新底层存储的清理可以作为收尾动作。4.3 第三板斧Ceph底层的人工清理OpenStack层处理好之后到Ceph节点上确认底层映射情况。这一步很多人会忽略因为从OpenStack控制台上看卷状态已经是available了好像没问题了。但实际上如果底层映射没有清理干净后续会有隐患比如这个卷再挂载到其他实例时可能出现冲突。在Ceph节点上执行# 查看当前rbd映射列表 rbd showmapped # 查看指定卷的watchers状态 rbd status 存储池名/卷名称如果发现有异常的watchers或者残留映射可以手动清理# 解除rbd映射如果是客户端节点 rbd unmap -o force 存储池名/卷名称 # 如果确认该卷没有其他客户端在访问可以刷新watcher rbd feature disable 存储池名/卷名称 exclusive-lock 2/dev/null || true rbd feature enable 存储池名/卷名称 exclusive-lock 2/dev/null || true在操作Ceph底层之前有一个动作非常重要确认所有挂载该卷的客户端都已经不再访问它。RBD的锁定机制exclusive-lock会自动保护正在被使用的卷如果你在客户端还在访问时强行unmap可能会引起IO错误甚至数据损坏。所以我在生产环境里执行这类操作前都会先在监控上或者通过rbd status确认没有活跃客户端。rbd unmap -o force的作用是强制解除本机的设备映射它清理的是客户端侧的映射关系。而如果数据面的锁还在比如blacklisted client通常需要检查Ceph的日志来确认是否有客户端被临时加入黑名单。如果你看到类似blacklisted的报错可以等黑名单过期默认一般是600秒或者手动处理相关客户端。4.4 有没有可能不重启实例就恢复大部分情况下上面的三板斧已经能解决问题。但也有一种情况实例还在正常跑只是某个卷分离不干净此时可以考虑“重新挂载再分离”的操作相当于让OpenStack重新走一遍正常流程。具体做法是用之前的快照或备份确认卷数据完好如果数据重要。将卷重新挂载到实例上即使之前显示还在in-use可能需要先重置状态为available。确认挂载成功后再一次发起分离操作。这个方法的价值在于它让Cinder重新走一遍标准流程有时候能把之前卡住的数据库状态和底层状态重新对齐。我在测试环境里验证过这个方案对于单纯的状态不同步场景成功率很高。但要注意生产环境里做这个操作之前务必确认实例内的业务是否有影响因为重新挂载本身就有短暂的中断风险。5. 折腾完之后的善后检查与长期预防强制处理完卷分离异常之后事情还没结束。如果不做善后检查和预防措施类似的坑大概率还会再踩。这块内容是我实际工作中总结出来的经验不是官方文档里会写的东西但对生产环境的稳定性帮助很大。5.1 善后检查数据库残留记录很多卷分离异常的病根在数据库层面尤其是cinder库里的volume_attachment表。这个表记录了卷与实例的关联信息一旦出现残留记录就会导致卷状态一直显示in-use无法再次挂载。排查残留记录的方法-- 登录cinder数据库 mysql -h 数据库地址 -u cinder -p cinder -- 查看指定卷的attachment记录 SELECT * FROM volume_attachment WHERE volume_id 卷UUID; -- 查看in-use状态但实际没有关联的卷 SELECT v.id, v.status, va.volume_id FROM volumes v LEFT JOIN volume_attachment va ON v.id va.volume_id WHERE v.status in-use AND va.id IS NULL;如果发现残留记录先确认该实例是否真的还在使用这块卷。确认不需要后可以手动清理DELETE FROM volume_attachment WHERE volume_id 卷UUID; UPDATE volumes SET status available, attach_status detached WHERE id 卷UUID;手动删除数据库记录这种事很多人觉得是违规操作但在生产环境里当OpenStack自身的状态机已经无法自愈时这往往是唯一高效的出路。不过操作前必须备份对应行记录确认不会影响其他业务。5.2 长期预防关键配置参数与巡检建议预防卷分离异常最有效的手段是提前发现风险而不是等问题爆发再处理。这里我给几个实用的建议。配置层面cinder.conf里有几个参数值得关注# 控制卷状态的超时时间避免卡死时间过长 volume_service_inet6 False更关键的是要处理好Nova和Cinder的衔接参数。注意检查nova.conf里的cinder_catalog_info和cinder_endpoint_template配置确保Nova能正确调用Cinder的API端点# nova.conf 示例 [oslo_messaging_rabbit] rabbit_host 消息队列节点IP rabbit_port 5672 rabbit_userid openstack rabbit_password 密码再强调一遍Nova和Cinder之间跨组件调用的稳定性有一个前置条件就是服务端点配置和网络策略正确。如果端点地址写错或者防火墙放开不彻底RPC调用就会超时卷分离自然也就卡住。巡检层面我建议把下面几条检查逻辑加入日常巡检脚本每日检查卷状态为detaching的卷检测时长超过10分钟就告警。每周检查cinder数据库volume_attachment表找出异常残留。每周在Ceph节点执行rbd showmapped核对映射列表和OpenStack卷状态是否一致。每两周挑一个非核心卷做一次挂载/分离演练确保链路正常。5.3 制定卷分离的标准操作流程最后一个建议可能有点“非技术”但它非常管用。如果你的团队有多个人在维护OpenStack环境建议把卷分离的操作流程固化成文档。尤其是强制分离的场景谁在什么情况下用了force参数、什么时候动了数据库、什么时候去Ceph层做了unmap这些操作都应该有记录。我见过太多环境是因为每个人处理问题的方式不同导致状态越来越乱。今天A用force detach明天B手动清了数据库后天C在Ceph层强制unmap最后没人说得清楚卷的真实状态。有一份标准操作流程至少能让大家不乱来。写在最后卷分离这件事经历过几次深夜故障之后我对OpenStack各组件之间的协作机制有了更切实的理解。很多问题从表面看是“卷分不开”实际根因五花八门——可能是数据库残留可能是驱动超时可能是底层存储锁没释放也可能是消息队列堵了。排查的过程更像是一个“分层验证”的过程每一层都确认清楚才能最终定位到问题的出口。我自己在操作中还有一个习惯处理完一次卷分离异常后会把当时的日志、命令和状态变化都记录下来哪怕只是一句话。时间久了这些记录会成为很有价值的参考资料下次遇到类似问题时直接查记录比什么都快。另外多说一句卷分离这种操作在变更实施前最好先确认数据安全策略有备份和快照加持的前提下再去处理心态会稳很多。毕竟OpenStack是一个庞大而复杂的系统在它面前保持敬畏多留一条后路总不会错。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进