云原生API网关微服务服务网格【免费下载链接】easegressA Cloud Native traffic orchestration system. (CNCF Project)项目地址https://gitcode.com/gh_mirrors/ea/easegress点击查看免费下载导读Easegress 的 Custom Data 特性为集群内的任何数据提供了一套统一、可校验、可订阅的持久化存储供 Pipeline、过滤器等各类组件共享与复用。本文以官方文档为骨架结合仓库源码系统讲解CustomDataKind的类型定义、CustomData的数据约束、完整的 v2 REST API 与egctl操作命令并深入到 etcd 存储布局、JSON Schema 校验与事务批量更新等底层实现帮助你从使用到原理全面掌握这一开发扩展能力。为什么需要 Custom DataEasegress 是一个云原生流量编排系统其内部存在大量组件之外的附属数据需要持久化例如某个过滤器要保存自身的运行状态、某个 Controller 要写入业务自定义的元数据等。这些数据有两种特点Schema 不固定不同组件持久化的数据结构千差万别需要跨成员共享集群中所有节点应当看到同一份数据。为此Easegress 提供了Custom Data特性它实现了一个存储任何数据any data的通用能力可以被其他组件直接用来做数据持久化。由于不同组件的数据结构不同必须通过CustomDataKind自定义数据类型来区分彼此。整个特性由三部分构成CustomDataKind数据类型的定义规定了标识字段与数据校验规则CustomData实际存储的数据项是与 Kind 关联的键值映射API / egctl对外暴露的增删改查与批量操作入口。从源码看存储层实现在 pkg/cluster/customdata/customdata.goAPI 层路由注册在 pkg/api/customdata.go客户端命令则位于 cmd/client 下。CustomDataKind自定义数据类型CustomDataKind用于描述某一类数据的规范它定义了这类数据项的标识字段ID以及可选的 JSON Schema 校验规则。定义示例下面的 YAML 定义了一个名为kind1的 CustomDataKindname: kind1 kind: CustomDataKind idField: name jsonSchema: type: object properties: name: type: string required: - name各字段含义如下字段必填说明name是该 Kind 的名称也是后续数据项的类型名在 API 路径中作为{kind name}使用kind是固定为CustomDataKind标识这是一份类型定义资源idField否数据项中用作唯一标识的字段名默认值为namejsonSchema否一段 JSON Schema 规范若提供则该 Kind 下所有数据项在写入前都会按此规则校验在源码 pkg/cluster/customdata/customdata.go 中Kind结构体的定义与此一一对应type Kind struct { Name string json:name jsonschema:required IDField string json:idField,omitempty JSONSchema dynamicobject.DynamicObject json:jsonSchema,omitempty }idField 的默认与解析逻辑idField的取值逻辑非常直接为空时回退为name。对应源码 GetIDField 与 dataIDfunc (k *Kind) GetIDField() string { if k.IDField { return name } return k.IDField } func (k *Kind) dataID(data Data) string { var id string if k.IDField { id, _ data[name].(string) } else { id, _ data[k.IDField].(string) } return id }即数据项的 ID 就是其idField字段的值同一 Kind 内 ID 必须唯一。测试用例 TestDataID 验证了默认name与自定义key两种场景下的 ID 提取结果。JSON Schema 的两层校验JSON Schema 校验发生在两个时机且都使用gojsonschema库定义 Kind 时PutKind会先加载kind.JSONSchema并调用gojsonschema.NewSchema校验 Schema 本身是否合法非法 Schema 直接拒绝创建customdata.go。写入数据时PutData与BatchUpdateData都会将数据项与 Schema 比对校验失败返回validation failed错误customdata.go。对应的测试 TestPutKind 覆盖了非法 Schema、重复创建、更新不存在 Kind 等失败路径TestPutData 则覆盖了空 ID、校验失败、校验通过等场景。创建 Kind 的命令官方文档给出的两种方式等价egctl create -f kind1.yaml egctl apply -f kind1.yaml两者都支持从文件或 stdin 读取 YAMLcreate对应 HTTPPOSTapply同样通过POST路径落库详见下文批量更新说明。CustomData数据项CustomData本质上是一个 map键必须是字符串值可以是任意合法的 JSON 值嵌套 map 的键同样必须是字符串。在源码中数据项被定义为dynamicobject.DynamicObject即map[string]interface{}customdata.go、dynamicobject.go。dynamicobject.go 中的UnmarshalYAML还特别处理了一个细节从 YAML 反序列化时嵌套 map 可能变成map[interface{}]interface{}标准json包无法处理因此会递归转换为map[string]interface{}——这正是文档要求嵌套 map 的键必须是字符串的根本原因。数据项必须包含 ID 字段每个CustomData数据项必须包含其所属CustomDataKind定义的idField。以上文kind1为例其idField为name因此数据项必须携带name字段作为标识。写入时若 ID 为空PutData会直接报错data id is emptycustomdata.go。数据项示例以下是一个kind1类型的数据项name: data1 field1: 12 field2: abc field3: [1, 2, 3, 4]name: data1是 ID 字段取值为data1field1、field2、field3是任意业务字段值分别为数字、字符串和数组均为合法 JSON 值。数据项的键对应 etcd 存储键同一 Kind 的数据存储在以/custom-data/{kind}/为前缀的键空间下每条数据以idField的值作为键名见下文存储布局。REST API 速查Custom Data 的 REST API 位于 Easegress API Server 的/apis/v2前缀下见 pkg/api/api.go 中的APIPrefixV2常量默认端口2381即http://{ip}:{port}/apis/v2。路由注册在 pkg/api/customdata.go完整端点如下。CustomDataKind 相关 API操作方法URLBody创建 CustomDataKindPOST/apis/v2/customdatakindsKind 定义YAML更新 CustomDataKindPUT/apis/v2/customdatakindsKind 定义YAML查询单个 Kind 定义GET/apis/v2/customdatakinds/{kind name}-列出所有 Kind 定义GET/apis/v2/customdatakinds-删除一个 KindDELETE/apis/v2/customdatakinds/{kind name}-值得注意GET /apis/v2/customdatakinds与GET /apis/v2/customdatakinds/{kind name}返回的每个 Kind 都附带len字段该 Kind 当前的数据条数由DataLen计算得出customdata.go、customdata.go。这也是egctl get customdatakind能打印出 DATA-NUM 列的来源。CustomData 相关 API操作方法URLBody创建 CustomDataPOST/apis/v2/customdata/{kind name}数据项定义YAML更新 CustomDataPUT/apis/v2/customdata/{kind name}数据项定义YAML查询单个数据项GET/apis/v2/customdata/{kind name}/{data id}-列出某 Kind 的所有数据GET/apis/v2/customdata/{kind name}-删除单个数据项DELETE/apis/v2/customdata/{kind name}/{data id}-删除某 Kind 的所有数据DELETE/apis/v2/customdata/{kind name}-批量更新Change RequestPOST/apis/v2/customdata/{kind name}/items变更请求YAML批量删除某 Kind 全部数据DELETE/apis/v2/customdata/{kind name}/items-创建/更新的语义细节从 pkg/api/customdata.go 与 pkg/api/customdata.go 可以看到createPOST走PutData(kind, data, false)数据已存在则报错existedupdatePUT走PutData(kind, data, true)数据不存在则报错not found创建成功后响应头Location会携带新资源的完整路径响应码为201 Created。同理Kind 的创建/更新也遵循这一幂等区分约定PutKind(kind, false)不允许覆盖已存在的 KindPutKind(kind, true)不允许更新不存在的 Kindcustomdata.go。批量更新Change Request对于需要一次性增删多条数据的场景Custom Data 提供了批量更新接口POST /apis/v2/customdata/{kind name}/items请求体是一个 Change RequestYAML结构如下name: kind1 kind: CustomData rebuild: false delete: [data1, data2] list: - name: data3 field1: 12 - name: data4 field1: foo语义说明字段默认值说明name-目标CustomDataKind的名称kind-固定为CustomDatarebuildfalse为true时先删除该 Kind 下的所有既有数据项再处理list中的数据delete-要删除的数据项 ID 数组当rebuild为true时该字段被忽略list-要创建或更新的数据项数组写入采用 upsert 语义同一 ID 直接覆盖底层实现中delete与list的写操作被放进**一个 etcd 事务STM**内原子执行要么全部成功、要么全部失败customdata.go这保证了批量操作的一致性。rebuild的全量清理则由 API 层先调用DeleteAllData完成pkg/api/customdata.go。客户端同样支持以 Change Request 形式创建或应用egctl create -f customdata-change-request.yaml egctl apply -f customdata-change-request.yaml其中name是CustomDataKind名称kind为CustomData。egctl 实战操作egctl 同时保留了新旧两套命令老式命令v1 风格在源码中已标记为(Deprecated)新式命令v2 风格与egctl get/describe/create/apply/delete/edit统一资源模型为推荐用法。新版命令推荐新式命令在 cmd/client/commandv2 中注册资源定义见 cmd/client/resources/customdata.go 与 cmd/client/resources/customdatakind.go# Kind 操作 egctl get customdatakind # 列出所有 Kind egctl get customdatakind kind1 # 查询单个 Kind egctl describe customdatakind kind1 # 描述单个 Kind egctl delete customdatakind kind1 # 删除一个 Kind # 数据操作customdata 支持两级参数kind [id] egctl get customdata kind1 # 列出 kind1 的所有数据 egctl get customdata kind1 data1 # 查询 kind1 下的 data1 egctl describe customdata kind1 data1 egctl delete customdata kind1 data1 # 删除单条数据 egctl delete customdata kind1 --all # 删除 kind1 的全部数据 # 创建 / 应用 / 编辑 egctl create -f kind1.yaml # 创建 Kind或通过 Change Request 写数据 egctl apply -f kind1.yaml egctl edit customdata kind1 # 以批量形式编辑 kind1 的所有数据 egctl edit customdata kind1 data1 # 编辑单条数据几个值得注意的行为均有源码依据get customdata kind默认以表格输出每行仅展示该 Kind 的 ID 字段值describe则打印完整字段customdata.go。edit不允许修改 ID 字段编辑保存时会比较新旧数据的idField值不一致则报错edit cannot change the idField of custom datacustomdata.go。get/describe customdatakind会以表格展示NAME / ID-FIELD / JSON-SCHEMA / DATA-NUM四列customdatakind.go。所有 v2 命令的 URL 均由 cmd/client/general/urls.go 统一定义前缀为/apis/v2。旧版命令已弃用老式命令定义在 cmd/client/command/customdata.goShort描述中明确标注(Deprecated)但功能仍完整可用egctl custom-data-kind list # 列出所有 Kind egctl custom-data-kind get kind # 查询单个 Kind egctl custom-data-kind create -f kind file # 创建 Kind egctl custom-data-kind update -f kind file # 更新 Kind egctl custom-data-kind delete kind # 删除 Kind egctl custom-data list kind # 列出某 Kind 的数据 egctl custom-data get kind id # 查询单条数据 egctl custom-data create kind -f data file # 创建数据 egctl custom-data update kind -f data file # 更新数据 egctl custom-data batch-update kind -f change-request file # 批量更新 egctl custom-data delete kind id # 删除单条数据底层实现存储布局、并发与监听etcd 存储布局Custom Data 最终落在集群的 etcd 中键空间由 pkg/cluster/layout.go 定义customDataKindPrefix /custom-data-kinds/ customDataPrefix /custom-data/Kind 定义存储键/custom-data-kinds/{kind name}数据项存储键/custom-data/{kind name}/{data id}。API Server 初始化时通过Layout()获取这两个前缀并构造 Storepkg/api/server.go后续所有读写都基于cluster.Cluster接口完成GetRaw / Put / Delete / STM 等。并发安全与一致性单条写PutData的已存在/不存在检查基于先读后写批量写则通过cluster.STMetcd 事务包裹确保delete与list原子生效。删除 Kind 的级联行为DeleteKind会先调用DeleteAllData清空该 Kind 下所有数据再删除 Kind 定义本身避免产生悬挂数据customdata.go。DELETE /apis/v2/customdatakinds会一次删除全部 Kind 及其数据DeleteAllKinds属于高危操作。数据变更监听Watch除增删改查外Store 还提供了Watch(ctx, kind, onChange)方法用于持续监听某个 Kind 的数据变更它通过集群 Syncer 拉取该 Kind 前缀下的全部键值每次变化都会以完整数据切片回调onChangecustomdata.go。这为数据变更驱动业务逻辑例如配置下发、规则同步提供了标准机制。实践建议与限制先定义 Kind再写数据PutData会先检查 Kind 是否存在不存在直接返回kind %s not found善用jsonSchema做数据守门它在 Kind 创建与数据写入两个阶段都会校验是保证数据质量的第一道防线大批量更新优先走 Change Request借助 etcd STM 保证原子性避免逐条POST的非事务风险rebuild: true会清空整个 Kind适用于整体替换场景但请确认不会误删存量数据ID 一经写入不可通过edit修改如需变更 ID请走删除 新建流程。说明本文 API 与命令均基于当前仓库源码pkg/api/customdata.go、pkg/cluster/customdata/customdata.go、cmd/client默认 API Server 地址为http://{ip}:2381实际以你的 Easegress 集群配置为准。赞分享云原生API网关微服务服务网格【免费下载链接】easegressA Cloud Native traffic orchestration system. (CNCF Project)项目地址https://gitcode.com/gh_mirrors/ea/easegress点击查看免费下载相关推荐iOS Expanding Collection与Core Data集成数据持久化的终极实践指南iOS Expanding Collection与Core Data集成数据持久化的终极实践指南 Expanding Collection是一个强大的iOS动移动开发UI组件MDS 2.1 快速入门如何在10分钟内理解这个革命性的移动出行数据规范MDS 2.1 快速入门如何在10分钟内理解这个革命性的移动出行数据规范 想要快速掌握全球移动出行数据标准MDS 2.1吗 这篇终极指南将带你了解这个改如何永久保存微信聊天记忆WeChatMsg开源工具终极指南如何永久保存微信聊天记忆WeChatMsg开源工具终极指南 你是否曾担心珍贵的微信聊天记录会随着手机更换而永久消失在数字时代微信对话不仅是简单的文字交流上一篇GrapesJS Trait Manager API 完全指南组件设置面板的配置、事件与自定义类型开发下一篇Envoy HTTP/2 流控整数溢出修复深度解析unconsumed_bytes_ 回绕问题创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考