Skip to main content

分布式缓存的 IORPC 协议

从 JuiceFS 企业版 5.2 开始,IORPC 为缓存组节点间数据传输提供了一套 RPC 框架。TCP Pool 是默认通信模式,适用于绝大多数场景。IORPC 仅在连接数过多导致性能衰退时考虑使用,其连接多路复用可以降低 goroutine 调度带来的 CPU 开销。IORPC 默认关闭,启用前请联系 Juicedata 技术支持评估可行性。

IORPC 与 TCP Pool 对比

JuiceFS 分布式缓存系统支持两种节点间数据传输的网络通信模式:

特性IORPCTCP Pool
多路复用一个连接可并发处理多个请求每个连接同一时刻只能处理一个请求
I/O 路径(默认)Direct I/O 读盘 + write 发送(两次用户态拷贝)sendfile(内核内零拷贝)
连接数高并发下所需连接数较少高并发下需要维护大量连接
传输方式TCP(默认)或 RDMA仅 TCP
缓存读取模式dio(默认)、pagecachesplicesendfile(默认)或 dio(需配合 --cache-try-dio
适用场景连接过多导致性能衰退时绝大多数场景

TCP Pool 是早期版本一直使用的传统模式,也是所有版本的默认模式。默认使用 sendfile 实现缓存盘到网络的零拷贝传输。

IORPC 支持多路复用,单个连接可以并发处理多个请求,显著减少高并发场景下的连接数量。此外,IORPC 还可以配合 RDMA 传输,获得更高的吞吐和更低的 CPU 占用。

启用 IORPC

IORPC 分为服务端客户端两个独立的部分。只有当两部分同时开启时,系统才会使用 IORPC 模式进行数据传输。

服务端

IORPC 服务端运行在缓存组成员节点上(即使用 --no-sharing 的挂载点)。从 5.2 版本开始,服务端默认开启

如需关闭某个节点的 IORPC 服务端,使用 --iorpc-mode=disable

客户端

IORPC 客户端默认关闭。如需在任意 JuiceFS 客户端(包括 --no-sharing 节点)上启用,使用 --use-iorpc

IORPC 与 RDMA 的关系

指定 --rdma-network 后,IORPC 会在服务端和客户端自动启用并以 RDMA 方式传输数据,无需单独设置 --use-iorpc。详见分布式缓存 RDMA 加速

IORPC 缓存读取模式

--iorpc-mode 参数控制 IORPC 服务端从磁盘读取缓存数据的方式。该设置仅对缓存组成员节点生效。

模式说明
dio(默认)Direct I/O,绕过内核 page cache,减少内存拷贝和系统内存占用。
pagecacheBuffer 读,经过内核 page cache,使用标准文件系统读路径。
splice零拷贝模式,利用内核管道(splice/vmsplice)在磁盘和网络之间直接传输数据,无需用户态拷贝。要求系统管道最大值 ≥ 8 MiB。RDMA 启用时自动回退为 dio
disable禁用本节点的 IORPC 服务端,缓存请求改由 TCP Pool 处理。

配置 splice 模式

使用 splice 模式时,设置 --iorpc-mode=splice

启用 splice 前,需将系统管道最大值调至 8 MiB 以上:

echo 8388608 > /proc/sys/fs/pipe-max-size

查看当前管道最大值:

sysctl fs.pipe-max-size

如果管道大小不足 8 MiB 或已启用 RDMA,服务端会自动回退为 dio 模式并在日志中输出警告。

连接管理

IORPC 会根据带宽和 QPS 自动调整连接数,增加连接每秒评估一次,减少连接每分钟评估一次。TCP 连接在带宽超过 300 MiB/s 或 QPS 超过 1000 时增加,在带宽和 QPS 同时分别低于 100 MiB/s 和 500 时减少。RDMA 连接的增长和减少阈值更高(增加阈值为 1 GiB/s 或 5000 QPS,减少阈值为 512 MiB/s 且 2000 QPS)。连接数始终至少保留一个。

验证 IORPC 是否生效

服务端

查看缓存组成员节点的 JuiceFS 客户端日志,日志行会显示当前 IORPC 模式和 TCP Pool 模式:

max pipe size: 8388608, iorpc: dio, tcp pool: sendfile

其中 iorpc 字段的可能值:

  • dio:Direct I/O(默认)
  • pagecache:Buffer 读
  • splice:零拷贝模式
  • disable:IORPC 服务端未启用

tcp pool 字段的可能值:

  • sendfile:默认零拷贝方式
  • dio:已启用 Direct I/O(通过 --cache-try-dio

客户端

当客户端与缓存服务端成功建立 IORPC 通信后,客户端日志中会显示:

iorpc client started, server address X.X.X.X:X

其中 X.X.X.X:X 为已连接的缓存服务端 IP 地址和端口号。

监控

关键日志

日志来源说明
max pipe size: ..., iorpc: dio, tcp pool: sendfile服务端启动显示当前 IORPC 模式和 TCP Pool 读盘方式。各字段值详见服务端验证
iorpc client started, server X.X.X.X:X客户端IORPC 连接成功建立。
get iorpc address from ... failed: rpc disabled客户端对端不支持 IORPC(旧版本),回退到 TCP Pool。
splice iorpc is disabled since max pipe size is ... or RDMA is enabled, use dio instead服务端splice 条件不满足,自动回退为 dio
iorpc-mode should be one of ..., but got ..., set to dio服务端配置了无效的 --iorpc-mode 值,回退为默认 dio

Prometheus 指标

以下为 IORPC 核心指标,前缀为 mount_。各延迟指标同时提供 _tp50 / _tp90 / _tp99 分位数及 _max

指标说明
mount_iorpc_processRespDur服务端处理 IORPC 请求的耗时(从收到请求到响应序列化)。
mount_iorpc_writeBodyDur将响应体写入网络连接的耗时。排查网络拥塞时可关注此指标。
mount_iorpc_decodeBodyDur解码请求/响应体的耗时。
mount_iorpc_inflight当前正在被服务端并发处理的 IORPC 请求数。达到默认并发上限 2048 后,新请求会排队等待,直到有空闲 slot 释放,可能导致延迟上升和客户端超时。若该指标持续接近 2048,需考虑扩容缓存组。

juicefs stats 实时输出

使用 juicefs stats 配合 r 字符和 -l 1 可实时查看 IORPC 内部各阶段耗时:

juicefs stats --schema=ufmcro -l 1 /jfs

remotecache 区域中,会额外显示三列:

  • db_c / lat:解码请求/响应体的操作次数和平均延迟。
  • pr_c / lat:服务端处理 RPC 请求的操作次数和平均延迟。
  • wb_c / lat:将响应体写入网络的操作次数和平均延迟。

不使用 -l 1 时,r 仅显示业务层 remotecache 指标。这些 IORPC 列在 -l 1 下始终显示,但仅在 IORPC 启用时才有实际数值。

调优建议

什么时候使用 IORPC

备注

启用 IORPC 前请联系 Juicedata 技术支持评估可行性。

当连接数过多导致性能衰退时,可考虑启用 IORPC。典型判断依据包括:

  • 缓存服务端进程 goroutine 数量达数千级(用 cat /jfs/.stats | grep goroutines 查看),但 juicefs stats 显示的 remotecache 吞吐并未随并发增加同步增长,表明 TCP Pool 每个连接一个 goroutine 的模型消耗了 CPU 却未能提升吞吐
  • juicefs stats 显示 CPU 占用高,但 remotecache 吞吐远低于网卡额定带宽,表明 CPU 被 goroutine 调度而非有效数据传输所消耗
  • 客户端到缓存组节点存在大量 TCP 连接(用 ss -tan | wc -l 查看,该命令统计 ESTABLISHEDTIME_WAIT 连接总量,TIME_WAIT 数量高直接反映连接频繁创建和关闭,是 TCP Pool 的典型特征),配合上述 CPU 或吞吐异常,可进一步确认瓶颈来自 TCP Pool 的连接模型

IORPC 通过多路复用解决该问题:单个连接通过消息 ID 匹配同时承载多个并发请求,一个 goroutine 即可服务多个请求,连接数从成千上万降至数十个,goroutine 随之大幅减少,Go 调度器因大量 goroutine 上下文切换产生的开销大幅减少。CPU 从连接管理中释放出来,回归缓存盘 I/O 和网络数据传输。

如果启用 IORPC 后仍无法充分利用带宽,可以进一步尝试 splice 模式。

什么时候使用 Direct I/O(dio)

默认的 dio 模式适用于大多数场景。尤其当使用 top 观察到 kswapd 进程占用较多 CPU 时,说明内存碎片化导致 page cache 分配缓慢,此时 Direct I/O 绕开内核 page cache 可避免该问题。但 Direct I/O 性能受磁盘性能限制。

什么时候使用 splice

如果 dio 模式下吞吐仍不理想,可以切换为 splice 模式,通过内核管道实现零拷贝传输。该模式希望在最大化吞吐的同时降低 CPU 开销,在内核版本低于 5.12(缺少 TCP 协议栈优化)的环境中收益尤为明显。

启用 splice 前请务必调高管道最大值至 8 MiB 以上。

IORPC 与 RDMA 的关系

使用 RDMA 加速 时,--iorpc-mode 仍然控制服务端的磁盘读取方式。不过 splice 模式在 RDMA 启用时会自动回退为 dio。RDMA 如何自动启用 IORPC 详见上文的说明,完整配置指南见分布式缓存 RDMA 加速