俠義的CMDB都是偏向純資產管理,但運維繫統每每圍繞着這些資產中心,從資產進行不斷外充擴容數據庫
在其基礎以外擴展出各功能,經過cmdb 擴展出各個子系統 運維
涉及工具: workbenchide
一個例子:設計一個數據庫實現主機信息、交換機信息,如何將之間的信息關聯起來
工具
初步的傳統設計:spa
主機 |
交換機 |
user |
資產編號 |
資產編號 |
部門 |
硬件配置信息 |
IDC |
使用人設計 |
機櫃位置 |
機櫃位置 |
業務線 |
外連ip |
外網IP |
|
業務線 |
內網IP |
|
備註 |
業務線 |
|
備註 |
每種屬性都是不一樣的,就算名稱同樣,那麼字段大小是否考慮過?orm
到底多少個字段合適,拆表的方式的話,須要拆多少張表?blog
傳統設計來說,確定是一個資產一個表,那麼關係型數據庫多少張合適?ip
若是真是這樣的狀況,才能引出CMDBrem
能夠認爲不一樣型號的產品都是一個資產,那麼不一樣產品放在一張表中確定不現實
每一個場景一張表,那麼若是新加場景如何考慮?增長字段?增長多少字段?
因此咱們要引入一種方式進行實現這些信息,不一樣信息是不同的,好比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;