平滑升级功能详解,不停服即可更新

2024-05-07
执剑

以往升级 JuiceFS 版本或修改挂载参数时,用户需要重新挂载文件系统,这会暂时中断业务。作为基础服务的文件系统一旦中断,便会影响系统中其他组件的正常运行。为了避免这类问题,我们在最新发布的 JuiceFS v1.2 版本中引入了平滑升级功能,允许用户在不暂停服务的情况下进行重启或升级。

01 使用

平滑升级的使用非常简单,只需要使用新的二进制或者参数,重新挂载即可。

客户端升级

例如,当前有一个正在运行的挂载进程 juicefs mount redis://127.0.0.1:6379/0 /mnt/jfs -d,用户希望在不卸载挂载点的情况下部署新的 JuiceFS 客户端,可以执行以下步骤:

# 1. 备份当前二进制
cp juicefs juicefs.bak

# 2. 下载新的二进制覆盖当前 juicefs 二进制

# 3. 再次执行 juicefs mount 命令完成平滑升级
juicefs mount redis://127.0.0.1:6379/0 /mnt/jfs -d

动态调整挂载参数

在上述进程中,当用户希望在不卸载挂载点的情况下将日志级别调整为 debug,可以执行以下命令:

# 调整日志级别
juicefs mount redis://127.0.0.1:6379/0 /mnt/jfs --debug -d

02 实现

FUSE 请求处理流程

要达成在不中断读写请求的情况下完成升级,首先需要理解用户读写请求的整个流程。

FUSE 请求处理流程
FUSE 请求处理流程

如上图所示,当用户使用 juicefs mount xxxxx /jfsopen /jfs/a.txt JuiceFS 和操作系统的主要行为如下:

  1. juicefs mount 后,JuiceFS 内部的 go-fuse 模块会 open /dev/fuse 获取 mount fd
  2. 用户发起 open 系统调用,系统调用进入 VFS 层,VFS 层将请求转入 FUSE 层
  3. FUSE 层根据协议将 open 请求按照格式写入 mount fd
  4. go-fuse 模块读取 mount fd 并在解析请求后调用 JuiceFS 对应实现
  5. go-fuse 将本次请求的处理结果按照格式写入 mount fd
  6. 内核态的 FUSE 模块读取 mount fd 得到本次请求的处理结果

通过以上示例流程可以发现 /dev/fuse 设备文件就是 JuiceFS 用户态文件系统与内核的沟通桥梁,两者通过 juicefs mountgo-fuse 模块 open /dev/fuse 设备文件得到的文件句柄 mount fd 进行沟通。内核写入请求,JuiceFS 借助 go-fuse 处理并返回请求,所以两者的关系可以简单的看做客户端-服务器协议,其中内核作为客户端请求服务,用户态的 JuiceFS 扮演着服务器端的角色,处理这些请求。

核心:如何在进程间传递文件句柄 mount fd

通过分析 FUSE 请求处理流程,不难发现如果能确保内核请求在过程中不发生丢失或错误,就能顺利完成 JuiceFS 的平滑升级,即使请求被延迟处理也是可以接受的。这里的关键就是维持首次挂载所获取到的文件句柄 mount fd 的一致性。新进程必须继承并使用旧进程的 mount fd ,因为这样对于内核来说一切都没变,所以业务对这个过程无感知。这里需要注意的是 FUSE 设备每次被 open 都会分配新的 session。新的 session 无法访问到之前旧 session open 的资源,所以要做到平滑升级,我们必须保持旧的 mount fd

在介绍如何实现 mount fd 的一致性具体操作之前,首先需要了解从 v1.2 开始,JuiceFS 由一个进程拆分为两个进程——守护(daemon)和服务进程(service)。当服务进程异常退出时,守护进程会重新启动服务进程,这个过程中,只读请求不会受到影响,写的请求会失败。平滑升级时新旧守护进程,守护进程与服务进程之间,我们都采用 Unix domain socket 传递文件句柄。

JuiceFS 平滑升级:mount fd 和状态信息传递示意
JuiceFS 平滑升级:mount fd 和状态信息传递示意

上图展示了平滑升级过程中 mount fd 和状态信息如何传递的流程。具体的操作步骤,从 1 到 7,在图中相应地标记着。

  1. 首次 mount 时旧服务进程通过 open /dev/fuse 设备拿到 mount fd
  2. 旧服务进程传递 mount fd 给旧守护进程
  3. 新守护进程从旧守护进程中获取 mount fd
  4. 新守护进程发送 SIGHUP 信号给旧服务进程,旧服务进程此时会停止接收新的 FUSE 请求,并且 flush 已经写入的数据到对象存储。如果某些请求在 3 秒内没有完成则会中断这些请求。
  5. 旧服务进程收到 SIGHUP 信号后在 /tmp 目录下生成中间状态文件。
  6. 新服务进程加载中间状态文件
  7. 新服务进程从新守护进程获取 mount fd

升级过程中,JuiceFS 会将内存中新写入的数据全部持久化到对象存储,并且将打开的文件句柄保存到磁盘上,新的进程启动后会恢复这些打开的文件,保证后续的 FUSE 操作没有问题。当某个 FUSE 请求未能在升级期间完成,他会被强制中断,可能会对业务产生影响,建议在负载比较低的时候进行升级操作。

经过上面一系列流程后新 JuiceFS 服务进程就已经获取到了旧 JuiceFS 使用的 monut fd,新服务进程处理从 mount fd 中读取到的请求即可。如下图流程所示:

启用平滑升级功能后,FUSE 请求处理流程
启用平滑升级功能后,FUSE 请求处理流程

03 注意事项

  1. 目前 v1.2-beta1 平滑升级仅支持 linux 平台,v1.2 正式发布时将同时支持 MacOS 平台。
  2. 平滑升级要求新旧进程的 JuiceFS 客户端版本都至少为 v1.2 版本。
  3. 新的挂载参数中的 FUSE 参数应该与旧的挂载参数保持一致,否则平滑升级会在当前挂载点上继续覆盖挂载。
  4. 升级过程中,未能 3 秒内完成的 FUSE 请求可能会被中断,某些业务如果不能自动重试中断的文件系统操作可能会受影响。

欢迎大家下载试用:https://github.com/juicedata/juicefs/releases/tag/v1.2.0-beta1

Author

执剑
Juicedata 系统工程师

最新博客

JuiceFS v1.3-Beta2:集成 Apache Ranger,实现更精细化的权限控制

2025-06-06
本文将介绍 JuiceFS 社区版如何与 Apache Ranger 进行集成,并探讨其权限管理的实现方式。该功能由多点 DMALL 数据平台团队李铭贡献,特此感谢她对社区的贡献!

JuiceFS 企业版 5.2:迈入千亿文件时代,稳定性与性能再升级,首次支持 Windows 客户端

2025-05-28
JuiceFS 企业版 5.2 版本近日发布,文件管理规模迈入千亿级。此次升级重点提升了超大规模集群的稳定性,优化了分布式缓存的网络性能,并增强了系统的易用性与安全性,旨在支持高并发访问等复杂的高性…

JuiceFS v1.3-Beta1:一亿文件备份分钟级完成,性能优化全解析

2025-05-21
在最新发布的 JuiceFS v1.3 Beta1 版本中,我们引入了一种全新的二进制备份机制,相比现有的 JSON 备份方式,该机制在导入导出元数据时不仅大幅提升了处理速度,还显著降低了内存占用。

中国科学院计算所:从 NFS 到 JuiceFS,大模型训推平台存储演进之路

2025-05-14
JuiceFS 在中科院计算所的实践,解决了模型训练场景中的数据读写瓶颈、元数据访问延迟以及计算资源之间的存储互通问题。