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

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 系统工程师

最新博客

贝壳找房: 为 AI 平台打造混合多云的存储加速底座

2024-06-12
贝壳机器学习平台团队从去年开始对存储系统进行重构,选择了基于 JuiceFS 的存储方案,本文将详细介绍贝壳在此重构过程中的演进历程和具体实践。

JuiceFS POSIX ACL 权限管理上手指南

2024-05-23
本文以 JuiceFS 文件系统的视角介绍了 POSIX ACL 基本用法、与 POSIX 默认权限的区别,以及日常使用中的注意事项。对 getfacl 和 setfacl 这两个常用命令在文件、目…

北美科技企业 Jerry:基于 JuiceFS 构建 ClickHouse 主从架构

2024-05-17
Jerry 创新性地使用 JuiceFS 快照功能实现了 ClickHouse 主从架构。确保了数据的高可用性和稳定性,显著提高了系统的性能和数据恢复能力。