写此文的目的
转眼间 OpenStack 已经发展到了 K,马上 L 版本开发周期也要开始了。记得我最早接触的是 OpenStack 的 E 版本,时间过去了 2 年多,OpenStack 社区仍然如火如荼,OpenStack 玩家,特别是重量级玩家越来越多,通过每次 OpenStack 峰会的报道、社区的 user survey 以及圈里的分享,我们发现 OpenStack 的生产环境部署也越来越多,但是相信很多企业,很多人,在使用 OpenStack 的过程中仍然很痛苦。安装部署困难,系统复杂性,过于灵活的架构,眼花缭乱的配置项,特别是系统搭建好以后,运行过程中各种各样的错误等,足以让一个充满热情的人望而却步。关于安装部署,目前已有有很多开源工具在做,像 TripleO、Fuel、RDO 以及一些像 Ansible、Puppet、Chef 等更 native 的工具,已经极大程度的降低了安装 OpenStack 的门槛,我就不再过多阐述。而关于运行期间如何排错,如何掌握系统的运行状态,在不了解系统实现原理的情况下,也会令人一筹莫展。当然,已经有很多发行版中包含了这部分功能。
本文的目的不是指导读者写一个新的类似的工具,而是分析为了配合这些工具,可以使用到的 OpenStack 自身能力。当然,系统的监控运维是一个大的话题,我能力和视野有限,喷不了那么多(没有真正用过的东西,我也不愿意喷),像主机的 CPU 监控、进程监控、网络流量监控、存储监控这些,也不在本文的范畴内。
言归正传,说说本文主要内容。OpenStack 有很多模块,但其中最为核心的当然是 Nova,所以本文就以 Nova 为例,来看一下如何通过 Nova 提供的能力来获取系统运行期间的状态。我把这些状态分为两类,一类是系统整体情况一览(系统状态),而是虚拟机相关的状态信息(虚拟机状态)。当然,以我一贯的风格,你会看到更多的 OpenStack 实现原理。
Nova 版本:Kilo
系统状态
Nova 提供这么几个资源状态的查询。
Service
Nova 中的 service 有两类,一类是所谓的 control service,一类就是 compute service。要想获取 Nova 的 service 详细信息,必须要启用 os-extended-services 扩展。
service 的详细信息主要包括如下几项:
binary, host, zone, status, state
其中:
- binary,可以理解为 service 的名称,类似于 nova-compute。
- host 是 service 所在的主机名称。
- zone 是 service 所属的 AZ,其实就是 service 所在的主机所属的 aggregate,只是 aggregate 的概念不对外呈现,所以用户看到的是 AZ。其实,在 Nova 内部,AZ 是 AG 的 metadata 而已。
- zone 的确定,涉及到两个配置项,对于非计算节点,zone 的名称依赖于配置项 internal_service_availability_zone(默认是 inte rnal)。
- 对于计算节点,如果不属于任何 AG,或者所属的 AG 没有 AZ 的 metadata 信息,默认的 zone 依赖于配置项 default_availability_zone(默认是 nova)。
- status 是服务 disable 属性的体现,该属性可以直接通过 API 修改 ;
- state 是服务真实的状态,是通过 servicegroup api 获取。每个服务在启动时会加入 servicegroup,以 db 后端为例,会在服务中启动定时器,更新 service 表中的
report_count
的值,同时也会刷新更新时间,后续会根据这个更新时间确定服务的死活;
当然,查询 service 信息也支持过滤条件,比如:
- 查询某个 host 相关的 service;
- 按 binary 名称查询 service。
知道了 service 的信息后,就至少能够获取到 Nova 各个服务的运行状态,从而判断系统是否健康。
Host
其实 Nova 中没有 host 这个独立的资源(数据库对象),但是 Nova 却有针对 host 的 API 操作,其实,在内部实现中,就是通过前面的 service 信息,间接组装返回 host 信息。
即:你可以获取系统中所有的主机信息,其中包括:主机名称、主机上的服务、主机所属的 AZ。
Hypervisor
hypervisor 的概念在 OpenStack 中其实不好理解。在使用 KVM 的环境中,hypervisor 通常是就是只 nova-compute 进程所在的主机;而在类 VMware 环境中(之所以说类 VMware,是因为华为也有一款虚拟化产品 FusionCompute 也是类似的架构),hypervisor 是指 nova-compute 进程下的一个’node’,对应于一个 vCenter 集群。换句话说,你可以把一个 hypervisor 看成一个 nova-compute 下的一个 node,KVM 的情况是一个特例而已。一个 hypervisor,是创建虚拟机能够调度到的最小单元。
Nova 中对于 hypervisor 的查询情况支持较为丰富。
- 查询所有的 hypervisor 概要信息。包含一个 id 和一个 hypervisor host name,如果启用了 os-hypervisor-status extension,还会返回 hypervisor 所属的 nova-compute 服务状态。
- 查询所有的 hypervisor 详细信息。除了包含上述信息外,还包含每个 hypervisor 的资源使用信息。如果启用 os-extended-hypervisors extension,还会包含 hypervisor 所属的 nova-compute 所在主机的 IP 地址。
- 查询所有 hypervisor 所使用的系统资源总量。即,系统计算资源使用量的一个总览。
- 模糊查询某些 hypervisor 的概要信息。
- 查询单个 hypervisor 资源使用的详细信息。
- 模糊查询某些 hypervisor 上的虚拟机信息,包含虚拟机的 ID 和名称。
可见,Nova 中的 hypervisor 给管理员提供了较为丰富系统计算资源使用情况的查询接口,通过对 hypervisor 使用情况的了解,管理员可以更有效地进行系统监控,并且为系统维护(扩容、减容、动态资源调整等)提供依据。
租户视角的系统状态
上面的几个资源,默认都是管理员有权限查询,普通租户是看不到的。那么作为租户,能够对系统使用状态有一个什么样的了解呢?
租户的资源配额
租户可以查询自己的资源配额限制和使用情况,管理员(admin)可以查询普通租户的资源配额使用情况(os-used-limits-for-admin extension)。参见这里, 这里和这里。
如下是租户查到的自己的资源配额限制和使用情况(片段):
{ "limits": { "absolute": { "maxImageMeta": 128, "maxPersonality": 5, "maxPersonalitySize": 10240, "maxSecurityGroupRules": 20, "maxSecurityGroups": 10, "maxServerMeta": 128, "maxTotalCores": 20, "maxTotalFloatingIps": 10, "maxTotalInstances": 10, "maxTotalKeypairs": 100, "maxTotalRAMSize": 51200, "maxServerGroups": 10, "maxServerGroupMembers": 10, "totalCoresUsed": 0, "totalInstancesUsed": 0, "totalRAMUsed": 0, "totalSecurityGroupsUsed": 0, "totalFloatingIpsUsed": 0, "totalServerGroupsUsed": ...
租户的资源使用量
管理员可以查询所有租户对计算资源的使用量,也可以查询某个租户的计算资源使用量(包括每个虚拟机计算资源使用信息),参见这里。
示例 1,管理员查询租户对计算资源的使用量:
{ "tenant_usages": [ { "start": "2012-10-08T21:10:44.587336", "stop": "2012-10-08T22:10:44.587336", "tenant_id": "openstack", "total_hours": 1.0, "total_local_gb_usage": 1.0, "total_memory_mb_usage": 512.0, "total_vcpus_usage": 1.0 } ] }
示例 2,查询某个租户的计算资源使用量:
{ "tenant_usage": { "server_usages": [ { "ended_at": null, "flavor": "m1.tiny", "hours": 1.0, "instance_id": "1f1deceb-17b5-4c04-84c7-e0d4499c8fe0", "local_gb": 1, "memory_mb": 512, "name": "new-server-test", "started_at": "2012-10-08T20:10:44.541277", "state": "active", "tenant_id": "openstack", "uptime": 3600, "vcpus": 1 } ], "start": "2012-10-08T20:10:44.587336", "stop": "2012-10-08T21:10:44.587336", "tenant_id": "openstack", "total_hours": 1.0, "total_local_gb_usage": 1.0, "total_memory_mb_usage": 512.0, "total_vcpus_usage": 1.0 } }
虚拟机状态
说到底,作为 IaaS,OpenStack 玩的还是虚拟机,因为各种资源(存储、网络)都是为了更好的使用虚拟机服务。所以对虚拟机状态的掌握就显得格外重要。
虚拟机操作事件通知
用户对虚拟机的每个操作(开始和结束),都会通过消息队列向外部发送通知,外部系统可以通过接收通知,了解系统的运行过程。使用通知的另外一个好处,就是可以与 Nova 解耦,作为外部系统的数据源,实现系统的监控分析。Ceilometer、StackTach 和 Monasca 都用到了 Nova 的通知作为自己的数据源。
与此同时,虚拟机 state 或 task_state 发生变化时,也会向外部发送通知。前提是配置项 notify_on_state_change 要配置为 vm_state 或 vm_and_task_state。
另外,Nova 中除了上述说的操作事件通知外,还有一种审计通知,即在一段时间内的系统资源状态,相关的配置项 instance_usage_audit_period,目前 Nova 中只有 event_type 类型为 compute.instance.exists 一种审计通知,这种通知可以让你对一段周期内系统中存在的虚拟机有一个全局的了解。
虚拟机操作事件记录
Nova 中的虚拟机每个操作(启动、停止、暂停、恢复等),都会在 db 中保存相关的操作记录,给用户提供查询。利用这个功能,用户对自己的虚拟机整个生命周期的过程和状态都会了如指掌,便于用户的管理。参见这里。示例如下:
{ "instanceActions": [ { "action": "resize", "instance_uuid": "b48316c5-71e8-45e4-9884-6c78055b9b13", "message": "", "project_id": "842", "request_id": "req-25517360-b757-47d3-be45-0e8d2a01b36a", "start_time": "2012-12-05 01:00:00.000000", "user_id": "789" }, { "action": "reboot", "instance_uuid": "b48316c5-71e8-45e4-9884-6c78055b9b13", "message": "", "project_id": "147", "request_id": "req-3293a3f1-b44c-4609-b8d2-d81b105636b8", "start_time": "2012-12-05 00:00:00.000000", "user_id": "789" } ] }
在内部实现中,nova-api 层会记录 action 开始的记录,在 nova-compute 层,则会添加 event 开始和结束的信息,action 和 event 根据 request id(一次消息请求的标识)关联。
虚拟机错误信息记录
因为 OpenStack 的安装部署复杂性,或者操作过程对环境、配置等要求比较苛刻,稍不注意,就有可能发生错误。一旦发生错误,除了从日志中获取错误信息外,还有什么比较方便、快捷的方式能够迅速定位错误呢?
在 API 层发生错误,用户会立即看到错误码和错误信息。但如果是在 conductor,scheduler 或 compute 层发生错误呢?
OpenStack 智慧的社区开发者们已经为我们提供了这种能力。其实还是利用 DB 和通知机制来实现。
- 先说通知,虚拟机操作异常时,一般都会发送 error 通知,通知中包含异常的函数名称、异常时函数的参数以及异常信息。
- 再说 db,虚拟机操作异常时,无论是在 conductor, scheduler 还是 compute 层,除了会发送通知外,还会记录异常信息到数据库(
instance_faults
表),当查询虚拟机信息时,会返回虚拟机的异常信息。
虚拟机诊断信息
租户可以查询虚拟机使用过程中的一些统计信息,比如虚拟机磁盘的读写情况、网络的 IO 情况等,对于 KVM 来讲,这些信息都是通过 libvirt 接口获取。
API 示例参见这里。返回消息示例:
{ "vnet0_tx_errors": 0, "vda_errors": -1, "vda_read": 4447232, "vda_write": 4347904, "vnet0_tx_packets": 1259, "vda_write_req": 3523, "memory-actual": 524288, "cpu0_time": 195230000000, "vnet0_tx": 364840, "vnet0_rx_drop": 0, "vnet0_rx_packets": 1423, "vnet0_rx_errors": 0, "memory": 524288, "memory-rss": 243188, "vda_read_req": 291, "vnet0_rx": 363725, "vnet0_tx_drop": 0 }
参考链接
- https://wiki.openstack.org/wiki/SystemUsageData
- https://wiki.openstack.org/wiki/NotificationEventExamples
- https://github.com/rackerlabs/yagi
- http://www.stacktach.com/
作者简介
孔令贤,华为技术有限公司云计算领域 OpenStack 社区团队技术主管,2011 年加入华为西安研究所,一直从事云计算相关方向的研发工作。于 2012 年开始研究 OpenStack,其个人博客(CSDN 博客: http://blog.csdn.net/lynn_kong ,Github 博客: http://lingxiankong.github.io/ 多次被业内人士学习和转载。同时,积极组织和推动 OpenStack 在国内的技术交流和活动,多次以主讲人的身份参加 OpenStack 西安 meetup。
感谢丁晓昀对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ , @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流。
评论