Feast HDFS Registry:将特性注册表存储在 Hadoop 分布式文件系统上的配置与实践
【免费下载链接】feastThe Open Source Feature Store for AI/ML项目地址: https://gitcode.com/GitHub_Trending/fe/feast
Feast 的 Registry 是特性仓库中所有对象(数据源、特征视图、特征服务等)的元数据目录,其默认实现是本地文件,但在大数据团队中,注册表往往需要与 Hadoop 集群同址存放,便于统一运维与权限管理。本文以仓库文档 docs/reference/registries/hdfs.md 为主体,完整覆盖 HDFS Registry 的前置条件、认证模型与feature_store.yaml配置示例,并结合 HDFSRegistryStore 的源码实现与集成测试,讲解其读写流程、参数默认值与适用边界,帮助你在 Hadoop 环境中正确接入并评估该注册表后端的并发局限。
一、HDFS Registry 是什么
HDFS registry 支持将 Feast 对象的protobuf 序列化表示(数据源、特征视图、特征服务、实体等)存储在 Hadoop Distributed File System(HDFS)中。注册表的本质是一个 Protobuf 文件,这一点在 Registry 组件文档 中有明确说明:文件型注册表将 Feast 元数据以 Protobuf 形式序列化为单个文件,可被其他语言程序读取,但官方不承诺内部结构的兼容性。
需要先明确适用边界:文档原文指出,虽然 HDFS registry可以用于生产,但文件型注册表存在固有局限——修改注册表中的任何单个字段都需要重写整个注册表文件。在多个并发写入者的场景下(例如同时为多个特征视图或多个时间区间运行 materialization),这带来两类风险:
- 数据丢失风险:并发写导致后写覆盖先写;
- 写入瓶颈:所有变更必须串行化,注册表写入成为吞吐瓶颈。
这一判断在源码中同样可以找到印证:registry.py 中关于特征视图版本 pin/revert 路径的注释明确写道“file registry is last-write-wins for true concurrent races……For multi-client environments, use the SQL registry”。因此,若团队存在多客户端并发写入需求,应优先考虑 SQL Registry。
二、前置条件
文档给出的硬性要求:
- Hadoop 3.3+已安装;
- 环境变量
HADOOP_HOME已设置。
这两项要求源于底层依赖:实现基于pyarrow.fs.HadoopFileSystem,它通过 JNI 调用宿主机上的 Hadoop 客户端库,因此 Feast 进程所在机器必须能访问到 Hadoop 客户端环境。
三、认证与用户配置(HDFS Registry 的关键差异点)
这是 HDFS registry 与对象存储类 registry(S3/GCS)最大的不同,务必理解:feature_store.yaml中不支持直接指定 HDFS 用户或 Kerberos 凭据。它完全依赖运行 Feast 的进程所能访问的 Hadoop 与系统环境配置。
文档说明,pyarrow.fs.HadoopFileSystem默认继承底层 Hadoop 客户端库的认证,涉及以下环境变量与配置文件:
HADOOP_USER_NAMEKRB5CCNAME(Kerberos 票据缓存)hadoop.security.authenticationcore-site.xml与hdfs-site.xml中的其他相关属性
换句话说,认证策略由进程所在节点的环境决定,而不是由 Feast 配置决定。这在实践上意味着:
- 使用 simple 认证时,写入 HDFS 的文件 owner 通常是
HADOOP_USER_NAME(或当前系统用户),多个服务账号共享同一个注册表文件时需要注意文件权限; - 使用 Kerberos 时,Feast 进程持有的票据(
KRB5CCNAME指向的 ccache)决定了它是否有权限读取/写入注册表路径,票据过期会导致读写失败。
四、配置示例与参数详解
文档给出的标准配置如下:
# feature_store.yaml project: feast_hdfs registry: path: hdfs://[YOUR NAMENODE HOST]:[YOUR NAMENODE PORT]/[PATH TO REGISTRY]/registry.pb cache_ttl_seconds: 60 online_store: null offline_store: null逐项参数说明(结合 RepoConfig 源码):
| 参数 | 说明 |
|---|---|
registry.path | 必须以hdfs://scheme 开头,格式为hdfs://namenode:port/path/to/registry.pb。源码 hdfs_registry_store.py#L29-L36 中通过urlparse解析 URI,scheme 不为hdfs时直接抛ValueError;port 缺省时默认8020(NameNode RPC 端口) |
registry.cache_ttl_seconds | 本地缓存注册表 proto 的 TTL,单位为秒。repo_config.py 中该字段类型为StrictInt,默认值 600;设为 0 表示每次读取都回源 HDFS |
registry.cache_mode | 可选字段,默认"sync";另有"thread"模式表示以cache_ttl_seconds为间隔做后台异步刷新。该字段对 HDFS 后端同样生效,因为缓存逻辑在 Registry.init中与具体 store 解耦 |
registry.registry_store_type | 可选的显式指定 store 类型。留空时 Feast 按path的 scheme 自动选择;registry.py#L79-L85 的映射表将"hdfs"scheme 路由到HDFSRegistryStore,不支持的 scheme 会报出 "Supported schemes are file, s3, gs and hdfs" |
注意 registry.py 中的REGISTRY_STORE_CLASS_FOR_SCHEME映射表:gs、s3、file(含空 scheme 及 Windows 盘符路径)、hdfs四种 scheme 分别路由到对应实现,hdfs即指向feast.infra.registry.contrib.hdfs.hdfs_registry_store.HDFSRegistryStore。因此只要path写对了 scheme,就无需额外指定 store 类型。
五、源码纵深:HDFSRegistryStore 的读写流程
完整实现位于 hdfs_registry_store.py,共约 120 行,是理解“注册表如何落到 HDFS 文件”的最佳入口。
5.1 构造与依赖检查
def __init__(self, registry_config: RegistryConfig, repo_path: Path): try: from pyarrow.fs import HadoopFileSystem except ImportError as e: from feast.errors import FeastExtrasDependencyImportError raise FeastExtrasDependencyImportError( "pyarrow.fs.HadoopFileSystem", str(e) )要点:
- 依赖在构造函数内惰性导入,缺失时抛出
FeastExtrasDependencyImportError,明确提示缺少pyarrow.fs.HadoopFileSystem——这就是第二节前置条件在代码层的落地; - 随后校验 URI scheme 必须为
hdfs,以HadoopFileSystem(hostname, port or 8020)建立连接,路径部分转为PurePosixPath保存。
5.2 读取:get_registry_proto
def get_registry_proto(self): registry_proto = RegistryProto() if _check_hdfs_path_exists(self._hdfs, str(self._path)): with self._hdfs.open_input_file(str(self._path)) as f: registry_proto.ParseFromString(f.read()) return registry_proto raise FileNotFoundError( f'Registry not found at path "{self._uri.geturl()}". Have you run "feast apply"?' )- 先通过
_check_hdfs_path_exists(调用get_file_info判断是否为FileType.NotFound)确认文件存在; - 不存在时抛
FileNotFoundError并提示 “Have you runfeast apply?”——上层 Registry.init会捕获该异常,记录 “Registry file not found. Creating new registry.” 并立即commit()创建新注册表。所以HDFS 上第一次feast apply会自动创建注册表文件,无需手工预置。
5.3 写入:update_registry_proto → _write_registry
def _write_registry(self, registry_proto: RegistryProto): registry_proto.version_id = str(uuid.uuid4()) registry_proto.last_updated.FromDatetime(_utc_now()) dir_path = self._path.parent if not _check_hdfs_path_exists(self._hdfs, str(dir_path)): self._hdfs.create_dir(str(dir_path), recursive=True) with self._hdfs.open_output_stream(str(self._path)) as f: f.write(registry_proto.SerializeToString())三个关键行为值得注意:
- 每次写入都更新
version_id(新的 UUID)与last_updated时间戳,可作为注册表“最近一次变更”的审计线索; - 父目录不存在时自动递归创建(
create_dir(..., recursive=True)),因此path中可以放心写尚未存在的路径层级; - 写入方式是
open_output_stream全量写入序列化后的整个 proto 字节流——这正是文档所述“改一个字段要重写整个文件”的机制根源,也是并发写场景下 last-write-wins 行为的技术成因。
5.4 删除与项目级元数据
teardown():调用delete_file删除注册表文件,对应feast teardown清理流程;set_project_metadata/get_project_metadata:HDFS 后端实现了项目级自定义元数据接口,将 JSON 键值对序列化后存入Registry.project_metadata的project_uuid字段并整体写回。上层 Registry.set_project_metadata 通过hasattr探测 store 是否实现该接口,未实现则抛NotImplementedError——HDFS 后端属于已实现该能力的一档。
六、集成测试证据:如何在 CI 中验证 HDFS Registry
仓库的 test_universal_registry.py 提供了hdfs_registryfixture,展示了端到端验证的完整套路,可直接借鉴到自己的测试环境:
- 使用 Docker 容器
bde2020/hadoop-namenode:2.0.0-hadoop3.2.1-java8与bde2020/hadoop-datanode(Hadoop 3.2.1)组成名为feast-hdfs-cluster的临时集群; - NameNode 等待日志标记为
namenode.NameNode: NameNode RPC up,DataNode 等待successfully registered with NN,超时 120 秒; - DataNode 通过
CORE_CONF_fs_defaultFS=hdfs://namenode:8020指向 NameNode; - 就绪后通过
pyarrow.fs.HadoopFileSystem创建/feast目录,并写入一个空文件作为初始注册表:hdfs://<ip>:<port>/feast/registry.db; - 该 fixture 被参数化进通用注册表测试(
lazy_fixture("hdfs_registry")),与其他后端跑同一套注册表读写断言,说明 HDFS 后端的 API 行为与 file/s3/gcs 等后端保持一致。
需要注意,测试镜像是 Hadoop 3.2.1,而文档建议生产使用Hadoop 3.3+,两者不冲突:CI 验证的是协议行为,生产建议面向客户端兼容性。
七、生产使用建议与局限小结
结合文档与源码,HDFS Registry 的适用画像与注意事项可以归纳为:
- 适用:已运行 Hadoop 集群、希望注册表与离线数据同集群管理、写入方基本串行(如 CI/CD 单一发布通道)的团队;
- 不适用/需谨慎:多客户端并发
apply、并发 materialization 同时触发注册表写入的高并发场景——文件型注册表是 last-write-wins,应改用 SQL registry; - 配置纪律:认证靠进程环境(
HADOOP_USER_NAME、KRB5CCNAME、core-site.xml/hdfs-site.xml),Kerberos 环境下要确保 Feast 进程持有有效票据; - 缓存调优:
cache_ttl_seconds(默认 600 秒)控制多进程间看到彼此变更的延迟窗口,跨节点多实例部署时可配合cache_mode: thread使用,避免长驻进程长期持有过期注册表快照; - 观测:每次写入刷新
version_id与last_updated,可用于排查“注册表到底是谁最后一次写的”。
参考路径
- 文档:docs/reference/registries/hdfs.md、Registry 组件、注册表索引
- 实现:hdfs_registry_store.py、registry.py、repo_config.py
- 测试:test_universal_registry.py
【免费下载链接】feastThe Open Source Feature Store for AI/ML项目地址: https://gitcode.com/GitHub_Trending/fe/feast
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考