Skip to content

用ResourceVO定义一个资源

zhangxin edited this page May 2, 2017 · 2 revisions

背景

ZStack中一个资源(例如Zone、Cluster、VM)都由UUID唯一标识,大都有一个字段name表示资源的名称。ZStack用一些表维护资源之间的关系,例如AccountResourceRefVO维护各个资源与账号的关系,SystemVO表中有resourceUuid字段维护资源和系统标签之间的关系。AccountResourceRefVO的部分定义如下:

CREATE TABLE  `zstack`.`AccountResourceRefVO` (
    `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT,
    `accountUuid` varchar(32) NOT NULL,   # 资源所属账户
    `resourceUuid` varchar(32) NOT NULL,  # 资源UUID
    `resourceType` varchar(255) NOT NULL, # 资源类型
    PRIMARY KEY  (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

这里resourceUuid字段表示资源UUID,reesourceType表示资源类型,根据resourceType的不同,UUID代表不同资源。这种表设计方法称为Ploymorphic Associations,在数据库设计中是典型的anti-pattern。但为了让Java编程更加容易和OO,我们仍然采用这种设计。该设计带来的主要问题是无法使用数据库的foreign key维护数据一致性,因为同一foreign key无法指向多个parent表(部分数据允许,但要求每张表里都有相同的内容)。所以AccountResourceRefVO表的resourceUuid字段无法使用foreign key同时指向VmInstanceVO和ImageVO表。这样带来的结果是,我们需要在application层面维护AccountResourceRefVO表的一致性,例如删除了一个VM后,要清理AccountResourceRefVO对应的条目。

使用ResourceVO

为了在应用层面方便的维护AccountResourceRefVO等使用Ploymorphic Associations设计的表的一致性,我们引入ResourceVO表作为所有资源的父表,该表设计如下:

CREATE TABLE `ResourceVO` (
  `uuid` varchar(32) NOT NULL UNIQUE, # 资源UUID
  `resourceName` varchar(255) DEFAULT NULL, # 资源名称
  `resourceType` varchar(255) DEFAULT NULL, # 资源类型
  PRIMARY KEY (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

resourceName和resourceType两个字段程序员无需关心,写入数据库时程序自动生成。

在Java程序中,对应的资源需要继承ResourceVO类,例如EipVO:

@Entity
@Table
public class EipVO extends ResourceVO {

EipVO表不再定义uuid字段,该字段由ResourceVO提供,name字段由各个资源类自定义。

资源应该尽可能使用单词name作为名字字段,如果使用了非name单词,需要通过@ResourceAttributes指定名字字段,例如: java @Entity @Table @ResourceAttributes(nameField = "jobName") public class SchedulerVO extends ResourceVO {

工作原理

由于所有资源类继承了ResourceVO类,JPA在删除一个子资源的时候,会将ResourceVO对应的row同时删除。这样AccountResourceRefVO等表只要将resourceUuid设置一个ON DELETE CASCADE foreign key到ResourceVO表即可维护数据的一致性。

UUID/名字翻译

ResourceVO表的另一个功能是实现资源UUID到资源name的翻译功能。例如知道一个UUID 1f89148d5fb74604a64403d83f67db12,不知道该UUID代表的是什么资源,又需要知道它的名字时,可以使用如下API:

curl -H "Content-Type: application/json" -H "Authorization: OAuth aa21b8a1fe9749fea2e96ebba7a11518" -X GET http://localhost:8080/v1/resources/names?uuids=1f89148d5fb74604a64403d83f67db12&uuids=8918fcec918d4b19a0485be700ed98f1
``