数据湖上了 Iceberg最磨人的往往不是计算而是 catalog。自建要么养一套 Hive Metastore要么跑一个 Polaris 或 Nessie光这一层又是一套服务要盯监控、要备份、要升级。很多人想试 Iceberg最后被表存在哪、元数据谁管两个问题劝退表没建几张先招了个专职运维。有人就琢磨catalog 管的就是表在对象存储里的位置那能不能让对象存储自己把这层也管了近两年这个方向确实热AWS 的 S3 Tables、一众开源 catalog 项目都在往存储即目录靠拢。本文拆一个具体做法把 Iceberg REST Catalog 直接做进对象存储内核一个进程、一个端口同时对外讲标准 S3 和 Iceberg REST。传统两件套的账经典玩法里对象存储管数据catalog 另起一个服务管元数据两边各管各的。代价是实打实的多一套进程要保活多一个依赖要升级多一份元数据要备份。catalog 和对象存储之间要有网络连通和鉴权对齐配错一处表就读不到。团队规模小的时候这一层的人力占比高得离谱。RustFS 从 1.0.0-rc.5 起把这套能力以S3 Table的形式开源内置了走的正是对象存储内核直接带 Iceberg REST Catalog这条路。下面看它怎么把两件套合成一个进程。一个进程两套协议起一个单节点S3 数据和 Iceberg REST Catalog 都在 9000 端口数据面走标准 S3控制面走/iceberg路径的 Iceberg REST。控制台 UI 单独在 9001。想确认 catalog 真的在监听一条 curl 就能验curl-XGET http://ip:9000/iceberg/v1/config\-HAuthorization: AWS4-HMAC-SHA256 ...返回里有defaults和signing-region说明控制面已经起来了。这一层是标准的 Iceberg REST 协议不绑定某个计算引擎。控制面CAS 加幂等键建表、提交快照这类写 catalog 的操作走 Iceberg REST Catalog。这里的一致性靠两件事CASCompare-And-Swap版本校验并发提交时过期的快照提交会被拒绝不会出现后提交的覆盖了先提交的。幂等键同一个提交重复发送catalog 只生效一次网络重试不会造出重复表版本。多引擎同时写也能保证目录层一致不用在存储侧加全局锁。数据面S3 直写存算分离真正的 Parquet 文件不进 catalog而是由计算引擎经 S3 API 直写桶内。catalog 只存元数据指针文件本身走标准 S3 写入路径。这就是典型的存算分离计算集群挂了数据还在桶里计算扩容不用动 catalog。防写坏保留前缀护住目录层元数据指针受保留前缀保护普通 S3 的 PUT/DELETE 改不动目录层结构。好处是你往桶里塞自己的非结构化对象时不会误手把 Iceberg 的元数据指针删了数据湖不会被写坏。反过来表数据落进去之后也要分清哪些 prefix 是表、哪些是你自己塞的对象别误删。并发冲突怎么走多引擎同时提交快照靠的是 catalog 的 CAS 拒绝过期提交不是存储层加锁。所以高频并发写的场景冲突会走读最新快照、重算、再提交的乐观路径。写应用的时候把重试逻辑留好比指望底层无锁更稳。这种架构适合谁团队小、不想养 metastore 的一个进程把数据和目录都管了运维面小。已经是 Spark / DuckDB / PyIceberg 技术栈的不用为 catalog 单独学一套系统。想存算分离的数据面走 S3、计算集群可独立扩缩。可以照着看的一步想判断这条路适不适合你半小时内能验证起一个单节点容器控制台建个桶并启用表存储桶用上面那条 curl 确认/iceberg/v1/config能返回再拿一段 PySpark 把表建出来。控制面和数据面是不是你要的一测就知道比看架构图实在。