從零打造一個CMDB(一)數據庫設計

俠義的CMDB都是偏向純資產管理,但運維繫統往往圍繞着這些資產中心,從資產進行不斷外充擴容

在其基礎之外擴展出各功能,通過cmdb 擴展出各個子系統 

涉及工具:workbench


一個例子:設計一個數據庫實現主機信息、交換機信息,如何將之間的信息關聯起來

初步的傳統設計:

主機
交換機
user
資產編號
資產編號
部門
硬件配置信息
 IDC

使用人

機櫃位置
 機櫃位置
業務線
外連ip
外網IP

業務線
內網IP

備註
業務線


  備註

每種屬性都是不同的,就算名稱一樣,那麼字段大小是否考慮過?

到底多少個字段合適,拆表的方式的話,需要拆多少張表?

傳統設計來講,肯定是一個資產一個表,那麼關係型數據庫多少張合適?

如果真是這樣的情況,才能引出CMDB


可以認爲不同型號的產品都是一個資產,那麼不同產品放在一張表中肯定不現實

每個場景一張表,那麼如果新加場景如何考慮?增加字段?增加多少字段?

所以我們要引入一種方式進行實現這些信息,不同信息是不一樣的,比如id信息是一種信息,主機名等也是一種信息,即使分析的再好,一旦廣泛使用起來,那麼需求也陸續膨脹

這樣的設計帶來很大的問題:字段無法控制,擴展性不夠,大量的字段冗餘,看似名字差不多,名字也差不多



引入CMDB

初期版本設計太繁瑣,需要用到的表關聯無計其數,所以需要引入一種新的設計方式來進行,通過字段表進行關聯開


虛擬表設計


先建立兩個表,Schema 和Filed 表

9921148.png

Schema 用於存放所有表

Filed  用於存放各種表的字段,這樣大多數的字段都可以撐得住


設計Schema

10343256.png

這裏存放着表信息,但是不存放字段

那麼這裏的意思肯定是一行對應一個表,相當於Schema 一個id對應一個表

不要看字段,只看行

比如主機表:id=1 name=host  desc="描述主機信息"

比如交換機:id=2 name=sw desc="描述交換機信息"


那麼它的具體字段是存放在Filed表

設計Filed表

12460158.png

# meta是元數據

從關聯的表,逐漸以每一行來表述,每一行都代表一個字段

首先考慮是一對多還是多對多

要求一個字段只能對應某一個明確的表中,即使字段名稱一樣,但是類型不一樣,類型即使一樣其他屬性也不一樣,即使同一個字段,但是所謂的描述信息不一樣,有的int 有的bigint 等等

即使看似像同一字段,可複用的功能性不是很強,但是實現可複用情況一定很高

所以採取簡單化的設計:通過不同表的字段和其他表的字段沒有任何關係

爲了簡化這樣的關係,這裏的meta描述是不一樣的


那麼這兩個表如何建立關聯?

一個filed id只能屬於一張表,比如只能屬於host表

多對一關係的建立

b12106b4-4927-4f8b-9911-9c467f9fe082.png


13186967.png



再來看一下filed表結構,它不但幫我們建了字段還添加了主鍵


查看外鍵約束

明確說明了外鍵是引用了schema 這個表,

13251036.png


而且用的是自己的id 來引用的schema id

image.png


理解這樣的關係

假設:

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,用於記錄主機,一對多關係,一個主機的描述信息只屬於一個

設計字段




idBIGINT唯一標識虛擬表的記錄
keyVARCHAR用於存放UUID


image.png


添加value

idBIGINT自增
valueVARCHAR存什麼?

16477122.png

現在的我們想的是將這些信息存放於value表中

image.png


這樣就引出了兩個字段:IP和HOSTNAME

那麼回到entity中,既然是存值,那麼是必須有id 唯一標識,新加字段

entity 與 value關聯關係:

一對多關係,entity只有一個id,value中有多個字段,那麼爲了描述這一個id對應的一行記錄,這兩個字段都要放在value中

如何描述字段,如何知道是哪個字段?那麼filed還需要與value建立關係

建立表關係

image.png


記錄哪個虛擬表完全靠schema_id 來表示,比如schema_id = 1 那麼就相當於找host表

假如描述這邊的字段該如何去關聯?

描述字段關係

這裏value 對應的就是就是entity_id 的而entity 又是唯一對應了schema_id

雖然是多端,這樣看只能對應一個,但是關聯起來之後從schema表中就能夠充分體現出是對應多個表id

只不過是中間做了一層過度,這樣每個表只對應一個id即可。 但是不能描述對應的哪些字段,所需還需要與filed進行關聯

image.png

這樣後期加字段或者表的時候直接加一行記錄即可

如果在使用的一張表在使用中,添加字段的話,物理結構也跟隨發生改變,那如果是虛擬表在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;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章