- 后端
- 企业应用
- 运维
【免费下载链接】bk-cmdb
蓝鲸智云配置平台(BlueKing CMDB)
导读
本文围绕蓝鲸智云配置平台(bk-cmdb)对外提供的resource_watch 事件监听接口展开,系统讲解该接口支持的资源类型、三种监听起点(时间点 / 当前时刻 / 游标)、短长链推拉结合的会话机制、批量事件与字段裁剪能力,并结合仓库源码(src/source_controller/cacheservice/event/watch/watch.go、src/common/watch/等)剖析其背后的**事件链(Event Chain)+ 游标(Cursor)**实现原理。读完本文,你将掌握如何通过该接口追踪 CMDB 中主机、业务、模型实例等资源的变化事件,以及如何利用游标实现异常数据回溯与断点续听。
该接口属 ESB/API 网关透传类 OpenAPI,对应文档原版位于 docs/apidoc/cc/en/resource_watch.md,中文版见 docs/apidoc/cc/zh_hans/resource_watch.md。
一、接口能力概述
resource_watch 用于监听系统资源变化产生的事件。该能力从 v3.8 版本起提供,调用权限按监听的资源类型划分,包括:主机事件监听、主机关系事件监听、业务事件监听、集群(Set)事件监听、模块(Module)数据监听、进程数据监听、模型实例事件监听、自定义拓扑层级(主线模型)事件监听、实例关联事件监听、业务集事件监听、管控区域(云区域)事件监听、容器集群 / 节点 / 命名空间 / 工作负载 / Pod 事件监听、项目事件监听等。
其核心特性包括:
- 限时高可用 watch:在有限时间窗口内(接口文档标注目前为 3 小时,官方明确"可能会调整,请勿依赖此时间")提供高可用的数据变更监听服务。
- 断点追数:在有限时间内,用户可基于上一次事件返回的游标(cursor)进行事件回溯或数据补录,适用于异常数据回溯与系统变更后的数据补齐。
- 三种监听起点:支持按时间点回溯、按游标回溯、从当前时间点开始监听三种方式。
- 事件类型过滤:支持按 create(新增)/ update(更新)/ delete(删除)事件类型筛选,事件中携带全量数据。
- 主机与主机关系联动:支持监听主机详情与主机关系数据的变化。
- 短长链设计:用户携带游标监听时,若无事件则保持会话连接(长链等待),在超时窗口(源码中为 20 秒)内一旦有事件产生便直接推回,避免频繁轮询,同时保证变更数据的及时性。
- 批量事件:支持一次返回一批事件(源码中单批上限
eventStep = 200),提升系统吞吐。 - 字段裁剪:支持自定义返回事件数据中的字段,满足轻量级 watch 需求。
二、请求参数详解
2.1 公共参数
接口遵循 CMDB OpenAPI 公共参数规范(common_args_desc),即需要携带bk_app_code、bk_app_secret、bk_username、bk_token等鉴权信息,具体见仓库 docs/apidoc/README.md 与 apidoc 公共参数说明。
2.2 接口参数
| 字段 | 类型 | 必选 | 描述 |
|---|---|---|---|
| bk_event_types | array<string> | 否 | 事件类型,填了则只关注该类型事件。可选值:create(新增)/ update(更新)/ delete(删除)。不填(空数组)则关注所有事件。 |
| bk_fields | array<string> | 视情况 | 事件中需要返回的字段列表。监听主机(host)资源时该字段必填且不能为空;主机关系(host_relation)可置空;置空则默认返回所有字段。 |
| bk_start_from | Int64 | 否 | 监听事件的起始时间,值为 Unix 时间戳(秒),即从 UTC 1970-01-01 00:00:00 起至目标时间点的总秒数。 |
| bk_cursor | string | 否 | 监听事件的游标,代表开始或继续监听的事件地址,系统返回该游标的下一个或一批事件。 |
| bk_resource | string | 是 | 要监听的资源类型,枚举值见下表。 |
| bk_supplier_account | string | 是 | 开发商账号。 |
| bk_filter | object | 否 | 过滤条件,目前支持bk_sub_resource。 |
bk_resource 可选值:host(主机详情事件)、host_relation(主机关系事件)、biz(业务详情事件)、set(集群详情事件)、module(模块详情事件)、process(进程详情事件)、object_instance(通用模型实例事件)、mainline_instance(主线模型实例事件)、biz_set(业务集事件)、biz_set_relation(业务集与业务的关系事件)、plat(管控区域事件)、project(项目事件)。
2.3 bk_filter
| 字段 | 类型 | 必选 | 描述 |
|---|---|---|---|
| bk_sub_resource | string | 否 | 要监听的下级资源类型,仅当 bk_resource 为 object_instance 或 mainline_instance 时使用,代表需要监听的模型的bk_obj_id。 |
需要说明的是,从当前仓库源码看,watch 支持的内部资源类型实际比接口文档枚举更丰富。在 src/common/watch/cursor.go 中定义了CursorType常量,除文档列举的 12 类外,还包含process_instance_relation、host_identifier(主机、主机关系、进程等事件混合后转换为主机标识事件)、inst_asst(实例关联事件)以及kube_cluster、kube_node、kube_namespace、kube_workload、kube_pod等容器相关类型,对应文档中"容器集群/节点/命名空间/工作负载/Pod 事件监听"的权限描述。ListCursorTypes()返回的完整列表见 src/common/watch/cursor.go。
2.4 关于 biz_set_relation 事件的特别说明
biz_set_relation事件会在以下场景触发:
- 业务集的
bk_scope字段被新增、删除或更新; - 业务的新增、删除、更新导致业务集与业务的关系发生变更。
所有业务集关系事件的事件类型(bk_event_type)均为 update;事件详情中返回关系发生变更的业务集 ID 和该业务集包含的所有业务 ID 列表;当事件由业务集删除事件触发时,返回的业务 ID 列表为空。
三、请求参数示例
3.1 监听主机事件
{ "bk_app_code": "esb_test", "bk_app_secret": "xxx", "bk_username": "xxx", "bk_token": "xxx", "bk_event_types": ["create", "update", "delete"], "bk_fields": ["bk_host_innerip", "bk_mac"], "bk_start_from": 12345678999, "bk_cursor": "MQ0yDTE1ODkyMDcyODENMQ01ZWI3ZWZjNTBiOTA5ZTYyMGFmYWQzZGY=", "bk_resource": "host" }3.2 监听通用模型实例事件
{ "bk_event_types": [], "bk_fields": ["bk_inst_id", "bk_inst_name"], "bk_start_from": 12345678999, "bk_cursor": "MQ0yDTE1ODkyMDcyODENMQ01ZWI3ZWZjNTBiOTA5ZTYyMGFmYWQzZGY=", "bk_resource": "object_instance", "bk_filter": { "bk_sub_resource": "xxx" }, "bk_supplier_account": "0" }注意:上述示例同时携带了
bk_start_from与bk_cursor,仅作参数形态演示。在真实调用中二者不能同时使用——源码 src/common/watch/watch.go 的Validate()明确校验:"bk_start_from and bk_cursor can not use at the same time",同时指定会直接报参数错误。
四、返回参数说明
4.1 完整返回示例
{ "result": true, "code": 0, "message": "success", "permission": null, "request_id": "e43da4ef221746868dc4c837d36f3807", "data": { "bk_watched": true, "bk_events": [ { "bk_cursor": "MQ0yDTE1ODkyMDcyODENMQ01ZWI3ZWZjNTBiOTA5ZTYyMGFmYWQzZGY=", "bk_resource": "host", "bk_event_type": "update", "bk_detail": { "bk_cpu": 2 } }, { "bk_cursor": "MQ0yDTE1ODkzNDExMDcNMQ01ZWI3ZWZjNTBiOTA5ZTYyMGFmYWQzZGY=", "bk_resource": "host", "bk_event_type": "update", "bk_detail": { "bk_cpu": 2 } } ] } }4.2 response 顶层字段
| 字段 | 类型 | 描述 |
|---|---|---|
| result | bool | 请求是否成功。true:成功;false:失败 |
| code | int | 错误编码。0 表示 success,>0 表示失败 |
| message | string | 请求失败时返回的错误信息 |
| permission | object | 权限信息 |
| request_id | string | 请求链 ID |
| data | Array | 事件数据详情,是一个有序数组,数组尾部的事件为最新事件 |
4.3 data 字段
| 字段 | 类型 | 描述 |
|---|---|---|
| bk_watched | bool | 是否监听到了事件。true:监听到了事件;false:未监听到事件 |
| bk_events | array | 事件详情列表,最大长度为 200(后续可能调整,请勿依赖该长度) |
4.4 bk_events 中的单个事件字段
| 字段 | 类型 | 描述 |
|---|---|---|
| bk_cursor | string | 当前资源事件的游标值,调用方可用该游标获取此事件之后的下一个事件 |
| bk_resource | string | 该事件对应的资源类型 |
| bk_event_type | string | 事件类型,枚举值:create(新增)/ update(更新)/ delete(删除) |
| bk_detail | object | 事件对应资源的详情数据,不同资源详情不同 |
4.5 各资源 bk_detail 示例
host_relation(主机关系)资源:
{ "bk_biz_id": 1, "bk_host_id": 2, "bk_module_id": 3, "bk_set_id": 4, "bk_supplier_account": "0" }host(主机)资源:
{ "bk_host_name": "hostname", "bk_mem": null, "bk_cloud_id": 0, "operator": "user", "bk_cpu": null, "bk_mac": "", "bk_host_innerip": "192.168.1.1", "bk_supplier_account": "0", "...." }biz_set_relation 资源:
{ "bk_biz_set_id": 1, "bk_biz_ids": [1, 2, 3] }| 字段 | 类型 | 描述 |
|---|---|---|
| bk_biz_set_id | int | 业务集和业务关系发生变化的业务集 ID |
| bk_biz_ids | int array | 该业务集所包含的所有业务的 ID 列表 |
五、使用流程与注意事项
5.1 标准使用流程
确定起始监听方式,三选一:
- 1.1 指定从某一时间开始监听:设置
bk_start_from(Unix 秒级时间戳); - 1.2 指定从当前时间开始监听:不传
bk_start_from与bk_cursor,直接发起请求; - 1.3 指定游标开始监听:设置
bk_cursor,从该游标位置继续监听。
确定后发起请求。
- 1.1 指定从某一时间开始监听:设置
处理返回结果:
- 2.1若
bk_watched为 true,表明已监听到事件,bk_events为事件详情列表;调用方取数组最后一个事件的 cursor,用 1.3 的方式继续下一次 watch; - 2.2若
bk_watched为 false,表明未监听到事件,bk_events中只有一个事件(携带可续用的游标),取该事件的 cursor 进行下一次 watch。
- 2.1若
5.2 事件过期与游标失效
事件有过期时间,目前为 3 小时。过期后事件被释放,对应游标(cursor)也一并失效。此时可通过两种方式重新开始监听:
- 指定从某一时间开始监听(
bk_start_from); - 指定从当前时间开始监听。
关于"3 小时"与源码的差异需要特别说明:接口文档标注的事件有效期目前为 3 小时(文档本身声明"可能会调整,请勿依赖此时间");而当前仓库源码中,事件 Key 的
ttlSeconds实际配置为6 * 60 * 60(6 小时),见 src/source_controller/cacheservice/event/key.go 中HostKey等所有 Key 的定义。因此客户端实现应以服务端实际 TTL 为准、并做好过期后的重启逻辑,切勿把任何固定时长写死为业务依赖。源码中 watch.go 在WatchWithStartFrom中会校验bk_start_from是否落在 TTL 范围内(time.Now().Unix() - opts.StartFrom大于 0 且不超过key.TTLSeconds()),超出范围会返回CCErrCommParamsInvalid参数错误。
六、底层实现原理(源码级剖析)
6.1 事件链(Event Chain)与链节点
watch 服务的数据结构基础是事件链。每一类被监听资源对应一个以"原集合名 +WatchChain"命名的链集合(见 src/source_controller/cacheservice/event/key.go 的ChainCollection()),例如主机集合cc_HostBase对应的链集合为cc_HostBaseWatchChain。事件写入数据库后由变更流(Change Stream)捕获,转换为链节点(ChainNode)追加到链尾。
链节点的结构定义在 src/common/watch/types.go:
| 字段 | 说明 |
|---|---|
| id | 自增 ID,用于顺序批量查询 |
| cluster_time | 事件的集群时间戳(MongoDB Change Stream 时间) |
| oid | 事件文档的 ObjectId(即源文档_id值) |
| type | 事件类型(create / update / delete) |
| token | MongoDB resume token;若为空表示链头 |
| cursor | CMDB 生成的游标,与 MongoDB resume token 一一对应 |
| inst_id | 实例 ID,用于事件聚合 |
| bk_sub_resource | 子资源标识(如通用实例事件对应的模型 bk_obj_id) |
| bk_supplier_account | 开发商账号 |
6.2 游标(Cursor)编解码
游标是用户与系统之间传递"事件地址"的载体,其编码规则定义在 src/common/watch/cursor.go。Cursor结构包含版本号、资源类型(CursorType的数字映射)、Oid、操作类型(OperType)、集群时间(秒 + 纳秒)以及可选的UniqKey。编码时按固定顺序以\r分隔各字段后整体做base64 编码,例如文档示例中的MQ0yDTE1ODkyMDcyODENMQ01ZWI3ZWZjNTBiOTA5ZTYyMGFmYWQzZGY=。
游标具备两个重要设计:
- 与 resume token 一对一:每个游标都携带了 MongoDB 的集群时间与 Oid,可精确对应到事件链上的唯一位置;
- 防伪造:Oid 为随机十六进制字符串,避免调用方自行构造游标跳读(src/common/watch/cursor.go)。
此外还预置了一个特殊的NoEventCursor(无事件游标),当长链等待超时仍未产生事件时返回给调用方,标识"当前没有新事件"(src/common/watch/cursor.go)。
6.3 三种监听路径的服务端实现
HTTP 入口在 cacheservice 的 service/cache.go,请求体被解码为watch.WatchEventOptions并经过Validate()校验(src/common/watch/watch.go)后,根据参数选择不同的处理函数:
- 携带
bk_cursor→WatchWithCursor(src/source_controller/cacheservice/event/watch/watch.go):先按游标向后检索匹配事件,若没有命中则进入轮询等待循环——每隔loopInternal = 250ms重查一次事件链,一旦 20 秒超时窗口(timeoutWatchLoopSeconds = 20)内有事件即立即返回;超时仍未命中则返回 NoEventCursor(或最后一个事件的游标),保证调用方可无缝续听。这正是文档所述"短长链设计"的实现:事件随时推回、无事件则保持会话。 - 携带
bk_start_from→WatchWithStartFrom(src/source_controller/cacheservice/event/watch/watch.go):先校验起始时间未过期,再在链集合中按cluster_time > bk_start_from过滤并排序,找到第一个符合条件的事件,随后向后批量拉取一批事件返回。 - 两者均不携带→
WatchFromNow(src/source_controller/cacheservice/event/watch/watch.go):直接取事件链的最新事件(链尾节点)返回,其游标即为"从现在开始继续监听"的起点。
6.4 事件过滤与详情回源
检索链节点时,服务端会同时应用两层过滤(src/source_controller/cacheservice/event/watch/watch.go):
- 事件类型过滤:
isNodeHitEventType检查链节点的事件类型是否在bk_event_types中,未指定则全部命中; - 子资源过滤:
isNodeHitSubResource检查链节点的bk_sub_resource是否匹配bk_filter.bk_sub_resource(仅通用实例 / 主线实例 / 实例关联 / 容器工作负载类资源支持)。
事件详情获取采用两级回源策略(getEventDetailsWithNodes,src/source_controller/cacheservice/event/watch/watch.go):优先从 Redis 缓存批量读取详情;缓存未命中的游标再回 MongoDB 源库补齐;通用资源(host、biz、set、module 等)的详情还会复用通用资源缓存,避免重复存储。返回前通过json.CutJsonDataWithFields按bk_fields裁剪字段,实现轻量级返回。host_identifier与biz_set_relation两类特殊资源则直接从数据库实时生成详情(src/source_controller/cacheservice/event/watch/watch.go)。
6.5 参数校验的边界规则
从源码 src/common/watch/watch.go 的Validate()可以梳理出以下调用约束:
bk_event_types中的每个类型必须为 create / update / delete 之一;- 监听 host / biz / set / module 时
bk_fields不能为空(对外 API 强制校验),这与文档"主机资源该字段必填"的说明一致且覆盖范围更广; bk_start_from与bk_cursor不能同时使用;bk_filter.bk_sub_resource仅允许出现在 object_instance(ObjectBase)、mainline_instance、inst_asst、kube_workload 类资源上,其他资源携带会报错。
6.6 事件链的写入与消费链路
从整体架构看,事件由 cacheservice 内的stream(MongoDB Change Stream 循环监听,见 src/source_controller/cacheservice/service/service.go)捕获数据库写入,经flow.NewEvent等流程转换为链节点与详情写入事件链集合与 Redis,watch 接口再从链上读取。event.Key还承担了通用资源缓存(generalResCacheKey)的关联职责(src/source_controller/cacheservice/event/key.go),使事件详情与资源详情缓存打通复用。
七、典型应用场景
结合接口能力与源码实现,resource_watch 常见的落地场景包括:
- 外部系统实时同步:第三方系统监听 host、biz、set、module 等资源,通过游标持续增量拉取,构建与 CMDB 一致的数据副本;
- 异常数据回溯:数据同步中断或异常后,用
bk_start_from从断点时间重新拉取,或直接用上次事件游标续听(在 TTL 有效期内); - 模型实例订阅:通过
object_instance/mainline_instance配合bk_filter.bk_sub_resource指定模型bk_obj_id,只关心特定模型的实例增删改; - 主机关系感知:监听
host_relation感知主机与模块、集群关系的变更,驱动服务编排或监控策略联动; - 轻量订阅:通过
bk_fields只订阅关心的字段(如仅取bk_host_innerip、bk_mac),降低数据量与带宽开销。
八、接入建议与注意事项汇总
- 游标是续听的唯一凭据:每次成功响应后务必持久化
bk_events末尾事件的bk_cursor,作为下一轮请求的入参;bk_watched = false时也要保存返回单事件中的游标。 - 三种起点按需选择:首次接入用
bk_start_from回溯或"从当前时间开始";日常轮询用bk_cursor增量续听;过期恢复用时间点回溯。 - 事件存在有效期:过期后游标失效,需重新以时间点或当前时间启动监听;不要依赖文档或源码中的任何固定时长,做好重启兜底。
- 合理利用长链等待:携带游标且无事件时,服务端会保持约 20 秒的等待窗口再返回 NoEventCursor,客户端可降低轮询频率、减小请求压力;同时注意设置足够长的 HTTP 客户端超时(建议大于 20 秒)。
- 注意字段与子资源的校验规则:host/biz/set/module 监听必须提供
bk_fields;bk_sub_resource仅用于实例类资源。 - 单批上限:
bk_events最大长度 200(源码常量eventStep = 200),数据量大时应以游标持续分页拉取,直至bk_watched = false。
以上内容均以当前仓库代码为准:接口文档见 docs/apidoc/cc/en/resource_watch.md,服务端实现入口见 src/source_controller/cacheservice/service/cache.go,事件链与游标核心逻辑见 src/common/watch/cursor.go 与 src/common/watch/types.go,事件 Key 与 TTL 定义见 src/source_controller/cacheservice/event/key.go。
- 后端
- 企业应用
- 运维
【免费下载链接】bk-cmdb
蓝鲸智云配置平台(BlueKing CMDB)
相关推荐
蓝鲸 CMDB 资源变更事件监听(Resource Watch)接口全解析:基于游标的事件回溯与实时推送实战指南
蓝鲸 CMDB 资源变更事件监听(Resource Watch)接口全解析:基于游标的事件回溯与实时推送实战指南 本篇技术指南以蓝鲸智云配置平台(BlueKin
后端企业应用运维蓝鲸 CMDB 资源变更事件 watch 接口详解:游标回溯、短长链轮询与实战调用指南
蓝鲸 CMDB 资源变更事件 watch 接口详解:游标回溯、短长链轮询与实战调用指南 蓝鲸智云配置平台(bk cmdb)提供基于 watch 模式的资源变更事
后端企业应用运维蓝鲸配置平台(bk-cmdb)事件订阅修改接口 update_event_subscribe 全解析
蓝鲸配置平台(bk cmdb)事件订阅修改接口 update_event_subscribe 全解析 导读 本文围绕蓝鲸配置平台(bk cmdb)提供的 事件订
后端企业应用运维
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考