第1章:Geaflow-Infer 模块简介
章节导读
本文将从宏观的角度出发,系统地介绍这个模块的定位 、应用场景 、核心功能 和组织结构。通过本章的学习,你将对 geaflow-infer 模块有一个全面的认识,为后续深入学习各个细节模块打下坚实的基础。
架构设计图
graph TB
subgraph "用户层"
A["InferContext
统一调用入口"] end subgraph "环境管理层" B["InferEnvironmentManager
环境初始化管理"] C["InferDependencyManager
依赖文件管理"] D["InferEnvironmentContext
环境上下文"] end subgraph "任务运行层" E["InferTaskRunImpl
Python进程管理"] F["ProcessLoggerManager
日志管理"] G["InferTaskStatus
状态管理"] end subgraph "数据交换层" H["InferDataBridgeImpl
数据桥接"] I["InferDataWriter
数据写入"] J["InferDataReader
数据读取"] K["DataExchangeQueue
共享内存队列"] end subgraph "序列化层" L["Pickler
序列化器"] M["Unpickler
反序列化器"] N["IEncoder/IDecoder
编解码接口"] end subgraph "Python进程" O["infer_server.py
推理服务"] P["用户自定义
Transform类"] end A --> B A --> H A --> E B --> C B --> D E --> F E --> G E --> O H --> I H --> J H --> N I --> K J --> K N --> L N --> M K --> O O --> P style A fill:#e1f5ff style B fill:#fff4e1 style E fill:#ffe1e1 style H fill:#e1ffe1 style L fill:#f0e1ff style O fill:#ffe1f0
统一调用入口"] end subgraph "环境管理层" B["InferEnvironmentManager
环境初始化管理"] C["InferDependencyManager
依赖文件管理"] D["InferEnvironmentContext
环境上下文"] end subgraph "任务运行层" E["InferTaskRunImpl
Python进程管理"] F["ProcessLoggerManager
日志管理"] G["InferTaskStatus
状态管理"] end subgraph "数据交换层" H["InferDataBridgeImpl
数据桥接"] I["InferDataWriter
数据写入"] J["InferDataReader
数据读取"] K["DataExchangeQueue
共享内存队列"] end subgraph "序列化层" L["Pickler
序列化器"] M["Unpickler
反序列化器"] N["IEncoder/IDecoder
编解码接口"] end subgraph "Python进程" O["infer_server.py
推理服务"] P["用户自定义
Transform类"] end A --> B A --> H A --> E B --> C B --> D E --> F E --> G E --> O H --> I H --> J H --> N I --> K J --> K N --> L N --> M K --> O O --> P style A fill:#e1f5ff style B fill:#fff4e1 style E fill:#ffe1e1 style H fill:#e1ffe1 style L fill:#f0e1ff style O fill:#ffe1f0
核心功能时序图
1. 环境初始化时序图
sequenceDiagram
participant User as 用户代码
participant IC as InferContext
participant IEM as InferEnvironmentManager
participant IDM as InferDependencyManager
participant Shell as Shell脚本
User->>IC: new InferContext(config)
IC->>IEM: buildInferEnvironmentManager()
IEM->>IEM: createEnvironment()
Note over IEM: 使用文件锁确保单次初始化
IEM->>IEM: 检查 _finish 或 _failed 文件
alt 已初始化
IEM-->>IC: 返回环境上下文
else 需要初始化
IEM->>IDM: new InferDependencyManager()
IDM->>IDM: 复制运行时文件
IDM->>IDM: 准备 requirements.txt
IDM-->>IEM: 返回脚本路径
IEM->>Shell: 执行 install-infer-env.sh
Shell->>Shell: 创建虚拟环境
Shell->>Shell: 安装依赖包
Shell-->>IEM: 安装完成
IEM->>IEM: 创建 _finish 文件
IEM-->>IC: 返回环境上下文
end
IC->>IC: 初始化完成
2. 推理调用时序图
sequenceDiagram
participant User as 用户代码
participant IC as InferContext
participant ITR as InferTaskRunImpl
participant IDB as InferDataBridgeImpl
participant IDW as InferDataWriter
participant SMQ as 共享内存队列
participant IDR as InferDataReader
participant Python as Python进程
User->>IC: infer(features...)
IC->>ITR: 启动Python进程
ITR->>Python: 启动 infer_server.py
Python->>Python: 加载用户Transform类
Python->>SMQ: 连接共享内存
Python-->>ITR: 进程就绪
IC->>IDB: write(features)
IDB->>IDW: 序列化数据
IDW->>SMQ: 写入数据到发送队列
Note over Python: Python进程读取数据
Python->>SMQ: 从接收队列读取
Python->>Python: 反序列化数据
Python->>Python: 执行推理
Python->>SMQ: 写入结果到发送队列
IC->>IDB: read()
IDB->>IDR: 从接收队列读取
IDR->>SMQ: 读取数据
IDR-->>IDB: 返回字节数组
IDB->>IDB: 反序列化结果
IDB-->>IC: 返回结果对象
IC-->>User: 返回推理结果
3. 共享内存数据交换时序图
sequenceDiagram
participant Java as Java进程
participant Encoder as Pickler编码器
participant Writer as InferDataWriter
participant Queue as DataExchangeQueue
participant Reader as InferDataReader
participant Decoder as Unpickler解码器
participant Python as Python进程
Note over Java,Python: 数据写入流程
Java->>Encoder: encode(object)
Encoder->>Encoder: 序列化为Pickle格式
Encoder-->>Java: byte[]
Java->>Writer: write(bytes)
Writer->>Writer: 添加4字节长度头
Writer->>Queue: 写入共享内存
Queue->>Queue: 更新写指针
Note over Java,Python: 数据读取流程
Python->>Queue: 检查可读数据
Queue-->>Python: 数据可用
Python->>Reader: read()
Reader->>Queue: 从共享内存读取
Reader->>Reader: 读取4字节长度头
Reader->>Queue: 读取数据体
Queue->>Queue: 更新读指针
Reader-->>Python: byte[]
Python->>Decoder: decode(bytes)
Decoder->>Decoder: 反序列化Pickle数据
Decoder-->>Python: Python对象
4. 进程生命周期管理时序图
sequenceDiagram
participant IC as InferContext
participant ITR as InferTaskRunImpl
participant PB as ProcessBuilder
participant Python as Python进程
participant PLM as ProcessLoggerManager
IC->>ITR: run(commands)
ITR->>PB: 构建进程
Note over PB: 配置环境变量
PATH, LD_LIBRARY_PATH, PYTHONPATH PB->>Python: 启动进程 Python-->>ITR: 进程对象 ITR->>PLM: startLogging() PLM->>PLM: 启动输出监听线程 PLM->>PLM: 启动错误监听线程 ITR->>ITR: waitFor(timeout) alt 超时退出 ITR->>ITR: 标记状态为FAILED ITR->>Python: destroyForcibly() else 正常运行 ITR->>ITR: 标记状态为RUNNING end Note over IC,Python: 推理执行中... IC->>ITR: stop() ITR->>Python: destroyForcibly() Python-->>ITR: 进程终止 ITR->>PLM: 停止日志收集
PATH, LD_LIBRARY_PATH, PYTHONPATH PB->>Python: 启动进程 Python-->>ITR: 进程对象 ITR->>PLM: startLogging() PLM->>PLM: 启动输出监听线程 PLM->>PLM: 启动错误监听线程 ITR->>ITR: waitFor(timeout) alt 超时退出 ITR->>ITR: 标记状态为FAILED ITR->>Python: destroyForcibly() else 正常运行 ITR->>ITR: 标记状态为RUNNING end Note over IC,Python: 推理执行中... IC->>ITR: stop() ITR->>Python: destroyForcibly() Python-->>ITR: 进程终止 ITR->>PLM: 停止日志收集
1.1 模块定位与应用场景
总体定位
GeaFlow-Infer 是 Apache GeaFlow 分布式图计算引擎中专门用于 ML 推理加速 的模块。它解决的核心问题是:如何在高性能分布式图计算的过程中,高效地集成机器学习模型进行实时推理。
从架构的角度看,geaflow-infer 充当了 Java 图计算引擎 与 Python ML 生态 之间的"桥梁",使得用户可以:
- 在 GeaFlow 的分布式图计算框架中,使用 Python 的强大 ML 库(TensorFlow、PyTorch、Sklearn 等)
- 以最小的性能开销进行模型推理
- 实现图计算与 ML 推理的无缝融合
应用场景
场景 1:知识图谱中的实体链接(Entity Linking)
arduino
用户查询: "苹果公司的CEO是谁?"
↓
[图计算] 在知识图谱中查找"苹果"相关实体
↓
[推理层] 使用 NLP 模型区分"苹果"(公司)vs "苹果"(水果)
↓
[返回结果] 准确的实体链接结果
为什么需要 geaflow-infer?
- 知识图谱本身数据庞大(可能包含数十亿个实体),单纯的图遍历可能返回多个候选实体
- 需要使用深度学习模型来计算相似度,判断最佳匹配
- geaflow-infer 可以在图计算的过程中,批量对候选实体进行 embedding 计算和相似度比对
场景 2:社交网络中的推荐系统
less
用户A的图邻域:
- 粉丝列表(万级别)
- 兴趣标签关系(百万级别)
↓
[图计算] 基于 PageRank 算法计算影响力
↓
[推理层] 使用协同过滤 + 深度学习模型评分
↓
[返回结果] Top-K 个性化推荐列表
为什么需要 geaflow-infer?
- 推荐需要通过复杂的图遍历(多跳关系)获取上下文信息
- 之后基于上下文用 ML 模型进行评分
- 高并发场景下,频繁调用 Python 推理服务成为性能瓶颈
- geaflow-infer 提供进程级别的隔离和共享内存加速,避免频繁的网络调用
场景 3:金融风险控制中的反欺诈
css
交易事件:用户A向用户B转账 ¥100,000
↓
[图计算] 追踪关联的转账链路、识别异常子图
↓
[推理层] 使用 GNN 模型计算风险分数
↓
[决策层] 风险判定:是否冻结账户
为什么需要 geaflow-infer?
- 反欺诈需要实时处理(毫秒级延迟要求)
- 需要获取完整的关联关系图(多层次的交易网络)
- Python GNN 模型提供更强的特征学习能力
- geaflow-infer 通过共享内存和无锁队列,实现零拷贝数据交换,显著降低延迟
核心价值主张
| 维度 | 传统方案 | GeaFlow-Infer |
|---|---|---|
| 性能 | Python RPC 调用:毫秒级延迟 | 共享内存 + 无锁队列:微秒级延迟 |
| 吞吐 | 单机单进程:有限 | 多进程隔离:充分利用多核 |
| 易用 | 需要维护 Web Service | 内嵌在 GeaFlow 中,无需额外基础设施 |
| 可靠 | 网络超时、进程崩溃风险 | 本地进程管理、自动恢复机制 |
1.2 核心功能概述
从功能的角度,geaflow-infer 主要包含以下几个核心模块:
总体功能架构
scss
┌─────────────────────────────────────────────────────────────┐
│ 用户应用层 (User App) │
│ InferContext API │
└───────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 环境管理层 (Environment Management) │
│ ┌──────────────────┐ ┌──────────────────────────────┐ │
│ │InferEnvironment │ │InferDependencyManager │ │
│ │Manager │ │ • 依赖文件管理 │ │
│ │ • Singleton │ │ • Shell脚本执行 │ │
│ │ • 虚拟环境初始化 │ │ • Conda环境配置 │ │
│ │ • 文件锁机制 │ └──────────────────────────────┘ │
│ └──────────────────┘ │
└───────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 任务运行层 (Task Execution) │
│ ┌──────────────────┐ ┌──────────────────────────────┐ │
│ │InferTaskRunImpl │ │ProcessLoggerManager │ │
│ │ • 进程启动 │ │ • Stdout/Stderr 捕获 │ │
│ │ • 环境变量配置 │ │ • Slf4j 集成 │ │
│ │ • 超时控制 │ └──────────────────────────────┘ │
│ └──────────────────┘ │
└───────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 数据交换层 (Data Exchange) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ InferDataBridgeImpl │ │
│ │ ┌────────────────┐ ┌────────────────┐ │ │
│ │ │ DataWriter │ │ DataReader │ │ │
│ │ │ • 编码 │ │ • 解码 │ │ │
│ │ │ • 写入内存 │ │ • 读取内存 │ │ │
│ │ └────────────────┘ └────────────────┘ │ │
│ │ ↓ ↑ │ │
│ │ ┌─────────────────────────┐ │ │
│ │ │ DataExchangeQueue │ │ │
│ │ │ (共享内存队列) │ │ │
│ │ │ • 无锁算法 │ │ │
│ │ │ • 内存映射 │ │ │
│ │ │ • 指针管理 │ │ │
│ │ └─────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 序列化层 (Serialization) │
│ ┌──────────────────┐ ┌──────────────────────────────┐ │
│ │Pickler │ │Unpickler │ │
│ │ • Java→Pickle │ │ • Pickle→Python │ │
│ │ • OpCode生成 │ │ • 对象构造 │ │
│ │ • 递归深度控制 │ │ • 类型映射 │ │
│ └──────────────────┘ └──────────────────────────────┘ │
└───────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Python进程 (Python Process) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ infer_server.py │ │
│ │ • 监听共享内存队列 │ │
│ │ • 反序列化输入数据 │ │
│ │ • 执行用户定义的 Transform 类 │ │
│ │ • 序列化输出结果 │ │
│ └──────────────────────────────────────────────────────┘ │
└───────────────────────────────────────────────────────────────┘
功能概览
1. 环境管理层(Environment Management)
目的:为 Python 推理进程创建独立、隔离的运行环境
核心组件:
InferEnvironmentManager:单例模式,负责虚拟环境的初始化。使用文件锁机制确保多进程场景下的初始化只执行一次InferDependencyManager:负责从 JAR 包中提取运行时文件,执行 Shell 脚本创建 Conda 虚拟环境
关键特性:
- 🔒 文件锁机制:防止多个 Java 进程同时初始化同一个虚拟环境
- 🔄 状态标记文件 :通过
_finish和_failed文件记录初始化状态 - 📦 依赖隔离:每个 GeaFlow 实例拥有独立的 Conda 虚拟环境,避免依赖冲突
2. 任务运行层(Task Execution)
目的:启动、管理和监控 Python 推理进程的生命周期
核心组件:
InferTaskRunImpl:通过ProcessBuilder启动 Python 子进程,配置必要的环境变量(PATH、LD_LIBRARY_PATH、PYTHONPATH)ProcessLoggerManager:监听进程的标准输出和错误输出,并通过 Slf4j 框架集成到 GeaFlow 的日志系统
关键特性:
- ⏱️ 超时控制:支持配置进程运行的最大时间,超时自动杀死进程
- 📝 日志捕获:完整捕获 Python 进程的输出,便于调试
- 🛡️ 错误恢复:进程异常退出时,自动标记状态并提示用户
3. 数据交换层(Data Exchange)
目的:在 Java 和 Python 进程之间高效地传输数据
核心组件:
DataExchangeQueue:基于 mmap(内存映射)的共享内存队列,实现了无锁算法InferDataWriter:将 Java 对象序列化后写入共享内存InferDataReader:从共享内存读取字节流,交给解序列化器处理
关键特性:
- 零拷贝:利用内存映射,避免数据在进程间的复制
- 无锁设计 :使用
sun.misc.Unsafe和内存屏障,实现高性能并发访问 - 字节序处理:统一使用 Little Endian,避免字节序转换的开销
4. 序列化层(Serialization)
目的:实现 Java 对象与 Python 对象之间的双向转换
核心组件:
Pickler:Java 实现的 Pickle 序列化器,生成 Python Pickle 格式的字节流Unpickler:解析 Pickle 格式的字节流,构建 Java 对象
关键特性:
- Pickle 协议:完整实现 Python Pickle Protocol v2,兼容 Python 3
- 跨语言映射:处理 Java 的基本类型、集合类型、自定义类型到 Python 的映射
- 自定义扩展:支持用户注册自定义的序列化器和反序列化器
1.3 模块依赖关系分析
直接依赖
xml
<dependencies>
<!-- geaflow-common 提供基础工具类 -->
<dependency>
<groupId>org.apache.geaflow</groupId>
<artifactId>geaflow-common</artifactId>
</dependency>
<!-- guava 提供 Joiner、Preconditions 等工具 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<!-- 阿里云 OSS 依赖(用于文件上传下载) -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
</dependency>
<!-- JCTools 提供高性能的并发数据结构 -->
<dependency>
<groupId>org.jctools</groupId>
<artifactId>jctools-core</artifactId>
</dependency>
<!-- geaflow-file-common 提供文件操作工具 -->
<dependency>
<groupId>org.apache.geaflow</groupId>
<artifactId>geaflow-file-common</artifactId>
</dependency>
</dependencies>
依赖关系图
markdown
┌─────────────────────────────────────────────┐
│ geaflow-infer 模块 │
└──────────────┬──────────────────────────────┘
│
┌───────┼───────┬───────────┬──────────┐
↓ ↓ ↓ ↓ ↓
┌────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│com.│ │google│ │alibaba│ │jctools│ │geaflow│
│aliyun│ │guava│ │oss │ │ │ │file │
│oss │ │ │ │ │ │ │ │common │
└────┘ └──────┘ └──────┘ └──────┘ └──────┘
│ │ │ │ │
└───────┼───────┴───────────┴──────────┘
│
┌───────↓────────────────┐
│ geaflow-common │
│ (基础工具类库) │
└────────────────────────┘
核心依赖说明
| 依赖库 | 用途 | 关键类 |
|---|---|---|
| geaflow-common | 异常、日志、配置管理 | GeaflowRuntimeException, Configuration |
| guava | 集合操作、字符串处理 | Joiner, Lists, Preconditions |
| jctools-core | 高性能无锁队列基础 | 作为参考实现 |
| geaflow-file-common | 文件操作工具 | 文件锁、文件复制、JAR 资源提取 |
| aliyun-sdk-oss | 云存储集成 | 支持大规模依赖文件的云存储 |
1.4 目录结构解析
源码目录树
bash
geaflow/geaflow-infer/
├── src/main/java/org/apache/geaflow/infer/
│ ├── InferContext.java # 门面类,用户主入口
│ ├── InferEnvironmentManager.java # 环境管理器(单例)
│ ├── InferDependencyManager.java # 依赖管理器
│ ├── InferEnvironmentContext.java # 环境上下文
│ ├── InferTaskRun.java # 任务运行接口
│ ├── InferTaskRunImpl.java # 任务运行实现
│ ├── InferTaskStatus.java # 任务状态枚举
│ │
│ ├── exchange/ # 数据交换模块
│ │ ├── DataExchangeQueue.java # 共享内存队列
│ │ ├── DataExchangeContext.java # 数据交换上下文
│ │ ├── InferDataWriter.java # 数据写入器
│ │ ├── InferDataReader.java # 数据读取器
│ │ ├── DataQueueInputStream.java # 队列输入流
│ │ ├── DataQueueOutputStream.java # 队列输出流
│ │ ├── IDataBridge.java # 数据桥接接口
│ │ │
│ │ ├── impl/
│ │ │ └── InferDataBridgeImpl.java # 数据桥接实现
│ │ │
│ │ └── serialize/ # 序列化模块
│ │ ├── Pickler.java # Pickle 序列化器
│ │ ├── Unpickler.java # Pickle 反序列化器
│ │ ├── UnpickleStack.java # 反序列化栈
│ │ ├── Opcodes.java # Pickle OpCode 定义
│ │ ├── IObjectPickler.java # 对象序列化接口
│ │ ├── IObjectConstructor.java # 对象构造接口
│ │ ├── IEncoder.java # 编码器接口
│ │ ├── IDecoder.java # 解码器接口
│ │ │
│ │ ├── impl/
│ │ │ ├── DataExchangeEnCoderImpl.java # 编码实现
│ │ │ ├── DataExchangeDeCoderImpl.java # 解码实现
│ │ │ ├── ComplexNumberConstructor.java # 复数构造器
│ │ │ ├── ArrayConstructor.java # 数组构造器
│ │ │ └── ByteArrayConstructor.java # 字节数组构造器
│ │ │
│ │ └── util/
│ │ ├── BinaryUtils.java # 二进制处理工具
│ │ ├── PickleUtils.java # Pickle 工具类
│ │ └── UnpickleUtils.java # 反Pickle 工具类
│ │
│ ├── log/ # 日志模块
│ │ ├── ProcessLoggerManager.java # 进程日志管理器
│ │ └── Slf4JProcessOutputConsumer.java # Slf4j 日志消费者
│ │
│ └── util/ # 工具模块
│ ├── InferFileUtils.java # 文件操作工具
│ └── PortableJvmInfo.java # JVM 信息工具
│
└── src/test/java/org/apache/geaflow/infer/ # 测试代码
├── InferContextTest.java # 完整流程测试
├── DataExchangeTest.java # 数据交换测试
└── SerializationTest.java # 序列化测试
模块分层说明
javascript
┌──────────────────────────────────────────────────┐
│ 用户 API 层 │
│ InferContext │
└──────────────────────────────────────────────────┘
▲ ▲
│ │
│ 控制流 │ 数据流
│ │
┌────────┴────────────────────┴──────────────────┐
│ 环 境 / 任 务 管 理 层 │
│ InferEnv* / InferTask* / Log │
└─────────────┬──────────────────────────────────┘
│
┌─────────────┴──────────────────────────────────┐
│ 数 据 交 换 & 序 列 化 层 │
│ DataExchange* / Pickle* │
└──────────────────────────────────────────────────┘
▼
Python 进程
(infer_server.py)