1. 程式人生 > >從零打造一個CMDB(一)資料庫設計

從零打造一個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,用於記錄主機,一對多關係,一個主機的描述資訊只屬於一個

設計欄位




id BIGINT 唯一標識虛擬表的記錄
key VARCHAR 用於存放UUID


image.png


新增value

id BIGINT 自增
value VARCHAR 存什麼?

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 @[email protected]@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @[email protected]@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @[email protected]@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 [email protected]_SQL_MODE;
SET [email protected]_FOREIGN_KEY_CHECKS;
SET [email protected]_UNIQUE_CHECKS;