Jina 内部通信协议详解:DataRequest 消息模型与 gRPC 服务接口规范
【免费下载链接】jina☁️ Build multimodal AI applications with cloud-native stack项目地址: https://gitcode.com/gh_mirrors/ji/jina
本指南以 docs/proto/docs.md 生成的 Protocol Buffer 文档为主体,结合仓库源码剖析 Jina 在 Gateway、Executor、Deployment 之间传递请求所依赖的消息定义与 RPC 服务。读完本文,你将完整掌握DataRequestProto、HeaderProto、StatusProto、RouteProto等核心消息的字段语义,理解docs/docs_bytes的序列化分流机制,并能对照源码看懂JinaRPC、JinaDataRequestRPC等服务在 jina.proto 与 grpc.py 中的落地实现。
一、协议文档概览:Jina 的通信基石
Jina 是一个以云原生方式构建多模态 AI 应用的框架,Gateway 与 Executor 之间、客户端与 Flow 之间都通过 gRPC 通信,而通信的"语言"就是由 Protobuf 定义的消息结构与服务接口。docs/proto/docs.md 是直接从.proto源文件生成并嵌入文档站的协议参考手册,包含三部分内容:
docarray.proto:声明文档数组(DocumentArray)的载体消息DocumentArrayProto;jina.proto:Jina 自己的请求/响应消息(DataRequestProto等)以及全部 gRPC 服务;- Scalar Value Types:Protobuf 标量类型与各语言类型的映射表。
其中jina.proto是绝对核心,它定义了 Flow 内部"请求在路由上如何被包装、如何携带文档数据、如何记录每个环节的执行状态"。仓库根目录下同时维护了两份同源 proto:docarray_v1/jina.proto 与 docarray_v2/jina.proto,区别仅在与 DocArray 版本兼容性(v1 兼容 DocArray <0.30,v2 兼容 DocArray >=0.30),消息与服务的定义保持一致。
二、核心消息类型逐字段解析
2.1 DataRequestProto:请求的统一载体
DataRequestProto是贯穿 Jina 全链路的最重要消息,客户端发来的文档数组、Executor 执行的参数、路由上的状态信息都被打包进这一个结构:
| 字段 | 类型 | Label | 说明 |
|---|---|---|---|
header | HeaderProto | header 中包含用户请求定义的元信息 | |
parameters | google.protobuf.Struct | 传给 Executor 的额外 kwargs | |
routes | RouteProto | repeated | 每个路由节点上的状态信息 |
data | DataRequestProto.DataContentProto | 承载 docs 与 groundtruths 的容器 |
对应的 proto 源码位于 docarray_v2/jina.proto。在 Python 侧,types/request/data.py 中的DataRequest类为它提供了惰性反序列化包装:只有当首次访问data.docs等成员时才触发 protobuf 解析,同时支持从DataRequestProto、dict、str(JSON)、bytes四种来源构造请求对象,构造失败会抛出BadRequestType。
2.2 HeaderProto:请求元信息与信封机制
HeaderProto描述的是请求的"信封",其生命周期注释清晰地说明了它在 Flow 中的流转规则:
- Header 的内容由用户请求定义;
- 会被拷贝到 envelope.header(信封头);
- Flow 内部操作会修改 envelope.header;
- 返回时再把 envelope.header 拷贝回 request.header。
| 字段 | 类型 | Label | 说明 |
|---|---|---|---|
request_id | string | 请求的唯一 ID,相同 ID 的多个请求会被聚合 | |
status | StatusProto | 状态信息 | |
exec_endpoint | string | optional | 由@requests(on='/abc')指定的端点 |
target_executor | string | optional | 若设置,请求定向到指定 executor,支持正则字符串 |
timeout | uint32 | optional | 以 epoch 秒计的截止时间,超时后请求应被丢弃 |
源码见 docarray_v2/jina.proto。target_executor支持正则匹配,是 Jina 实现"请求定向路由"的底层机制。
2.3 StatusProto 与 ExceptionProto:错误传播
StatusProto用于表示一次执行的状态,内部包含状态码枚举与异常详情:
| 字段 | 类型 | Label | 说明 |
|---|---|---|---|
code | StatusProto.StatusCode | 状态码 | |
description | string | 首个异常的 error 描述 | |
exception | StatusProto.ExceptionProto | 错误详情 |
StatusCode枚举只有两个取值:SUCCESS = 0、ERROR = 1。当发生错误时,ExceptionProto记录完整异常信息:
| 字段 | 类型 | Label | 说明 |
|---|---|---|---|
name | string | 异常类名 | |
args | string | repeated | 传给异常构造函数的参数列表 |
stacks | string | repeated | 异常 traceback 栈 |
executor | string | 绑定该异常的 Executor 名称(如适用) |
在 types/request/init.py 中可以看到这套结构的实际写入逻辑:Request.add_exception()会把异常类名、参数、traceback 栈以及executor.__class__.__name__依次填入header.status,并将code置为ERROR。
2.4 RouteProto:路由链路与耗时度量
RouteProto记录消息在 Gateway 视角下的路由路径,其注释给出了关键的时间语义:
start_time在 Gateway 向 Pod 发送消息时设置;end_time在 Gateway 从 Pod 收到消息时设置;因此end_time - start_time包含了 Executor 计算、运行时开销、序列化与网络耗时。
| 字段 | 类型 | Label | 说明 |
|---|---|---|---|
executor | string | BasePod 的名称 | |
start_time | google.protobuf.Timestamp | Gateway 开始向 Pod 发送的时间 | |
end_time | google.protobuf.Timestamp | Gateway 从 Pod 收到消息的时间 | |
status | StatusProto | 执行状态 |
由于routes在DataRequestProto中是 repeated 字段,一条请求经过多个 Executor 时会累积出完整的路由链路,这也是 Jina 做端到端链路追踪与耗时拆分的原始数据来源。
2.5 EndpointsProto:Executor 能力暴露
EndpointsProto表示 Executor 暴露的一组端点,用于服务发现场景:
| 字段 | 类型 | Label | 说明 |
|---|---|---|---|
endpoints | string | repeated | Executor 暴露的端点列表 |
(在 docarray_v2/jina.proto 中该消息还扩展了write_endpoints与按端点记录的输入/输出schemas字段。)
2.6 其余辅助消息
- JinaInfoProto:携带运行中的系统信息与包版本信息(
jinamap)以及环境变量设置(envsmap),由JinaInfoRPC._status方法返回,用于jina ping等健康/信息探测。 - RelatedEntity:表示一个实体(如 ExecutorRuntime),字段为
id(如 pod 名称)、address(IP 或域名,不含端口)、port、shard_id(可选,所属分片 ID)。 - DataRequestProtoWoData:
DataRequestProto去掉data字段的轻量版本(保留header、parameters、routes),用于不需要携带文档数据的场景。 - DataRequestListProto:请求列表,注释明确说明"应当被流式取代"(
This should be replaced by streaming),requests为 repeated 的DataRequestProto。 - DocumentArrayProto:定义在
docarray.proto中,注释指出它只是"来自 jina._docarray 依赖的占位文件"——真正完整的 DocList/Document 定义由 DocArray 库提供。
三、data 字段的双通道设计:docs 与 docs_bytes
DataRequestProto.DataContentProto使用oneof documents同时声明两个互斥通道:
| 字段 | 类型 | 说明 |
|---|---|---|
docs | docarray.DocumentArrayProto | 请求中的文档数组(结构化 protobuf) |
docs_bytes | bytes | 请求中的文档数组(原始字节) |
这是 Jina 针对大数据量传输做的重要优化:文档以 bytes 形式传递时,接收方无需先反序列化整个 protobuf 再读取文档,而是按需、惰性加载。对应逻辑在 types/request/data.py 中:docs属性在首次访问时才检查WhichOneof('documents'),若为docs_bytes则调用DocumentArray.from_bytes(),否则调用from_protobuf()完成反序列化。
四、gRPC 服务定义与源码落地
jina.proto定义了 7 个核心服务,docs.md 中记录了它们的完整方法签名:
| 服务 | 方法 | 请求类型 | 响应类型 | 说明 |
|---|---|---|---|---|
JinaRPC | Call | DataRequestProto(stream) | DataRequestProto(stream) | 流式服务:传入请求,返回带 matches 的请求 |
JinaDataRequestRPC | process_data | DataRequestListProto | DataRequestProto | 向 Executor 传递请求列表 |
JinaSingleDataRequestRPC | process_single_data | DataRequestProto | DataRequestProto | 无需列表时向 Executor 发送单个请求 |
JinaDiscoverEndpointsRPC | endpoint_discovery | google.protobuf.Empty | EndpointsProto | 暴露 Executor 的端点 |
JinaGatewayDryRunRPC | dry_run | google.protobuf.Empty | StatusProto | Gateway 干跑(连通性验证) |
JinaInfoRPC | _status | google.protobuf.Empty | JinaInfoProto | 暴露运行中的 jina 版本与环境信息 |
服务实现在 serve/runtimes/servers/grpc.py 中有清晰对应:GRPCServer.setup_server()启动grpc.aio.server后,会按 request handler 是否具备相应方法(process_data、dry_run、endpoint_discovery、snapshot等),把对应 Servicer 逐个注册到同一 gRPC 端口,并启用 gRPC reflection 服务。各方法的具体实现分散于:
- Gateway 侧:serve/runtimes/gateway/request_handling.py(
dry_run、_status、endpoint_discovery、stream_doc、process_single_data); - Worker(Executor)侧:serve/runtimes/worker/request_handling.py(
process_data、process_single_data、stream_doc、snapshot、restore等); - Head 侧:serve/runtimes/head/request_handling.py(
process_data、endpoint_discovery、_status)。
docs.md 收录的 7 个服务之外,docarray_v2/jina.proto 还定义了快照/恢复相关的一族服务(JinaExecutorSnapshot、JinaExecutorSnapshotProgress、JinaExecutorRestore、JinaExecutorRestoreProgress及SingleDocumentRequestProto等),这些属于较新的能力扩展。
五、自定义 Serializer:让 gRPC 直接收发 DataRequest
proto/serializer.py 为 gRPC 提供了替代默认序列化器的实现,使线上直接以DataRequest业务对象收发消息。其要点包括:
DataRequestProto.SerializeToString/FromString:未解压时直接取内部 buffer,否则SerializePartialToString;同时通过JINA_GRPC_SEND_BYTES/JINA_GRPC_RECV_BYTES环境变量累积统计收发字节数(供监控指标使用);DataRequestListProto.SerializeToString:既能序列化单个DataRequest,也能序列化请求列表,统一打包成DataRequestListProto,从而对上层隐藏MessageListProto的细节;EndpointsProto、StatusProto、JinaInfoProto等则作为占位类,直接委托内部 protobuf 结构完成序列化与反序列化。
六、标量值类型映射表
docs.md 末尾附带了完整的 Protobuf 标量类型与各语言类型对照表,在做跨语言 gRPC 客户端、或解读协议字段时可直接查阅:
| .proto 类型 | 说明 | C++ | Java | Python | Go | C# | PHP | Ruby | | ----------- | ----- | --- | ---- | ------ | -- | -- | --- | ---- | |double| | double | double | float | float64 | double | float | Float | |float| | float | float | float | float32 | float | float | Float | |int32| 变长编码;负数编码效率低,可能为负时改用sint32| int32 | int | int | int32 | int | integer | Bignum 或 Fixnum | |int64| 变长编码;负数编码效率低,可能为负时改用sint64| int64 | long | int/long | int64 | long | integer/string | Bignum | |uint32| 变长编码 | uint32 | int | int/long | uint32 | uint | integer | Bignum 或 Fixnum | |uint64| 变长编码 | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum 或 Fixnum | |sint32| 变长编码的有符号值,对负数编码比 int32 更高效 | int32 | int | int | int32 | int | integer | Bignum 或 Fixnum | |sint64| 变长编码的有符号值,对负数编码比 int64 更高效 | int64 | long | int/long | int64 | long | integer/string | Bignum | |fixed32| 固定 4 字节;值常大于 2^28 时比 uint32 高效 | uint32 | int | int | uint32 | uint | integer | Bignum 或 Fixnum | |fixed64| 固定 8 字节;值常大于 2^56 时比 uint64 高效 | uint64 | long | int/long | uint64 | ulong | integer/string | Bignum | |sfixed32| 固定 4 字节 | int32 | int | int | int32 | int | integer | Bignum 或 Fixnum | |sfixed64| 固定 8 字节 | int64 | long | int/long | int64 | long | integer/string | Bignum | |bool| | bool | boolean | boolean | bool | bool | boolean | TrueClass/FalseClass | |string| 必须包含 UTF-8 编码或 7-bit ASCII 文本 | string | String | str/unicode | string | string | string | String (UTF-8) | |bytes| 可包含任意字节序列 | string | ByteString | str | []byte | ByteString | string | String (ASCII-8BIT) |
七、更新与重新生成协议
jina.proto与docarray.proto属于"源文件",jina_pb2.py、jina_pb2_grpc.py等由它们生成。仓库通过 Docker 镜像完成代码生成,避免在本地环境安装多版本 protobuf 工具链:
- 构建生成镜像(protobuf 3.21 之前的版本)与 3.21+ 版本分别使用 protogen.Dockerfile 和 protogen-3.21.Dockerfile;
- 更新 DocArray v1 对应代码:
docker run -it -v $(pwd)/jina/proto/docarray_v1:/jina/proto jinaai/protogen:local; - 更新 DocArray >=0.30 对应代码:
docker run -it -v $(pwd)/jina/proto/docarray_v2:/jina/proto jinaai/protogen:local;
完整步骤见 proto/README.md,而 docs/proto/index.md 展示了如何在文档站中用{include} docs.md把生成的协议文档嵌入页面,同时在仓库根目录运行docker run -v $(pwd)/jina/:/jina/ jinaai/protogen即可一键更新jina的 Protobuf 代码。
结语
jina.proto是 Jina 分布式架构的"神经系统":DataRequestProto定义了请求的统一外形,HeaderProto/RouteProto/StatusProto负责元信息、链路追踪与错误传播,docs/docs_bytes双通道解决了大数据量文档的高效传输,而 7 个 gRPC 服务则支撑起客户端到 Gateway、Gateway 到 Executor 的完整调用链。理解这套协议,是深入阅读 Jina 网关、流式与状态管理等源码的起点。
【免费下载链接】jina☁️ Build multimodal AI applications with cloud-native stack项目地址: https://gitcode.com/gh_mirrors/ji/jina
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考