ovirt中文环境下虚拟机迁移异常跟踪

来源:互联网 发布:财新数据可视化实验室 编辑:程序博客网 时间:2024/05/18 01:34

        在客户现场发现1个体验很差的问题,负载均衡触发的虚拟机迁移,使得虚拟机一直保持在迁移状态,更严重的是,此时的虚拟机失去管控,前端既不能关闭它,也不能通过控制台使用它,最后客户着急了,凌晨将研发人员叫到现场解决问题。

        迁移失败其实是有别的与原因引起的,如两边主机名相同,如虚拟机使用的cache模式不为none, 或者另一边的主机启动虚拟机失败等等。或许迁移失败是可以接受的,但是迁移失败导致虚拟机一直处于迁移状态不可使用不可恢复,那问题就严重了,其实还有更严重的,如果重启两边主机的vdsm服务,虚拟机能从迁移状态中恢复回来,但是虚拟机迁移时目标主机预留的内存,pending_vmem_size, 并没有回收回来,而且是永久的,除非手动修改数据库,否则这部分内存就永远被“雪藏“了,不能再用于虚拟机的分配。

        这么严重的一个问题,最后居然发现是由于python对中文的处理导致异常引起的。虚拟机的迁移属于异步调度任务,调度时的处理在virt/migration.py中:

    def run(self):
        try:
            startTime = time.time()
            self._setupVdsConnection()
            self._setupRemoteMachineParams()
            self._prepareGuest()
            with SourceThread._ongoingMigrations:
                try:
                    if self._migrationCanceledEvt:
                        self._raiseAbortError()
                    self.log.debug(
                        "migration semaphore acquired after %d seconds",
                        time.time() - startTime)
                    params = {
                        'dst': self._dst,
                        'mode': self._mode,
                        'method': self._method,
                        'dstparams': self._dstparams,
                        'dstqemu': self._dstqemu,
                    }
                    with self._vm.migration_parameters(params):
                        self._vm.saveState()
                        self._startUnderlyingMigration(time.time())
                        self._finishSuccessfully()
                except libvirt.libvirtError as e:
                    if e.get_error_code() == libvirt.VIR_ERR_OPERATION_ABORTED:
                        self.status['status']['code'] = \
                            errCode['migCancelErr']['status']['code']
                        self.status['status']['message'] = 'Migration canceled'
                        self.status['progress'] = 0
                    raise
        except Exception as e:
            self.log.error("Failed to migrate", exc_info=True)
           self._recover(str(e))

        问题就出在最后的异常处理,调度self._recover来恢复虚拟机的状态,使其能与engine管理端正常同步状态,但是如果e中包含有中文,则调用str(e)直接会抛出异常,从而跳过了recover的执行,导致了悲剧,由于libvirt的异常使用utf-8编码,所以我们只需要将最后一句改成 self._recover(e.message.decode('utf-8'))就好了,虚拟机迁移失败,迅速回到可用状态。