组件开发基本概念
更新时间: 2026/08/20
在Gitcode上查看源码

组件开发基本概念

文档说明

本文介绍 openUBMC 组件开发的基本概念与核心机制。本文面向初次接触 openUBMC 组件开发的工程师。

本文重点回答以下问题:

  1. openUBMC 采用微组件架构的原因。
  2. “组件”“Skynet 服务”“进程”“MDS 类”“D-Bus 对象”等概念的含义。
  3. MDS、mdb_interface、资源协作接口、CSR/PSR、Skynet、错误引擎、BMC Studio CLI、Conan/CMake、DT、hicamanifest 分别解决的问题。
  4. 模型、接口、业务代码和硬件配置之间的关系。
  5. 一个组件从模型定义到运行、测试、构建和产品集成的大致阶段。
  6. 部件开发者和整机开发者在同一套组件架构中的不同关注点。

说明

本文中的“组件开发基本概念”既包括业务组件本身,也包括组件开发所依赖的模型、运行框架、公共组件和工程机制。它们并不属于同一种软件实体,需要结合各自职责分别理解。

1. openUBMC 微组件架构概述

1.1 组件化的价值

openUBMC 是算力设备管理软件。与将大量业务集中在单个程序中的方式不同,openUBMC 将系统功能拆分为多个相对独立、可以自行演进的组件,再由多个组件组合形成完整系统。

组件化带来的核心价值包括:

  • 独立开发:开发者可以围绕单一业务边界修改或新增组件,而不需要理解整个系统的全部实现。
  • 独立测试:组件在开发阶段即可进行单元测试和集成测试,尽早发现问题。
  • 独立构建和发布:组件通过 Conan 包进行管理,可以单独构建、打包和发布。
  • 按需组合和裁剪:产品可以根据机型和业务诉求选择组件组合,更适合差异化和定制化场景。
  • 接口解耦:组件之间通过统一的资源协作接口交互,而不是直接依赖对方内部代码。

因此,openUBMC 的组件化不仅是“把代码拆成多个仓”,还包括对模型、接口、运行、测试、构建和发布边界的拆分。

1.2 微组件定义

从开发视角看,一个 openUBMC 组件可以理解为一个相对独立的业务功能单元。它通常拥有自己的:

  • MDS 模型;
  • 业务代码;
  • 对外资源协作接口实现;
  • 对其他组件资源协作接口的依赖声明;
  • 测试代码;
  • 构建和打包配置;
  • 组件版本与 Conan 包。

“微”并不表示组件必须非常小,而是强调功能边界清晰、职责相对集中、可以独立演进。

多数业务组件只需要一个 Skynet 服务即可完成主要业务,但一个组件也可以根据业务需要创建多个 Skynet 服务。

1.3 组件、服务和进程的区别

组件、Skynet 服务和操作系统进程分别属于不同层次。

概念含义典型作用
组件(Component)功能开发、模型、测试、构建和发布的基本边界承载一类相对独立的业务能力
Skynet 服务(Service)Skynet 中的独立运行单元,拥有独立 Lua 虚拟机执行组件运行态业务逻辑
进程(Process)操作系统进程,可承载一个或多个 Skynet 服务提供运行资源和故障隔离边界
工作线程(Worker Thread)Skynet 进程内部用于调度服务的线程支持多个服务并发运行
协程(Coroutine)服务内部的轻量级协作式执行单元处理异步 RPC、数据库、网络和周期任务等

可以将其关系简化理解为:

text
产品
└── 多个进程
    └── 一个或多个 Skynet 服务
        └── 对应组件业务
            └── 一个或多个协程 / Task

一个组件通常对应一个主要 Skynet 服务,但并不是强制的一一对应关系;多个组件也可以根据运行编排进入同一个进程。

1.4 组件间协作方式

组件之间原则上不直接调用彼此的内部函数,而是通过资源协作接口进行协作。

资源协作接口采用 D-Bus 协议实现,通过“服务、对象路径、接口、属性/方法”等信息描述和访问资源。

一次典型的跨组件调用可以概括为:

text
组件 A

  │ 声明并使用资源协作接口

资源协作接口 / D-Bus

  │ 属性访问 / RPC 方法调用

组件 B

  └── 执行组件 B 内部业务逻辑

这种方式把“能力的定义”和“能力的内部实现”隔离开。调用方只依赖统一接口契约,不需要了解被调用组件内部的代码结构。

1.5 组件开发的分层理解

openUBMC 组件开发涉及多个机制,如果只记忆 MDS、CSR、Skynet、Conan 等名称,很容易把它们看成彼此独立的工具。

从整体上可以将相关机制理解为四个相互衔接的层次:

text
┌─────────────────────────────────────────────┐
│ 产品与集成层                                │
│ manifest / hica / 产品组件组合 / 运行编排   │
├─────────────────────────────────────────────┤
│ 工程交付层                                  │
│ DT / bingo / CMake / Conan / 组件包         │
├─────────────────────────────────────────────┤
│ 运行与协作层                                │
│ 业务组件 / Skynet / D-Bus / 资源协作接口    │
│ 错误引擎                                    │
├─────────────────────────────────────────────┤
│ 模型与硬件描述层                            │
│ MDS / mdb_interface / CSR / PSR             │
└─────────────────────────────────────────────┘

四层共同构成组件从定义到进入产品的完整体系:

  1. 模型与硬件描述层定义组件管理什么、接口契约是什么以及实际硬件有什么。
  2. 运行与协作层使组件业务运行起来,并通过统一接口与其他组件交互。
  3. 工程交付层保证组件能够进行代码生成、测试、构建和独立发布。
  4. 产品与集成层负责将多个组件组合为具体产品,并完成运行编排和制品集成。

2. 微组件架构中的核心组成及作用

2.1 业务组件——功能的实际提供者

业务组件是 openUBMC 功能实现的主体。

从开发视角看,一个业务组件通常需要回答四个问题:

  1. 组件管理什么数据和对象? —— 由 MDS 描述。
  2. 组件向系统提供什么能力? —— 由资源协作接口定义,组件负责实现。
  3. 组件依赖其他组件的什么能力? —— 通过运行时资源依赖进行声明。
  4. 组件业务逻辑如何运行? —— 由 Skynet 服务以及 Lua/C/C++ 等业务代码承载。

因此,业务组件并不是孤立的一组源码,而是模型、接口、业务实现、运行和工程交付共同形成的功能单元。

2.2 MDS——组件的软件模型

MDS(Module Description Source)是微组件框架的核心模型源,用于描述组件本身以及组件管理的数据模型。

MDS 主要描述:

  • 组件名称、版本、类型等基本信息;
  • 组件构建和测试依赖;
  • 运行时需要访问的资源协作接口;
  • 组件管理的类、属性和对象路径;
  • 组件实现的资源协作接口;
  • 私有属性、持久化、权限等模型信息;
  • IPMI 命令模型;
  • 结构体、枚举等复杂数据类型。

常见模型文件包括:

文件主要作用
service.json描述组件服务模型、版本、构建/测试依赖以及运行时资源依赖
model.json描述类、属性、对象路径、接口和持久化等数据模型
ipmi.json描述组件 IPMI 命令模型
types.json描述结构体、枚举等复杂数据类型
schema.json根据模型生成,用于模型字段格式校验

MDS 的关键价值在于模型驱动开发:开发者先通过模型定义组件结构和资源边界,再由工程框架根据模型生成对象管理、服务初始化、RPC 桩函数和客户端访问等基础代码。

2.3 mdb_interface——公共接口与错误定义

mdb_interface 是组件开发中的公共组件仓,主要承担两类职责。

2.3.1 统一定义资源协作接口

资源协作接口的公共契约在 mdb_interface 中统一维护,包括:

  • 对象路径;
  • 接口名称;
  • 属性;
  • RPC 方法;
  • 方法请求和响应数据模型等。

可以将其与业务组件之间的关系理解为:

text
mdb_interface

      │ 定义公共接口契约

业务组件

      │ 实现具体业务行为

资源协作接口实例

因此:

说明

mdb_interface 定义“接口是什么”,业务组件决定“接口具体做什么”。

2.3.2 统一管理公共错误定义

公共错误定义同样由 mdb_interface 管理。

业务组件可以使用统一生成的错误对象处理异常,中间组件在跨组件 RPC 调用过程中也可以识别、转换和继续传递错误,从而保持跨组件错误语义的一致性。

2.4 资源协作接口——组件之间的标准边界

资源协作接口采用 D-Bus 协议实现,是组件之间交换数据和调用能力的统一通道。

一个运行态资源通常通过以下信息进行定位:

text
服务(service)
+ 对象路径(object path)
+ 接口(interface)
+ 属性 / 方法(property / method)

组件可以通过资源协作接口:

  • 对外提供属性;
  • 对外提供 RPC 方法;
  • 查询其他组件资源;
  • 调用其他组件 RPC;
  • 订阅资源属性变化。

因此,资源协作接口解决的是:

说明

不同组件之间如何在不依赖彼此内部实现的情况下进行稳定协作。

2.5 Skynet——组件的运行与调度框架

Skynet 是 openUBMC Lua 组件的重要运行框架。

它主要提供:

  • 服务运行;
  • 服务间消息通信;
  • 工作线程调度;
  • 协程调度;
  • 异步任务处理;
  • 周期任务等运行能力。

在 RPC、数据库和网络 I/O 等存在等待的场景中,当前协程可以挂起,使服务能够继续处理其他可执行任务。

需要区分:

  • Skynet 服务不是操作系统进程;
  • skynet.fork 创建的是协程,不是线程;
  • 协程调度不等于实时调度;
  • 长时间阻塞操作不适合直接放在普通协程中执行;
  • 对于需要真正线程隔离的阻塞型调用,可以结合相应 Worker 机制处理。

2.6 CSR / PSR——硬件自描述

openUBMC 使用硬件自描述机制降低业务软件与具体硬件之间的耦合。

CSR

CSR(Component Self-description Record)从软件视角描述部件内部实际硬件,包括:

  • 器件;
  • 器件之间的连接关系;
  • 管理拓扑;
  • 硬件能力;
  • 对象实例;
  • 对象属性及其数据关系。

PSR

PSR(Product Self-description Record)从整机角度描述产品硬件组成和能力。

MDS 和 CSR 关注的对象不同:

text
MDS
从软件组件角度定义:
“软件能够管理什么”

          ↓ 对应

CSR
从具体部件角度描述:
“当前硬件实际有什么”

CSR 中的对象类型需要与相应 MDS 类建立对应关系,对象属性也需要与组件模型允许管理的属性保持一致。

说明

MDS 和 CSR 不是两套孤立机制,而是共同完成软件模型与实际硬件实例之间的映射

2.7 错误引擎——统一跨组件错误语义

错误引擎用于统一组件错误的定义、生成和处理方式。

在跨组件调用链中,错误可能经过多个组件逐级返回。如果各组件自行设计错误格式,调用方难以形成统一处理逻辑。

统一错误机制使组件能够:

  • 使用公共错误类型;
  • 抛出标准化异常;
  • 识别其他组件返回的错误;
  • 对错误进行必要的转换;
  • 保持跨组件调用链中的错误语义一致。

2.8 hica——组件运行编排

hica 与组件运行阶段的组织和编排相关。

在产品中,多个组件可能存在:

  • 启动顺序要求;
  • 子系统归属;
  • 进程组织要求;
  • 并行拉起需求。

hica 相关配置用于描述这些运行关系。

因此,hica 主要回答:

说明

组件进入产品后,以怎样的运行关系被组织和拉起。

它不是接口定义机制,也不是组件包管理机制。

2.9 BMC Studio 与 BMC Studio CLI (bingo)

BMC Studio 提供组件开发相关的可视化配置和工程能力,BMC Studio CLI (bingo) 则提供统一的命令行开发入口。

它将模型代码生成、测试、构建等工程动作统一起来,例如:

shell
bingo gen
bingo test -ut
bingo test -it
bingo build

bingo 本身并不替代 MDS、测试框架、CMake 或 Conan,而是对这些工程能力进行统一组织,为不同组件提供一致的开发入口。

2.10 Conan 与 CMake——组件构建和交付基础

openUBMC 使用 Conan 与 CMake 支撑组件的独立构建和交付。

二者职责不同:

  • CMake:描述源码如何编译、链接和安装;
  • Conan:负责组件包及其依赖的管理、构建和交付。

常见工程文件包括:

  • CMakeLists.txt:组件编译和安装规则;
  • conanfile.py:组件 Conan 构建脚本;
  • conanbase.py:通用 Conan 构建逻辑。

组件源码经过构建后形成 Conan 组件包,组件包进一步作为产品集成的基本输入。

2.11 DT——开发者测试

开发者测试用于保证组件在进入完整产品之前具备独立验证能力,主要包括:

单元测试

验证组件内部功能单元的正确性,重点关注:

  • 正常路径;
  • 异常路径;
  • 边界条件;
  • 内部业务逻辑。

外部组件或环境依赖通常通过 Mock 方式进行隔离。

集成测试

验证组件对外资源协作接口以及组件之间的协作关系。

这类测试通常需要相应运行环境,并通过真实资源访问、属性操作或 RPC 调用验证组件边界行为。

二者关注点可以概括为:

text
单元测试

组件内部逻辑

集成测试

组件边界及跨组件协作

2.12 manifest——产品组件组合

组件构建得到 Conan 包后,还没有形成完整产品。

产品构建需要通过 manifest 选择和组合相应组件包:

text
组件源码

组件构建

Conan 组件包

manifest 选择和组合

目标产品 / 机型制品

因此,manifest 主要解决:

说明

一个具体产品由哪些组件版本组合而成。

3. 组件开发的基本机制

第 2 章分别介绍了组件开发中的核心组成。本章不再重复各概念的定义,而是重点说明它们在组件开发过程中如何相互连接。

3.1 MDS、代码生成与业务实现

MDS、代码生成和业务实现共同构成模型驱动开发链路:

text
MDS 模型

代码生成

通用基础代码

业务实现

MDS 负责描述组件结构、对象模型和资源边界;工程工具依据模型生成对象管理、服务初始化、RPC 桩和客户端访问等通用代码;开发者在生成框架的基础上补充具体业务逻辑。

因此,模型驱动开发的核心是将模型定义、通用框架能力和具体业务实现分离,减少重复开发,并使组件结构和接口保持一致。

3.2 公共接口、组件模型与 RPC

资源协作接口从公共契约到实际可调用能力,需要经过接口定义、组件声明和业务实现几个环节:

text
mdb_interface
公共接口契约

MDS 声明实现 / 依赖

代码生成

提供方实现业务逻辑

调用方通过资源协作接口访问

mdb_interface 负责定义统一接口契约,MDS 描述组件实现或依赖哪些接口,代码生成机制提供基础访问和实现入口,最终由业务组件补充实际处理逻辑。

因此,需要区分“接口已经定义”和“组件已经实现该接口”。只有完成组件侧实现并进入运行态后,相应 RPC 能力才真正可供其他组件调用。

跨组件 RPC 调用还可能涉及调用上下文。RPC 回调中的 ctx 用于承载调用相关上下文信息;当调用继续跨越其他组件时,需要根据业务要求保持相应上下文。

3.3 MDS 与 CSR / PSR 的映射关系

对于硬件相关组件,软件模型和硬件自描述共同参与对象管理:

text
MDS
软件类 / 属性 / 接口模型

          │ 对应

业务组件管理对象


CSR / PSR
实际硬件 / 对象实例 / 拓扑

MDS 定义软件能够识别和管理的模型边界,CSR/PSR 描述具体部件或产品中的实际硬件及实例信息。组件结合两者,将通用软件模型落实到具体硬件环境中。

这种机制使业务代码能够尽量基于统一模型工作,而将不同板卡、部件或产品之间的硬件差异交由自描述配置承载。

3.4 进程、Skynet 服务与协程调度

组件运行时涉及进程、Skynet 服务和协程等不同层次:

text
进程

Skynet 服务

协程 / Task

进程提供操作系统级运行和隔离环境;Skynet 服务承载具体运行态业务;协程用于组织服务内部的异步任务。Skynet 进程内部的工作线程负责调度服务执行。

因此,运行机制的重点是明确不同层次的职责:进程提供运行环境,服务承载业务,协程组织异步执行。

3.5 单元测试与集成测试

开发者测试从组件内部和组件边界两个层次验证功能:

text
组件内部逻辑

   单元测试

组件边界与协作

   集成测试

单元测试重点验证函数、模块和内部业务逻辑,外部依赖通常通过 Mock 隔离;集成测试重点验证资源协作接口、RPC 以及组件之间的实际协作行为。

两类测试共同保证组件既能独立验证内部逻辑,也能验证对外接口是否符合预期。

3.6 CMake、Conan 与组件包

组件从源码到独立交付物,需要经过编译、安装和打包:

text
组件源码

CMake 编译 / 安装

Conan 打包与依赖管理

Conan 组件包

CMake 主要负责源码如何编译、链接和安装,Conan 负责组件包及其依赖的管理和交付,bingo 为这些工程动作提供统一入口。

最终形成的 Conan 组件包,是组件进入产品集成阶段的重要交付边界。

3.7 manifesthica

组件进入产品后,还需要解决“选择哪些组件”和“组件如何运行”两个不同问题:

text
Conan 组件包

manifest
选择产品包含哪些组件及版本

产品制品

hica
组织组件运行关系

组件运行环境

manifest 侧重产品组件组合,hica 侧重运行时组织和编排。二者分别解决产品构成和运行关系问题,不应混为一谈。

4. 组件开发中的关键概念关系

前文已经介绍了主要概念及其连接机制。本章只对开发过程中容易混淆的几个概念进行集中区分。

4.1 MDS 类和运行态对象

MDS model.json 中定义的是类和模型结构,运行时组件则根据模型管理具体对象实例。

可以理解为:

text
MDS 类
   ↓ 实例化 / 管理
运行态对象

具体对象路径和属性数据

“类”描述一类对象具有什么属性和能力,“对象”则是运行过程中实际存在和被管理的实例。

4.2 资源协作接口和 RPC 实现

公共接口定义描述接口允许访问哪些属性、调用哪些方法,但接口被定义并不意味着某个业务组件已经完成对应功能。

完整关系为:

text
接口契约

MDS 声明

代码生成

业务实现

运行时形成对应的资源协作能力

因此,需要区分接口契约、模型声明、自动生成代码和业务实现。组件完成实际实现并进入运行态后,相关能力才能通过资源协作接口对外提供。

4.3 build/test 依赖和 required 依赖

不同依赖对应不同阶段:

类型主要阶段解决的问题
dependencies.build构建阶段组件构建需要哪些 Conan 包
dependencies.test测试阶段开发者测试需要哪些组件或包
required运行阶段组件运行时需要访问哪些资源协作接口

因此,“构建时依赖某个包”和“运行时需要某个资源”不是同一个概念。组件能够成功编译,也不代表运行环境中的资源依赖已经满足。

4.4 CSR Object 和 D-Bus Object

CSR 中的 Objects 用于描述具体硬件或业务实例;D-Bus Object 则属于运行态资源协作体系中的对象,两者处于不同层次。

可以理解为:

text
CSR Object

描述具体硬件 / 业务实例

由相应组件结合 MDS 模型加载和管理

需要对外提供的能力
通过相应运行态资源协作接口暴露

因此,CSR 是硬件和实例配置入口,不是 D-Bus 接口定义文件,也不能简单理解为每一个 CSR Object 都与一个 D-Bus Object 一一对应。

4.5 Conan 包和运行中的组件

Conan 包是组件的构建和交付形态,运行中的 Skynet 服务等则属于组件的运行形态

完整关系可以理解为:

text
组件源码

构建

Conan 包

产品集成

设备环境

组件被拉起

形成运行态服务

因此,“组件包已经生成”只表示组件具备了可交付的软件包形态,并不表示组件已经在目标系统中运行。

5. 组件开发生命周期概览

前面的章节分别介绍了组件开发中的基本概念。将这些概念串联起来,一个组件从设计到进入产品,大致经历以下生命周期:

text
组件设计

接口与模型定义

代码生成

业务实现

硬件配置与适配(需要时)

运行与资源协作

开发者测试

组件构建与打包

产品集成

设备运行

并非所有组件都涉及完全相同的环节。例如,与具体硬件无关的纯业务组件可能不需要直接处理 CSR;不同语言和运行形态的组件在具体实现方式上也可能存在差异。

5.1 组件边界与接口契约

组件开发首先需要确定功能边界,包括组件负责管理什么业务和对象、向外提供哪些能力、依赖哪些外部能力,以及是否与具体硬件相关。

如果某项能力需要跨组件使用,还需要通过统一资源协作接口形成稳定的接口契约。

这一阶段主要确定:

说明

组件负责什么,以及组件与其他组件之间的边界在哪里。

5.2 模型定义与代码生成

组件边界明确后,通过 MDS 描述组件的软件模型,并通过公共接口定义确定需要实现或依赖的资源协作能力。

模型完成后,工程框架根据模型生成相应基础代码:

text
业务设计

模型与接口定义

代码生成

组件基础框架

这一阶段将业务设计转化为可实现的软件结构,并通过代码生成机制承载通用框架能力。

5.3 业务实现

在生成的基础框架上,开发者补充具体业务逻辑,使模型中定义的对象、属性和接口形成实际业务行为。

业务实现通常涉及对象管理、接口实现、跨组件调用、错误处理以及周期或异步业务逻辑等内容。

对于 Lua 组件,这些业务逻辑通常由 Skynet 服务承载。

5.4 硬件配置与适配

对于硬件相关组件,还需要结合 CSR 等硬件自描述信息,将 MDS 定义的软件模型与具体部件中的实际硬件和对象实例建立对应关系。

text
MDS 软件模型


   业务组件


CSR 硬件实例描述

这一环节使通用业务模型能够适配不同板卡或部件,并减少业务代码对具体硬件差异的直接依赖。

5.5 运行与资源协作

完成模型、业务实现以及必要的硬件适配后,组件进入运行环境。

运行态组件通过 Skynet 等运行框架承载业务,并通过资源协作接口与其他组件交换数据、访问属性或调用 RPC。

此时,前面定义的软件模型、接口契约和业务逻辑共同形成实际运行能力。

5.6 测试、构建与组件交付

组件需要通过开发者测试验证内部逻辑和组件边界行为,再通过构建系统形成可独立交付的组件包:

text
组件实现

开发者测试

CMake / Conan 构建

Conan 组件包

组件包代表组件进入产品集成阶段前的独立交付形态。

5.7 产品集成与设备运行

组件包最终需要进入具体产品。产品通过 manifest 等机制选择和组合所需组件及版本,并通过 hica 等运行编排机制组织组件在设备中的运行关系。

text
多个组件包

产品组件组合

产品制品

运行编排

设备中的完整 BMC 系统

至此,组件完成从软件设计、实现和验证到产品集成与设备运行的完整生命周期。

6. 组件开发整体概念图

6.1 核心概念关系

可以用下面的关系理解 openUBMC 组件开发中的主要概念:

text
                         ┌──────────────────────┐
                         │   mdb_interface      │
                         │ 接口契约 / 公共错误   │
                         └──────────┬───────────┘

                           接口定义 / 实现 / 依赖


┌──────────────┐          ┌──────────────────────┐
│ MDS          │─────────▶│      业务组件         │
│ 软件模型      │ 代码生成  │ 模型对象 + 业务代码   │
└──────┬───────┘          └──────────┬───────────┘
       │                              │
       │                              │ 资源协作接口
       │                              │ D-Bus / RPC
       │                              ▼
       │                     ┌────────────────────┐
       │                     │    其他业务组件     │
       │                     └────────────────────┘

       │ 模型与实例对应

┌──────────────┐
│ CSR / PSR    │
│ 硬件实例/拓扑 │
└──────────────┘

业务组件运行

Skynet / Service / Coroutine

开发者测试
UT / 集成测试 / Mock

组件构建与交付
bingo / CMake / Conan

产品集成
manifest / hica

产品制品与设备运行

6.2 总结

openUBMC 组件开发可以概括为一条由模型、实现、运行、验证、交付和集成共同组成的链路:MDS 定义组件的软件模型,mdb_interface 提供公共接口契约,业务组件在生成框架上实现具体功能;硬件相关组件结合 CSR/PSR 完成软件模型与实际硬件实例的对应;运行时通过 Skynet 等框架承载业务,并通过资源协作接口完成跨组件协作;组件经过开发者测试、CMake/Conan 构建后形成独立组件包,再通过 manifesthica 等机制进入具体产品。