ZStack--查询API

     IaaS软件用户面临的共同挑战是如何快速、准确地找到一个想要的资源;例如,从10,000台虚拟机中发现有EIP(16.16.16.16)的虚拟机。大多数IaaS软件通过API中的特定查询逻辑解决这个问题。ZStack不用特定查询,而是配备了一个框架,这个框架可以自动为每个资源的每个字段生成查询,并联合跨越了多个资源的查询,帮助用户管理云端数量庞大的资源。

    动机

    一个中型的云可以管理几百台物理主机和成千上万台虚拟机,因为IaaS软件很少有全部的查询API,导致寻找想要的资源成为挑战。大多数IaaS软件只允许用户使用少量条件(如name,UUID)查询资源,这些条件硬编码在查询AP中。如果用户想要使用硬编码之外的条件做一个查询,例如,通过创建日期查询虚拟机,他们可能不得不最终列出所有虚拟机,然后用for..loop来过滤结果。使用任意字段查询资源至今在大多数IaaS软件中都不被完全支持,更不用说联合查询;例如,如果用户想要找到一个虚拟机,这个虚拟机的网卡应用了特定的安全组规则,他们可能不得不列出所有资源(虚拟机,安全组),然后做两次for..loop。

    另一方面,相比类似JIRA的软件,大多数IaaS软件的UI是最粗糙简陋的。许多开发人员可能并没有意识到糟糕UI的根源不是因为UI开发人员缺乏CSS/HTML/JavaScript的技能,而是软件本身并不能提供强大的API来支持复杂的UI;例如,为了实现一个类似JIRA过滤器的功能,即只显示满足指定条件的资源,UI可能需要做很多由listing all then filtering by for..loop的后置处理工作,这些后置处理工作需要把大量的资源拧在一起。

    IaaS软件因此饱受折磨了一段时间;对此的解药就是要提供一种机制,这种机制可以自动为每个资源的每个字段都生成查询,而且可以处理join查询。

    问题

    大多数IaaS软件使用关系型数据库(如MySQL)作为后台数据库,在这种数据库中资源通常被安排在单独的表中,比如虚拟机表,主机表,云盘表。对于每一个资源,都有一个API用来获取该资源的单独的一条记录,它可能被命名为describe API、list API或query API;这些API通常有硬编码的参数,用来暴露一部分数据库表的列,允许用户通过少量的查询条件查询资源;这些参数是精心选择的,通常是对API设计者自身非常重要的列,例如,name、UUID。然而,由于并不是所有的列都被暴露,用户经常遇到他们想查询的列不存在的情况,这样他们就必须检索所有的资源,然后使用一个或多个for..loop进行后置处理。

    一个复杂的查询场景,可能需要使用联合查询,这种查询通常跨越多个数据库表;例如,找到一个EIP为16.16.16.16的虚拟机,它可能涉及虚拟表、网卡表和EIP表。一些IaaS软件使用数据库视图解决这个问题,这是另一种硬编码方式,只能以固定的格式join选中的表,而在现实中表是能以非常复杂的方式被join的。在软件升级过程中,如果一个视图指向的任一表已经改变了的话,视图也需要进行数据库迁移操作。

    查询API

    为了避免在API中手动编码查询逻辑,并给用户提供能在任何地方查询任何东西的灵活的查询,ZStack创建了一个框架,这个框架可以自动为所有资源生成查询,并且不需要开发者写代码去实现查询逻辑;更进一步,该框架还可以生成各种join查询,只要所需的表已经通过外键连接。

    在以下篇幅中,我们将用zone作为一个例子来阐述这个令人惊叹的框架。一个zone在数据库中有下面的这些列:

    用户可以通过任何一个字段或字段组合来查询zone,并采用常规的SQL比较运算符如'=', '!=', '>', '>=', '<', '<=', 'in', 'not in', 'is null', 'is not null', 'like', 'not like'。

 注意:在命令行工具中,一些运算符有不同的格式:'in'(?=), 'not in'(!?=), 'is null'(=null), 'is not null'(!=null), 'like'(~=), 'not like'(!~=).

    因为zone是ZStack中主要资源的祖先,很多资源都或多或少和它有关系;例如,一个运行中的虚拟机总是在一个zone内。像这种关系可以生成联合查询,如:

    如上表格所示,一个zone不会暴露任何叫vmInstance的字段,但在上述查询中有一个条件是由'vmInstance'开始的。这种查询在ZStack中称为扩展查询。这里vmInstance代表VM表,VM表有一个字段为zoneUuid(外键)指向zone表,因此查询框架可以理解它们的关系并生成联合查询。上面的例子可以被解释为“寻找运行着名字为web-vm1的虚拟机的zone”。进一步扩展这个例子,因为虚拟机网卡表有外键指向VM表,并且EIP表有外键指向虚拟机网卡表,查询zone也可以使用EIP作为条件:

    查询被解释为“查找一个区域,它上面的虚拟机的网卡的EIP为 16.16.16.16”。现在您知道了查询接口的强大之处了!我们甚至可以创建一些非常复杂的查询:

    这个复杂的查询目的是找到磁盘快照,目标磁盘快照是由虚拟机磁盘创建的,而该虚拟机有网卡在L3网络上,这个L3网络的父L2网络则是附加在一个集群上的,这个集群的uuid是13238c8e0591444e9160df4d3636be82。不要惊慌,你很少需要这么复杂的查询,但它确实证明了框架的能力。此外,SQL的一些特性例如选择字段、排序、计数和分页也是支持的:

    实现

    尽管查询API功能是如此强大,实现却是非常简洁的。当添加一个新的资源时,开发人员不需要写任何关于查询逻辑的代码,除了定义查询API和资源本身。要实现zone的查询API,开发人员需要:

    1使用查询元数据注解zone的inventory

    上面的注解声明了zone和其他资源之间的关系,这是zone扩展查询的基础。

    2定义一个查询API

    3在区域的API配置文件中声明查询API

    API APIQueryZoneMsg通过指定服务ID query被路由到查询服务。就是这样了,查询逻辑不需要一行代码;查询服务会把其余部分自动完成。所有的ZStack查询API都像这样定义,添加新资源的查询API是非常容易的。

    当前限制

    主要的限制是在查询条件中,只有逻辑AND是被支持的,OR是不被支持的。例如:

    上述查询语句可以被解释为“寻找区域名字为west-coast且state是Enabled的区域”我们这么做的原因是我们由ZStack源代码中SQL的使用分析得出99%的组合的查询条件都是基于AND逻辑的。另一方面,如果逻辑OR在没有创建DSL的情况下就被引入,要保持代码简洁是非常困难的。然而,在很多情况下,OR可以使用比较操作in(?=)实现:

    上述例子表述的是“寻找名字为west-coast的区域,并且它的状态是Enabled或Disabled”,将来,我们将引入DSL风格的查询语言,例如:

    总结

    这篇文章中,我们演示了ZStack的查询API。通过使用这个强大的工具,用户能以类似关系型数据库的方式查询任何资源。将来,ZStack将建立一套高级的UI,它可以使用查询API创建各种各样的视图(过滤器),例如,展示所有运行在同一L3网络的虚拟机,为IaaS UI的用户体验带来革命性的改变。

你可能感兴趣的:(ZStack--查询API)