Trove:对 list 命令的优化

354 阅读2分钟

问题描述

在 OpenStack 中使用 openstack database instance list (后简写 instance list)时 trove api 会与 guestagent 进行通信,但处于 ERROR 状态的实例无法连接 MQ 导致一直阻塞重试直至超时,大大影响效率

问题解决

对于这个问题我首先会想到与 instance list 命令作用差不多的命令 trove list,于是在这两条命令上分别加 --debug 进行对比

  • 首先从结果上来看:instance list 会多一列 Addresses,除此之外显示内容大概相同
  • 然后从发送的请求来看:trove list 只发送了一个 list 请求,即列出实例;但 instance list 在发送一个 list 请求后又对返回的所有实例分别发送一个 show 请求以获取 Addresses,这也说明了为什么二者的结果稍有不同 通过 --debug 选项我们发现问题的所在,于是在配置文件中开启 debug 开始调试以找到更多的细节,在众多的调试信息中寻找与 guestagent 有关的信息
DEBUG trove.instance.models [-] Instance ba30ad79-6399-423e-8568-ff765ad80452 service status is guestagent error. load_instance_with_info /usr/lib/python3.6/site-packages/trove/instance/models.py:579
DEBUG trove.guestagent.api [-] Check Volume Info on instance ba30ad79-6399-423e-8568-ff765ad80452. get_volume_info /usr/lib/python3.6/site-packages/trove/guestagent/api.py:434
DEBUG trove.guestagent.api [-] Calling get_filesystem_stats with timeout 15 _call /usr/lib/python3.6/site-packages/trove/guestagent/api.py:87

首先根据错误信息一直向上找到最近的调试信息,这里猜测应该是 models.py 中的 load_instance_with_info 函数调用了 guestagent/api 中的 get_volume_info,然后其内部通过消息队列与实例中的 guestagent 进行通信,此时在代码中予以验证

# trove/instance/models.py
def load_instance_with_info(cls, context, id, cluster_id=None):
    db_info = get_db_info(context, id, cluster_id)
    load_simple_instance_server_status(context, db_info)
    service_status = InstanceServiceStatus.find_by(instance_id=id)
    LOG.debug("Instance %(instance_id)s service status is %(service_status)s.",
              {'instance_id': id, 'service_status': service_status.status})
    instance = cls(context, db_info, service_status)
    load_guest_info(instance, context, id)
    load_server_group_info(instance, context)
    return instance
  
def load_guest_info(instance, context, id):
    if instance.status not in AGENT_INVALID_STATUSES:
        guest = create_guest_client(context, id)
        try:
            volume_info = guest.get_volume_info()
            instance.volume_used = volume_info['used']
            instance.volume_total = volume_info['total']
        except Exception as e:
            LOG.exception(e)
    return instance
    
# trove/guestagent/api.py
def get_volume_info(self):
    """Make a synchronous call to get volume info for the container."""
    LOG.debug("Check Volume Info on instance %s.", self.id)
    version = self.API_BASE_VERSION

    return self._call("get_filesystem_stats", self.agent_low_timeout,
                      version=version, fs_path=None)

代码条理还是比较清晰的,与猜测的相同,接下来寻找具体的问题,trove/instance/models.py 中的 load_guest_info 函数调用 guestagent 中的函数,从代码中不难看出其逻辑,即如果实例状态不为非法状态的话就获取卷的信息,虽然不知道为什么 show 一个实例需要获取卷信息,但是离谱的是为什么非法状态不包括 ERROR? 此时查看 AGENT_INVALID_STATUSES 的值为 ["BUILD", "REBOOT", "RESIZE", "PROMOTE", "EJECT", "UPGRADE"],不知道这属于 bug 还是有意为之,但这确实是不太合理的

于是在其中加入 ERROR 状态,再次进行调试,错误解决,速度也快了不少,至于后续可能会存在的什么隐患还未可知,就目前来说是没有任何问题