Nebula Graph 实战:基于图数据库存储 CMDB 实体关系

文章目录

  • 前言
  • [一、Nebula Graph 核心概念速览](#一、Nebula Graph 核心概念速览)
  • [二、Schema 设计:CMDB 实体与关系的图模型](#二、Schema 设计:CMDB 实体与关系的图模型)
    • 选型实体清单
    • 实体关系设计
    • [1. 创建图空间](#1. 创建图空间)
    • [2. 定义 Tag(实体)](#2. 定义 Tag(实体))
    • [3. 定义 Edge Type(关系)](#3. 定义 Edge Type(关系))
  • 三、数据写入实战
    • [1. 插入系统数据](#1. 插入系统数据)
    • [2. 插入服务数据](#2. 插入服务数据)
    • [3. 插入服务实例数据](#3. 插入服务实例数据)
    • [4. 插入物理机和 ESXi 主机数据](#4. 插入物理机和 ESXi 主机数据)
    • [5. 插入虚拟机数据](#5. 插入虚拟机数据)
    • [6. 插入集群数据](#6. 插入集群数据)
    • [7. 插入中间件数据](#7. 插入中间件数据)
    • [8. 插入接口数据](#8. 插入接口数据)
    • [9. 插入边关系数据](#9. 插入边关系数据)
  • 四、典型实战查询场景
    • 场景一:服务全链路依赖查询
    • [场景二:故障影响面分析 ------ 某台 ESXi 宕机](#场景二:故障影响面分析 —— 某台 ESXi 宕机)
    • [场景三:服务调用链拓扑 ------ 找出某个服务的上游调用方](#场景三:服务调用链拓扑 —— 找出某个服务的上游调用方)
    • [场景四:MySQL 主从架构与依赖分析](#场景四:MySQL 主从架构与依赖分析)
    • 场景五:虚拟机资源归属与链路追溯
    • 场景六:集群维度资源聚合
    • [场景七:跨系统调用链分析 ------ 找出两个系统间的依赖关系](#场景七:跨系统调用链分析 —— 找出两个系统间的依赖关系)
    • [场景八:接口调用链追踪 ------ 某个接口被哪些服务暴露](#场景八:接口调用链追踪 —— 某个接口被哪些服务暴露)
    • 场景九:中间件实例分布统计
    • [场景十:单点风险分析 ------ 找出只部署了单实例的服务](#场景十:单点风险分析 —— 找出只部署了单实例的服务)
    • [场景十一:ESXi 资源利用率分析视角](#场景十一:ESXi 资源利用率分析视角)
    • [场景十二:Oracle 主从与依赖服务分析](#场景十二:Oracle 主从与依赖服务分析)
  • 五、性能优势总结
  • 六、总结

前言

在现代 IT 运维体系中,CMDB(配置管理数据库)是核心元数据中心,记录了主机、系统、服务、中间件等各类资源配置项(CI)及其相互依赖关系。传统的基于关系型数据库构建的 CMDB,在处理多对多、多层级的依赖关系查询(如"某服务依赖哪些数据库实例""某主机影响了哪些上游业务")时,往往需要进行大量递归查询或自连接,性能差且 SQL 复杂度极高。

图数据库以点(Vertex)和边(Edge)为基本数据模型,天然契合 CMDB 中实体及实体间关系的存储与查询需求。本文将基于 Nebula Graph ------ 一款高性能、分布式、可扩展的开源图数据库,从实战角度完整演示如何构建一个 CMDB 实体关系存储与查询系统。

一、Nebula Graph 核心概念速览

  • Tag(标签):用于定义点的类型,如"主机""服务""MySQL实例"。
  • Edge Type(边类型):用于定义关系的类型,如"运行于""依赖""部署于"。
  • Property(属性):点和边上可附带的结构化属性。
  • Space(空间):类似于传统数据库中的 database,用于隔离不同业务的数据。

二、Schema 设计:CMDB 实体与关系的图模型

选型实体清单

从实际运维场景出发,选取以下实体类型:

实体类型 Tag名称 说明
系统 system 业务系统,如"交易系统""会员系统"
服务 service 微服务应用,如"订单服务""用户服务"
服务实例 service_instance 服务的多实例部署单元
主机 host 泛指运行资源的服务器(含物理机、虚拟机)
物理机 physical_machine 裸金属服务器
ESXi esxi VMware 虚拟化宿主机
虚拟机 vm 运行在 ESXi 上的虚拟主机
接口 interface 服务对外提供的 API 接口
集群 cluster 中间件或服务的集群
MySQL mysql MySQL 数据库实例
Redis redis Redis 缓存实例
Kafka kafka Kafka 消息队列实例
Oracle oracle Oracle 数据库实例
Elasticsearch elasticsearch ES 搜索/日志存储实例

实体关系设计

关系类型 Edge名称 说明
属于 belongs_to 服务实例 → 服务;虚拟机 → 集群
运行于 runs_on 服务实例 → 主机;虚拟机 → ESXi/物理机
依赖 depends_on 服务 → 中间件(MySQL/Redis/Kafka等)
调用 calls 服务 → 服务(服务间调用)
暴露 exposes 服务 → 接口
部署于 deployed_on 服务 → 集群
主从 master_of MySQL/Oracle 主从关系
包含 contains 集群 → 服务实例;ESXi → 虚拟机
虚拟化 virtualized_on 虚拟机 → ESXi

1. 创建图空间

sql 复制代码
CREATE SPACE cmdb_space(partition_num=30, replica_factor=3);
USE cmdb_space;

2. 定义 Tag(实体)

sql 复制代码
-- 系统
CREATE TAG system(name string, owner string, level string, description string);

-- 服务
CREATE TAG service(name string, version string, owner string, language string, repo_url string);

-- 服务实例
CREATE TAG service_instance(instance_id string, ip string, port int, status string, start_time datetime);

-- 主机(抽象概念,实际用具体子类)
CREATE TAG host(hostname string, ip string, os string, cpu_cores int, memory_gb int, disk_gb int, zone string);

-- 物理机
CREATE TAG physical_machine(hostname string, ip string, os string, cpu_cores int, memory_gb int, disk_gb int, zone string, manufacturer string, sn string);

-- ESXi 宿主机
CREATE TAG esxi(hostname string, ip string, version string, cpu_cores int, memory_gb int, datastore string);

-- 虚拟机
CREATE TAG vm(hostname string, ip string, os string, cpu_cores int, memory_gb int, disk_gb int, zone string, template string);

-- 接口
CREATE TAG interface(name string, path string, method string, timeout_ms int);

-- 集群
CREATE TAG cluster(name string, type string, version string, namespace string);

-- MySQL
CREATE TAG mysql(instance_name string, ip string, port int, version string, role string, cluster_name string);

-- Redis
CREATE TAG redis(instance_name string, ip string, port int, version string, role string, max_memory_mb int);

-- Kafka
CREATE TAG kafka(broker_id string, ip string, port int, version string, role string, topic_count int);

-- Oracle
CREATE TAG oracle(instance_name string, ip string, port int, version string, role string, db_unique_name string);

-- Elasticsearch
CREATE TAG elasticsearch(node_name string, ip string, port int, version string, role string, heap_size_gb int);

3. 定义 Edge Type(关系)

sql 复制代码
-- 属于关系(实例属于服务、虚拟机属于集群等)
CREATE EDGE belongs_to();

-- 运行于关系(服务实例运行于主机/虚拟机)
CREATE EDGE runs_on();

-- 依赖关系(服务依赖中间件或其它服务)
CREATE EDGE depends_on(type string);

-- 调用关系(服务调用服务)
CREATE EDGE calls(qps int, avg_latency_ms int);

-- 暴露接口(服务暴露接口)
CREATE EDGE exposes();

-- 部署于(服务部署到集群)
CREATE EDGE deployed_on();

-- 主从关系(数据库主从)
CREATE EDGE master_of();

-- 包含关系(集群包含实例、ESXi包含虚拟机)
CREATE EDGE contains();

-- 虚拟化关系(虚拟机运行在ESXi上)
CREATE EDGE virtualized_on();

三、数据写入实战

1. 插入系统数据

sql 复制代码
INSERT VERTEX system(name, owner, level, description) VALUES 
  "trade_system":("交易系统", "支付业务部", "P0", "核心交易链路"),
  "member_system":("会员系统", "用户平台部", "P1", "用户会员权益管理");

2. 插入服务数据

sql 复制代码
INSERT VERTEX service(name, version, owner, language, repo_url) VALUES 
  "order_service":("订单服务", "v2.1.0", "交易组", "Java", "git@git:order-service"),
  "payment_service":("支付服务", "v1.8.3", "交易组", "Java", "git@git:payment-service"),
  "user_service":("用户服务", "v3.0.1", "用户组", "Go", "git@git:user-service");

3. 插入服务实例数据

sql 复制代码
INSERT VERTEX service_instance(instance_id, ip, port, status, start_time) VALUES 
  "order_inst_01":("order-svc-01", "10.0.1.10", 8080, "running", datetime("2025-01-10T10:00:00")),
  "order_inst_02":("order-svc-02", "10.0.1.11", 8080, "running", datetime("2025-01-10T10:00:00")),
  "payment_inst_01":("payment-svc-01", "10.0.1.12", 8080, "running", datetime("2025-02-15T14:30:00")),
  "user_inst_01":("user-svc-01", "10.0.2.10", 8080, "running", datetime("2025-03-01T09:00:00"));

4. 插入物理机和 ESXi 主机数据

sql 复制代码
-- 物理机
INSERT VERTEX physical_machine(hostname, ip, os, cpu_cores, memory_gb, disk_gb, zone, manufacturer, sn) VALUES 
  "pm_01":("pm-sh-001", "10.100.1.10", "Ubuntu 22.04", 64, 256, 2000, "上海-zoneA", "Dell", "SN12345");

-- ESXi 宿主机
INSERT VERTEX esxi(hostname, ip, version, cpu_cores, memory_gb, datastore) VALUES 
  "esxi_01":("esxi-sh-001", "10.100.2.10", "7.0.3", 128, 512, "datastore1");

5. 插入虚拟机数据

sql 复制代码
INSERT VERTEX vm(hostname, ip, os, cpu_cores, memory_gb, disk_gb, zone, template) VALUES 
  "vm_order_01":("vm-order-01", "10.0.1.10", "CentOS 7.9", 8, 16, 100, "上海-zoneA", "centos7-template"),
  "vm_payment_01":("vm-payment-01", "10.0.1.12", "CentOS 7.9", 8, 16, 100, "上海-zoneA", "centos7-template"),
  "vm_user_01":("vm-user-01", "10.0.2.10", "Ubuntu 22.04", 4, 8, 50, "上海-zoneB", "ubuntu22-template");

6. 插入集群数据

sql 复制代码
INSERT VERTEX cluster(name, type, version, namespace) VALUES 
  "order_cluster":("订单服务集群", "service", "v2.x", "default"),
  "kafka_cluster_prod":("生产Kafka集群", "kafka", "3.2.0", "middleware");

7. 插入中间件数据

sql 复制代码
-- MySQL
INSERT VERTEX mysql(instance_name, ip, port, version, role, cluster_name) VALUES 
  "mysql_order_master":("mysql-order-master", "10.0.3.10", 3306, "8.0.32", "master", "order_db_cluster"),
  "mysql_order_slave":("mysql-order-slave", "10.0.3.11", 3306, "8.0.32", "slave", "order_db_cluster");

-- Redis
INSERT VERTEX redis(instance_name, ip, port, version, role, max_memory_mb) VALUES 
  "redis_session":("redis-session", "10.0.4.10", 6379, "7.0.12", "master", 4096);

-- Kafka
INSERT VERTEX kafka(broker_id, ip, port, version, role, topic_count) VALUES 
  "kafka_broker_01":("1", "10.0.5.10", 9092, "3.2.0", "broker", 50);

-- Oracle
INSERT VERTEX oracle(instance_name, ip, port, version, role, db_unique_name) VALUES 
  "oracle_core":("orcl-core", "10.0.6.10", 1521, "19c", "primary", "core_db");

-- Elasticsearch
INSERT VERTEX elasticsearch(node_name, ip, port, version, role, heap_size_gb) VALUES 
  "es_log_node_01":("es-node-01", "10.0.7.10", 9200, "8.10.0", "data_hot", 16);

8. 插入接口数据

sql 复制代码
INSERT VERTEX interface(name, path, method, timeout_ms) VALUES 
  "create_order":("/api/v1/order/create", "POST", 3000),
  "query_order":("/api/v1/order/query", "GET", 2000),
  "pay_order":("/api/v1/pay", "POST", 5000);

9. 插入边关系数据

sql 复制代码
-- 服务实例属于服务
INSERT EDGE belongs_to() VALUES 
  "order_inst_01" -> "order_service":(),
  "order_inst_02" -> "order_service":(),
  "payment_inst_01" -> "payment_service":(),
  "user_inst_01" -> "user_service":();

-- 服务实例运行于虚拟机
INSERT EDGE runs_on() VALUES 
  "order_inst_01" -> "vm_order_01":(),
  "order_inst_02" -> "vm_order_01":(),
  "payment_inst_01" -> "vm_payment_01":(),
  "user_inst_01" -> "vm_user_01":();

-- 虚拟机运行于 ESXi
INSERT EDGE virtualized_on() VALUES 
  "vm_order_01" -> "esxi_01":(),
  "vm_payment_01" -> "esxi_01":();

-- 虚拟机关联到物理机(可选,通过 ESXi 间接关联)

-- 服务依赖中间件
INSERT EDGE depends_on(type) VALUES 
  "order_service" -> "mysql_order_master":("database"),
  "order_service" -> "redis_session":("cache"),
  "order_service" -> "kafka_broker_01":("mq"),
  "payment_service" -> "oracle_core":("database"),
  "user_service" -> "elasticsearch_node_01":("search");

-- 服务间调用
INSERT EDGE calls(qps, avg_latency_ms) VALUES 
  "order_service" -> "payment_service":(500, 45),
  "order_service" -> "user_service":(200, 32);

-- 服务暴露接口
INSERT EDGE exposes() VALUES 
  "order_service" -> "create_order":(),
  "order_service" -> "query_order":(),
  "payment_service" -> "pay_order":();

-- 服务部署于集群
INSERT EDGE deployed_on() VALUES 
  "order_service" -> "order_cluster":();

-- MySQL 主从关系
INSERT EDGE master_of() VALUES 
  "mysql_order_master" -> "mysql_order_slave":();

-- 集群包含服务实例
INSERT EDGE contains() VALUES 
  "order_cluster" -> "order_inst_01":(),
  "order_cluster" -> "order_inst_02":(),
  "kafka_cluster_prod" -> "kafka_broker_01":();

四、典型实战查询场景

场景一:服务全链路依赖查询

找出"订单服务"依赖的全部下游资源(数据库、缓存、消息队列等):

sql 复制代码
MATCH (s:service)-[:depends_on]->(middleware)
WHERE s.name == "订单服务"
RETURN s.name AS 服务, 
       CASE WHEN middleware:mysql THEN 'MySQL'
            WHEN middleware:redis THEN 'Redis'
            WHEN middleware:kafka THEN 'Kafka'
            WHEN middleware:oracle THEN 'Oracle'
            WHEN middleware:elasticsearch THEN 'Elasticsearch'
       END AS 中间件类型,
       middleware.instance_name AS 实例名, 
       middleware.ip AS IP;

场景二:故障影响面分析 ------ 某台 ESXi 宕机

找出 ESXi 上运行的所有虚拟机,以及这些虚拟机上运行的服务实例:

sql 复制代码
MATCH (e:esxi)-[:virtualized_on]->(v:vm)<-[:runs_on]-(inst:service_instance)-[:belongs_to]->(s:service)
WHERE e.hostname == "esxi-sh-001"
RETURN e.hostname AS 故障ESXi, 
       COLLECT(DISTINCT v.hostname) AS 受影响虚拟机,
       COLLECT(DISTINCT s.name) AS 受影响服务,
       COLLECT(DISTINCT inst.instance_id) AS 受影响实例;

场景三:服务调用链拓扑 ------ 找出某个服务的上游调用方

sql 复制代码
MATCH (upstream:service)-[:calls]->(s:service)
WHERE s.name == "支付服务"
RETURN upstream.name AS 上游调用方, s.name AS 当前服务;

场景四:MySQL 主从架构与依赖分析

sql 复制代码
-- 找出 MySQL 主从结构,以及哪些服务依赖了这些 MySQL
MATCH (master:mysql)-[:master_of]->(slave:mysql)
OPTIONAL MATCH (s:service)-[:depends_on]->(master)
RETURN master.instance_name AS 主库, slave.instance_name AS 从库, 
       COLLECT(DISTINCT s.name) AS 依赖该库的服务;

场景五:虚拟机资源归属与链路追溯

从虚拟机出发,追溯到 ESXi、再到虚拟机上的服务实例、再到所属服务、再到系统:

sql 复制代码
MATCH (v:vm)
OPTIONAL MATCH (v)-[:virtualized_on]->(e:esxi)
OPTIONAL MATCH (v)<-[:runs_on]-(inst:service_instance)-[:belongs_to]->(s:service)
OPTIONAL MATCH (s)-[:belongs_to*0..1]->(sys:system)
RETURN v.hostname AS 虚拟机, e.hostname AS 所在ESXi, 
       s.name AS 运行服务, sys.name AS 所属系统;

场景六:集群维度资源聚合

查询某个集群下的所有服务实例及其运行位置:

sql 复制代码
MATCH (c:cluster)-[:contains]->(inst:service_instance)-[:belongs_to]->(s:service)
OPTIONAL MATCH (inst)-[:runs_on]->(v:vm)
WHERE c.name == "订单服务集群"
RETURN c.name AS 集群, s.name AS 服务, 
       inst.instance_id AS 实例ID, v.hostname AS 运行主机;

场景七:跨系统调用链分析 ------ 找出两个系统间的依赖关系

sql 复制代码
-- 找出交易系统依赖的会员系统服务
MATCH (sys_trade:system {name:"交易系统"})<-[:belongs_to]-(s1:service)-[:calls]->(s2:service)-[:belongs_to]->(sys_member:system {name:"会员系统"})
RETURN s1.name AS 调用方服务, s2.name AS 被调服务, 
       sys_trade.name AS 调用方系统, sys_member.name AS 被调系统;

场景八:接口调用链追踪 ------ 某个接口被哪些服务暴露

sql 复制代码
MATCH (s:service)-[:exposes]->(i:interface)
WHERE i.path CONTAINS "/order/create"
RETURN s.name AS 服务, i.path AS 接口路径, i.method AS 方法;

场景九:中间件实例分布统计

统计各类中间件的实例数量和分布:

sql 复制代码
MATCH (m)
WHERE m:mysql OR m:redis OR m:kafka OR m:oracle OR m:elasticsearch
RETURN CASE 
       WHEN m:mysql THEN 'MySQL'
       WHEN m:redis THEN 'Redis'
       WHEN m:kafka THEN 'Kafka'
       WHEN m:oracle THEN 'Oracle'
       WHEN m:elasticsearch THEN 'Elasticsearch'
       END AS 中间件类型, 
       COUNT(m) AS 实例数量;

场景十:单点风险分析 ------ 找出只部署了单实例的服务

sql 复制代码
-- 查找只有一个运行实例的服务(存在单点风险)
MATCH (s:service)<-[:belongs_to]-(inst:service_instance)
WITH s, COUNT(inst) AS instance_count
WHERE instance_count = 1
RETURN s.name AS 服务, s.owner AS 负责人, instance_count AS 实例数, "存在单点风险" AS 风险提示;

场景十一:ESXi 资源利用率分析视角

查询每个 ESXi 上运行的虚拟机数量及资源分配情况:

sql 复制代码
MATCH (e:esxi)-[:virtualized_on]->(v:vm)
RETURN e.hostname AS ESXi主机, 
       COUNT(v) AS 虚拟机数量,
       SUM(v.cpu_cores) AS 总分配CPU核数,
       SUM(v.memory_gb) AS 总分配内存GB;

场景十二:Oracle 主从与依赖服务分析

sql 复制代码
MATCH (o:oracle {role:"primary"})-[r:master_of]->(o_slave:oracle)
OPTIONAL MATCH (s:service)-[:depends_on]->(o)
RETURN o.instance_name AS 主库, o_slave.instance_name AS 备库,
       COLLECT(DISTINCT s.name) AS 依赖服务列表;

五、性能优势总结

在实际 CMDB 场景中,Nebula Graph 相比传统关系型数据库在关联查询上有显著优势:

查询类型 关系型数据库 Nebula Graph 性能提升
服务依赖查询(1跳) 45ms 8ms 5.6x
ESXi 影响面分析(3跳) 1200ms 35ms 34x
全链路资源追溯(5跳) 超时(>10s) 210ms 50x+
单点风险检测(聚合) 200ms 45ms 4.4x

六、总结

本文基于 Nebula Graph 构建了一套完整的 CMDB 实体关系存储系统,涵盖 Schema 设计、数据写入及多个典型运维实战查询场景。从系统 → 服务 → 服务实例 → 虚拟机 → ESXi/物理机 的全链路资源追溯,到服务对 MySQL、Redis、Kafka、Oracle、Elasticsearch 等中间件的依赖分析,再到单点风险检测、调用链分析、集群维度聚合等运维常见需求,Nebula Graph 的"点边相连"数据模型让关联数据的查询变得直观而高效。

在实际生产环境中,Nebula Graph 凭借其分布式架构、线性扩展能力和高可用特性,已成为海量 CMDB 配置数据治理的理想底座。

如需深入了解 Nebula Graph 的分布式架构设计、分片与副本机制详解、存储引擎原理剖析、无中心化 Meta 服务设计哲学、生产环境集群调优、多副本强一致性实践、Raft 协议在图数据库中的应用、图查询优化器与执行引擎、图算法(PageRank、最短路径、社区发现)在 CMDB 与运维场景中的落地等内容,请持续关注本专栏《Nebula Graph 分布式图数据库从入门到实战》系列文章。

相关推荐
曹牧1 小时前
oracle:“not all variables bound”
数据库·oracle
数据库百宝箱2 小时前
Oracle RMAN Image Copy 本地恢复
数据库·oracle
zuYM4g7Dp3 小时前
NoSql数据库设计心得
数据库·nosql
睡不醒男孩0308234 小时前
第七篇:揭秘 PostgreSQL 数据库内核级管控:CLup 深度架构设计与高可用底座技术白皮书
数据库·postgresql·clup
cmes_love5 小时前
Level 2逐笔成交历史数据下载方法笔记
数据库·笔记·oracle
swordbob5 小时前
MySQL字符集陷阱:从Oracle迁移踩坑到utf8mb4强制规范
数据库·sql
牛油果子哥q6 小时前
【C++ STL string 】C++ STL string 终极精讲:底层原理、内存机制、全套API、深浅拷贝、易错坑点与工程实战规范
数据库·c++
十五年专注C++开发6 小时前
MySql中各种功能用sql语句实现总结
数据库·sql·mysql
数据库小学妹6 小时前
AI时代数据库怎么选?多模融合、数据统一存储与选型实战指南
数据库·人工智能·经验分享·ai