俠義的CMDB都是偏向純資產管理,但運維繫統往往圍繞着這些資產中心,從資產進行不斷外充擴容
在其基礎之外擴展出各功能,通過cmdb 擴展出各個子系統
涉及工具:workbench
一個例子:設計一個數據庫實現主機信息、交換機信息,如何將之間的信息關聯起來
初步的傳統設計:
主機 | 交換機 | user |
資產編號 | 資產編號 | 部門 |
硬件配置信息 | IDC | 使用人 |
機櫃位置 | 機櫃位置 | 業務線 |
外連ip | 外網IP | |
業務線 | 內網IP | |
備註 | 業務線 | |
備註 |
每種屬性都是不同的,就算名稱一樣,那麼字段大小是否考慮過?
到底多少個字段合適,拆表的方式的話,需要拆多少張表?
傳統設計來講,肯定是一個資產一個表,那麼關係型數據庫多少張合適?
如果真是這樣的情況,才能引出CMDB
可以認爲不同型號的產品都是一個資產,那麼不同產品放在一張表中肯定不現實
每個場景一張表,那麼如果新加場景如何考慮?增加字段?增加多少字段?
所以我們要引入一種方式進行實現這些信息,不同信息是不一樣的,比如id信息是一種信息,主機名等也是一種信息,即使分析的再好,一旦廣泛使用起來,那麼需求也陸續膨脹
這樣的設計帶來很大的問題:字段無法控制,擴展性不夠,大量的字段冗餘,看似名字差不多,名字也差不多
引入CMDB
初期版本設計太繁瑣,需要用到的表關聯無計其數,所以需要引入一種新的設計方式來進行,通過字段表進行關聯開
虛擬表設計
先建立兩個表,Schema 和Filed 表
Schema 用於存放所有表
Filed 用於存放各種表的字段,這樣大多數的字段都可以撐得住
設計Schema
這裏存放着表信息,但是不存放字段
那麼這裏的意思肯定是一行對應一個表,相當於Schema 一個id對應一個表
不要看字段,只看行
比如主機表:id=1 name=host desc="描述主機信息"
比如交換機:id=2 name=sw desc="描述交換機信息"
那麼它的具體字段是存放在Filed表
設計Filed表
# meta是元數據
從關聯的表,逐漸以每一行來表述,每一行都代表一個字段
首先考慮是一對多還是多對多
要求一個字段只能對應某一個明確的表中,即使字段名稱一樣,但是類型不一樣,類型即使一樣其他屬性也不一樣,即使同一個字段,但是所謂的描述信息不一樣,有的int 有的bigint 等等
即使看似像同一字段,可複用的功能性不是很強,但是實現可複用情況一定很高
所以採取簡單化的設計:通過不同表的字段和其他表的字段沒有任何關係
爲了簡化這樣的關係,這裏的meta描述是不一樣的
那麼這兩個表如何建立關聯?
一個filed id只能屬於一張表,比如只能屬於host表
多對一關係的建立
再來看一下filed表結構,它不但幫我們建了字段還添加了主鍵
查看外鍵約束
明確說明了外鍵是引用了schema 這個表,
而且用的是自己的id 來引用的schema id
理解這樣的關係
假設:
schema
id =1
name = host
meta = 信息爲主機
filed
id = 1
name = ip
meta = 先不管
schema_id BIGINT = 1
再寫一個信息
id = 2
name =hostname
meta = 先不管
schema_id BIGINT =1
只要schema_id 是 1的 代表生成了一張host表
而這個host表有兩個字段 1 和 2
1是描述這個ip的 2 是描述ip的
這就建立了一種關聯關係
建立sw表
如果順序往後排,那麼schema id 就是2
如果序號如果對應的話,就是3 和 4,唯一代表一個字段
這種邏輯上的關係被稱爲虛擬表
再有一個資產來的話,再加一張表就可以了,無非就是加了一行
以上是一對多關係,在多端添加字段schema_id 解決
描述資產比較難,不同資產有不同的屬性,比較難在一張表中設計固定個數
所以通過schema 和 filed 組合 在filed表中建立多個記錄來描述,只要在filed表中增加一條記錄描述即可
這樣兩者構建成了一個虛擬表,來描述邏輯上的表
schema 只描述表是誰
filed 只描述字段,動態添加
中間通過外鍵約束來構建成虛擬表,達到動態增加資產的需求
一個栗子
需求
建立一個業務 ipaddress表,對應schema_id 爲 10,它有2個字段,字段的描述在filed中,
filed.id = 1, name 和字段 filed.id = 5,name 這兩部分構成一張表的定義
分析
一個字段是一行記錄在filed表中,可以跟其形成一張邏輯表,就是ipaddres表
ipaddress表對應的schema_id 爲10
必須定義兩個ipaddress,id肯定不一樣的,但是描述不一樣,這樣肯定搞混,建議再加一個UQ 保證名字不重複
還需要根據提交的邏輯表名稱,萬一尾部多敲空格,那麼是否需要檢驗空格
邏輯表設計
加入一個表entity,用於記錄主機,一對多關係,一個主機的描述信息只屬於一個
設計字段
id | BIGINT | 唯一標識虛擬表的記錄 |
key | VARCHAR | 用於存放UUID |
添加value表
id | BIGINT | 自增 |
value | VARCHAR | 存什麼? |
現在的我們想的是將這些信息存放於value表中
這樣就引出了兩個字段:IP和HOSTNAME
那麼回到entity中,既然是存值,那麼是必須有id 唯一標識,新加字段
entity 與 value關聯關係:
一對多關係,entity只有一個id,value中有多個字段,那麼爲了描述這一個id對應的一行記錄,這兩個字段都要放在value中
如何描述字段,如何知道是哪個字段?那麼filed還需要與value建立關係
建立表關係
記錄哪個虛擬表完全靠schema_id 來表示,比如schema_id = 1 那麼就相當於找host表
假如描述這邊的字段該如何去關聯?
描述字段關係
這裏value 對應的就是就是entity_id 的而entity 又是唯一對應了schema_id
雖然是多端,這樣看只能對應一個,但是關聯起來之後從schema表中就能夠充分體現出是對應多個表id
只不過是中間做了一層過度,這樣每個表只對應一個id即可。 但是不能描述對應的哪些字段,所需還需要與filed進行關聯
這樣後期加字段或者表的時候直接加一行記錄即可
如果在使用的一張表在使用中,添加字段的話,物理結構也跟隨發生改變,那如果是虛擬表在filed表中添加字段,那麼就又生成了filed表的id來對應一些信息
那這樣的話添加的代價會下降很多,假如字段描述爲空的話原來的虛擬表生成的記錄可以不動,如果不爲空可以做一系列缺省值的設置
由filed表中的meta中進行定義字段 多類型
可以有約束也可以沒有 代碼中寫明確即可,看實際場景,設計的時候先設計主表,將最關聯的幾張表列出,這幾個表中又有其他描述性的信息在其他表裏依次做join就可以了,其他信息再進行關聯
生成工程
-- MySQL Workbench Forward Engineering SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0; SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0; SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES'; -- ----------------------------------------------------- -- Schema cmdb -- ----------------------------------------------------- -- ----------------------------------------------------- -- Schema cmdb -- ----------------------------------------------------- CREATE SCHEMA IF NOT EXISTS `cmdb` DEFAULT CHARACTER SET utf8 ; USE `cmdb` ; -- ----------------------------------------------------- -- Table `cmdb`.`schema` -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS `cmdb`.`schema` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `name` VARCHAR(45) NOT NULL, `desc` VARCHAR(45) NULL, PRIMARY KEY (`id`)) ENGINE = InnoDB; -- ----------------------------------------------------- -- Table `cmdb`.`field` -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS `cmdb`.`field` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `name` VARCHAR(45) NOT NULL, `meta` TEXT NULL, `schema_id` BIGINT NOT NULL, PRIMARY KEY (`id`), INDEX `fk_field_schema_idx` (`schema_id` ASC), CONSTRAINT `fk_field_schema` FOREIGN KEY (`schema_id`) REFERENCES `cmdb`.`schema` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB; -- ----------------------------------------------------- -- Table `cmdb`.`entity` -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS `cmdb`.`entity` ( `id` INT NOT NULL, `key` VARCHAR(45) NOT NULL COMMENT '唯一描述', `schema_id` BIGINT NOT NULL, PRIMARY KEY (`id`), INDEX `fk_entity_schema1_idx` (`schema_id` ASC), CONSTRAINT `fk_entity_schema1` FOREIGN KEY (`schema_id`) REFERENCES `cmdb`.`schema` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB; -- ----------------------------------------------------- -- Table `cmdb`.`value` -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS `cmdb`.`value` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `value` VARCHAR(45) NOT NULL, `field_id` BIGINT NOT NULL, `entity_id` INT NOT NULL, PRIMARY KEY (`id`), INDEX `fk_value_field1_idx` (`field_id` ASC), INDEX `fk_value_entity1_idx` (`entity_id` ASC), CONSTRAINT `fk_value_field1` FOREIGN KEY (`field_id`) REFERENCES `cmdb`.`field` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, CONSTRAINT `fk_value_entity1` FOREIGN KEY (`entity_id`) REFERENCES `cmdb`.`entity` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB COMMENT = ''; SET SQL_MODE=@OLD_SQL_MODE; SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;