NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

JuiceFS 在携程海量冷数据场景下的实践

妙成/小峰

  • 2022-08-31
    北京
  • 本文字数:4659 字

    阅读完需:约 15 分钟

JuiceFS 在携程海量冷数据场景下的实践

一、摘要


携程的冷数据规模在 10PB+,包括备份数据、图片语音训练数据和日志数据等,存储方案主要是本地磁盘和 GlusterFS。在实际使用中这些方案遇到了不少痛点:


  • GlusterFS 在单目录下文件众多时,ls 命令速度很慢;

  •  受疫情期间机器采购周期的制约,无法灵活地根据实际需求弹性扩缩容,存储成本控制困难;

  • 磁盘损坏等故障带来的机器替换和扩缩容操作,使得运维成本居高不下。


随着云计算技术的发展,公有云厂商为混合云客户提供了海量冷数据的廉价存储方案,经过严谨的成本计算,我们发现使用公有云的对象存储可以显著降低存储和运维成本。为了减少迁移成本,我们一直在寻找后端存储能支持各类公有云对象存储、高性能的文件系统,直到 JuiceFS 出现在我们的视野中。JuiceFS 有以下优势:


  • POSIX 接口,对应用无侵入

  • 强一致性,文件修改立刻可见,为同一个 volume 被多台机器挂载的场景提供 了 close-to-open 保证

  • 支持了主流的公有云对象存储,支持开源软件作为元数据引擎(Redis、TiKV)等

  • 支持云原生,能够将 volume 以 CSI 的方式挂载到 Pod 上

  • 社区活跃,代码更新快


经过大半年的测试和使用,我们已经对接了数据库备份和 ElasticSearch 冷数据存储,将 2PB+的数据迁移到了 JuiceFS,预计后续还会有 10PB+的数据接入。目前 JuiceFS 系统稳定,在降低运维成本和存储成本方面取得了良好的效果。本文将对 JuiceFS 原理以及我们在使用中所遇到的问题和采取的优化方案进行简单介绍。


二、JuiceFS 架构与 POC 测试


2.1 架构简介


JuiceFS 将元数据信息和真实数据块分开管理,通过 FUSE 实现 POSIX 接口,允许用户像本地文件系统一样使用。用户将文件写入 JuiceFS 挂载的目录后,文件数据会存储到对象存储,相应的元数据(文件名、文件大小、权限组、创建修改时间和目录结构等)会存到元数据引擎中。在该架构下,ls、数据删除等操作只是对元数据引擎的操作,不受到对象存储的速度限制,性能上会有较好的保证。



2.2 元数据引擎选型与测试


JuiceFS 的元数据引擎有很多选择,包括开源的 Redis、TiKV 以及官方提供的闭源的企业版元数据引擎。考虑到携程的数据规模较大并且后续会有更多的数据接入,元数据引擎需要能够支持 TB 级元数据的存储并且能横向扩容。因此 TiKV 和官方的企业版元数据引擎成了我们的备选方案。


为了验证 TiKV 的性能,我们使用 go-ycsb 做了一些性能测试。

 

机器

CPU

Memory

Storage

Network

Node1

2 Socket / 20 Core / 40 Thread

128G

1.9T SSD

bond0 25G

Node2

2 Socket / 20 Core / 40 Thread

128G

960G SSD

bond0 25G

Node3

2 Socket / 20 Core / 40 Thread

128G

1.2T SSD

bond0 25G


测试结果:


1)Write 事务写入操作,随着客户端线程数增加,TPS 上升,峰值超过 30000



2)Get 事务读取操作, 随着客户端线程数增加,QPS 上升,单节点峰值接近 70000


从测试结果看,TiKV 有较高的读写吞吐量,并且单次操作的响应时间 P99<10ms,在冷数据场景中性能表现可满足业务需求。


官方的企业版元数据引擎比 TiKV 有更好的性能表现,但是考虑到冷数据存储对性能要求并不苛刻,而且相比于对象存储 20~200ms 的访问速度,元数据引擎并不会明显降低整个系统响应的速度。为了减少技术黑箱,我们选择了 TiKV 作为元数据引擎。


2.3 JuiceFS 整体 POC 测试


在交付生产之前,为了明确 SLA 指标和最佳使用场景,我们使用 mdtest 对以 TiKV 为元数据引擎的 JuiceFS 进行了整体 POC 测试,部署使用如下架构:



1)单线程写入,测试文件大小与吞吐量的关系


测试结果表明随着文件大小增大,吞吐量也随之增大。在单文件为 128MB~256MB 左右时,原先的吞吐量与文件大小的增长曲线明显放缓。可以理解为当文件较小时,JuiceFS 客户端与元数据引擎和对象存储的交互成本与有效数据传输成本相比,占比较高,限制了吞吐量;当文件较大时,交互成本占比降低,吞吐量上升。为了发挥充分 JuiceFS 的吞吐能力,建议存储 128MB 以上的文件。


2)目录深度与 JuiceFS IOPS 的关系



测试结果表明目录深度与 JuiceFS IOPS 没有明显关系。研究 JuiceFS 代码可知,虽然深度越深,文件路径变长,但 JuiceFS 在创建文件/目录时在 TiKV 里的 Key 是父目录 inode + 新条目的名字,所以目录深度不影响 TiKV 里的键值对大小,就不影响 TiKV 的查询性能,符合测试结果。


3)目录大小与 ls 速度的关系


单目录下文件个数

ls耗时(ms)

1025

25

24269

31


测试结果表明目录下文件个数对 ls 几乎没有影响。


2.4 元数据引擎故障测试


理论上 TiKV 节点中 Region 通过 Raft 保证一致性,即非 Leader Region 故障完全不影响上层应用,Leader Region 故障则会在该 Region 的副本中重新选举出一个 Leader Region,选举需要时间,并且需要上报 PD 节点进行处理,因此会影响到上层应用的部分请求。


PD 集群用来管理 TiKV 集群,PD 的非 Leader 节点故障完全不影响上层应用,Leader 节点故障则需要重新选举新 PD Leader,选举过程 JuiceFS 客户端的请求无法得到响应,新 Leader 节点确立后 JuiceFS 重新建立连接也需要一定耗时,该时间段内会对上层应用的请求产生影响。


据此我们模拟节点故障的场景,测试实际应用过程中元数据引擎故障后恢复所需时间,计算正常场景中读写一定数量文件与异常情况下的耗时差异。结果表明故障影响时间可以控制在秒级。


1)TiKV 故障


File size/count

正常

异常

Diffms

单线程写 4MiB/1024

237035.52

249333.76

12298.24

单线程读 4MiB/1024

360222.72

362577.92

2355.2


2)PD 故障


File size/count

正常

异常

Diffms

单线程写4MiB/1024

237035.52

247531.52

10496

单线程读 4MiB/1024

362332.16

362577.92

245.76


三、JuiceFS 原理解析


3.1 文件写入


JuiceFS 接收到写请求会先将数据写入 Buffer,并按照 Chunk、Slice、Block 的规则进行数据块管理,最后以 Slice 为维度 Flush 到对象存储。一次 Flush 实质上是对 Slice 中的每个 Block 进行 PUT 操作,将数据写到对象存储,并完成元数据修改。如下图:



1)大文件先经过 FUSE 处理成 128K 的块,在 JuiceFS 内部拼成一个个 4M 大小的 Block,Slice 管理的 Block 不断增加,直到 Slice 达到 64M(即一个 Chunk 的大小),触发一次 flush 操作。Chunk、Slice、Block 的拼装使用的是内存 buffer,其大小受 JuiceFS 启动参数 buffer-size 的限制。                                                                              

2)小文件由新的 Slice 单独管理,在文件写入完成时被上传到对象存储。


3)如果客户端设置 writeback 模式,JuiceFS 不会直接写数据到 Object Storage,而是写到 JuiceFS 所在机器的本地磁盘,后续异步写到对象存储。这种方式存在丢数据的风险,但是可以提升数据写入速度。


3.2 文件读取


读取流程数据处理方式与写入流程类似,读取请求被 JuiceFS 进程接收到后会先访问元数据引擎,找到需要读取的 Block,向对象存储并发发出 GET 请求。由于 Block 数据不变性,读取出的 4M 的 Block 会写到本地的缓存目录中。读取过程中按照 4M(Block) 的方式实现了一定程度的预读,可以通过调整 prefetch 参数,将预读窗口设置的更大,默认 prefetch = 1。如下图:



1)大文件顺序读场景下,会读取对象存储中 4M 大小的对象,经过 FUSE 处理成 128K 的块返回给用户。此场景中缓存命中率会很高,由于预读和本地 Block 缓存,吞吐性能较好。                            


2)大文件随机读场景下流程和顺序读一致,该场景下的预读、缓存被命中的概率很低,这些逻辑反而可能影响读取性能(需要将读取到的数据写入本地缓存目录),可以通过设置 cache-size = 0 关闭缓存。


3)小文件(例如 4K)读取场景下,会读取当前文件的 Block,经过 FUSE 后响应给用户程序。获取到的数据也会写到本地缓存目录中。


四、故障处理与性能优化


4.1 TiKV CPU 使用率过高,导致拒绝服务


现象:TiKV kv_scan 请求数突然上升,unified_read_po 线程池 CPU 使用率被打满


分析:客户端运行 cleanTrash 任务导致的。Beta 1 版本的客户端会同时进行该任务,当同一个 volume 挂载的客户端较多,并且 trash 中的数据量非常多的时候,该任务会对元数据引擎造成突发的压力。


解决方案:


1)增加客户端对元数据引擎各个接口的调用量监控,便于快速诊断是哪些客户端导致的问题;


2)将后台任务从客户端中剥离,客户端只需要执行用户的请求,cleanTrash 这样的后台任务交给单独的组件执行,便于 JuiceFS 管理员控制;


3)升级客户端,Beta3 开始增加了分布式锁,并且增加了 no-bgjob 启动参数。


4.2 TiKV 数据泄露


现象:文件数目和 OSS 中的数据量没有增加的情况下,region 数目不断增加,store size 不断增加


分析:通过 tikv-ctl 查看 TiKV 里的数据,发现 MVCC 的修改和删除记录没有被清除。完整的 TiDB 部署会 10min 触发一次数据 GC。但是单独部署 TiKV,数据 GC 需要由其他程序触发。另一方面 5.0.1 版本的 TiKV 有 bug,数据 GC 没有清理删除记录,相关issue


解决方案:


1)参考

https://github.com/tikv/client-go/blob/v2.0.0/examples/gcworker/gcworker.go

单独实现一个组件,定期调用 GC 功能


2)升级 TiKV 到 5.0.6


4.3 CSI 挂载场景中,PV 清理后数据 OSS 中数据无法回收

现象:k8s 中的 ElasticSearch 所有 Pod、PVC、PV 下线一天后 OSS 数据仍没被清理。


分析:PV 被清理时 CSI 执行了 JuiceFS rmr 指令,将 volume 数据全部放到回收站,根据默认配置 trash-day=1,即一天后开始回收数据。由于环境中的 JuiceFS mount Pod 已经全部下线,即没有 JuiceFS 进程挂载了 CSI 的 volume,于是出现了没有清理回收站的情况。


解决方案:由于 CSI 模式使用 JuiceFS 是模拟了 subdir 的过程,即整个 CSI 管理 Pod 挂载的 volume 是同一个,通过写到子目录的方式进行数据隔离。我们停止了 mount pod 的所有后台任务,另外找了一台机器挂载该 volume 来完成自动清理回收站数据等后台任务,该方法也消除了后台任务带来的客户端性能抖动。


4.4 客户端使用内存过高


现象:部分使用 JuiceFS 的机器占用内存过高,达到了 20GB+。


分析:


1)通过 cat /proc/$pid/smaps 查看,发现占用的内存都是 Private_Dirty,说明是被 JuiceFS 进程长期持有,不是 Page Cache 缓存占用导致。


2)通过使用 pprof 工具分析 heap 占用情况,可推测出是 dump meta(backup)导致的异常。



解决方案:将客户端的启动参数 backup-meta 默认值改为 0,元数据备份参考官方的实现思路通过另外的组件统一实现,客户端不执行元数据备份任务。


4.5 优化后架构


生产实践过程中涉及数 PB 级的数据,业务场景相差巨大,经过规划与调优,最终演进成如下架构。



1)量级较小的业务由用户挂载的 JuiceFS client 治理 session、trash 等数据。                                                  

2)量级较大的业务(PB 级、数百 client 级)挂载的 client 不处理 session、trash 等数据的清理(开启 no-bgjob 参数),由 admin 提供一个 client 单独处理,并提供清理加速的能力。


3)提供了一个 client 统一做同一 tikv 集群内所有 volume 的 backup-meta 操作。


4)提供访问 OSS 和 TIKV 集群的限流能力,通过命令下发修改 client 的限流能力,用于在必要情况下保护专线带宽、元数据库,实现服务降级。


5)使用多套元数据集群用来隔离行为差异较大的业务。


6)提供服务触发 TiKV 的 GC。


五、总结与展望


通过 JuiceFS 将冷数据上公有云, Elasticsearch 实现了一定程度的存算分离,去除了副本带来的内存需求,提升整体集群数据存储能力。DBA 备份数据从 GlusterFS 迁移到 JuiceFS 后 ls 等行为的性能大幅提高,不仅运维人员不再需要投入精力进行磁盘扩容维修,大大降低了运维成本,而且用户还能够按照保留时间快速地控制存储成本。


目前已有 2PB 来自 ElasticSearch、DBA 备份的数据存储到 JuiceFS,后续我们会推动更多的数据上 JuiceFS,当然后续也很多需要进一步探索和优化的地方,例如:


1)进一步优化元数据引擎 TiKV 的性能与提升 JuiceFS 的稳定性,以应对 10PB+的数据量。


2)探索 JuiceFS 在 ClickHouse 冷数据存储上的使用方法。


3)公有云场景下使用 JuiceFS 替换 HDFS,以降低云上的存储成本。


作者简介:

妙成,携程云原生研发工程师,主要从事 Elasticsearch、JuiceFS 的研发运维,关注分布式数据库、NoSQL。小峰, 携程云原生研发工程师,主要专注于数据库容器化领域,对分布式存储有浓厚兴趣。

2022-08-31 16:474068

评论

发布
暂无评论
发现更多内容

PoseiSwap 参赛,参与斯坦福、Nautilus等联合主办的 Hackathon 活动

西柚子

线程是如何通讯的?

Java你猿哥

Java 线程 多线程 ssm 通讯

公司来了一个腾讯做优化的大佬,三下五除二让我程序快了200%

做梦都在改BUG

Java 性能优化 JVM 性能调优

美团T9大牛总结的神仙微服务架构设计模式PDF

做梦都在改BUG

Java 架构 微服务

一张图感受真实的 TCP 状态转移

九零后程序员

TCP 网络 Linux Kenel ebpf

聊聊技术变现这件事

老张

斜杠青年 技术变现 技术咨询

Go 语言 map 如何顺序读取?

AlwaysBeta

Go 面试 map

Github星标88.8k,阿里新产的Spring Cloud进阶小册!面面俱到

Java你猿哥

Java 架构 微服务 微服务架构 Spring Cloud

火爆Github的1000道Java面试题:无死角打击所有Java面试问题,按这个学,找工作完全没问题!

架构师之道

Java 编程

这个线上BUG,让你彻底搞懂了MySQL的字符集,别问我咋知道的

Java你猿哥

Java MySQL ssm 字符串 字符集

面试官:SpringBoot可以同时处理多少请求?

做梦都在改BUG

Java spring Spring Boot 框架

关于斐波那契数列的笔记

贝湖光

Go 语言 map 是并发安全的吗?

AlwaysBeta

Go 面试 map

不止缓存!Redis这16种妙用你可能没见识过……

Java你猿哥

redis 缓存 分布式 消息队列 全局唯一ID

Nautilus Chain上线主网,为DeFi和流支付的未来构建基础

BlockChain先知

线程的生命周期和常用方法

Java你猿哥

源码 jdk 线程 多线程 Monitor

WritingGPT: 基于ChatGPT和AutoGPT打造个人写作团队

俞凡

人工智能

MySQL 正确使用带有横线“-”SQL语句

Andy

Vue3 修改项目名称及相关信息

Andy

AIGC背后的技术分析 | 机器学习背后的微分入门

TiAmo

机器学习 AIGC

RoCE多网卡时,报文可以过去,但是回不来

华为云开发者联盟

后端 开发 华为云 华为云开发者联盟 企业号 5 月 PK 榜

神册!出自阿里P8的深入理解Java虚拟机最新版,让我涨薪60%

Java你猿哥

Java JVM 虚拟机 并发 代码优化

世界顶级级架构师编写2580页DDD领域驱动设计笔记,属实有牌面

Java你猿哥

Java 领域驱动设计 DDD crud 领域驱动

PoseiSwap  参赛,参与斯坦福、Nautilus等联合主办的 Hackathon 活动

鳄鱼视界

mac端摄影师青睐软件:ON1 Photo RAW 2023.5 中文激活版

真大的脸盆

Mac Mac 软件 图像编辑 编辑图像 照片编辑

SpringBoot 整合 MyBatis 组合 Redis 作为数据源缓存

Java你猿哥

Java redis Spring Boot mybatis ssm

京东首席系统架构师教你如何搭建高可用高并发系统架构

做梦都在改BUG

Java 高可用 系统架构 高并发

腾讯T8架构师基于SpringBoot2.x搭建分布式架构

做梦都在改BUG

Java spring Spring Boot 框架

设计模式之订阅发布模式

越长大越悲伤

设计模式 发布订阅模式 spring boot3 订阅发布

解决缓存与数据库数据不一致的问题,这篇文章告诉你如何做!

做梦都在改BUG

Java 数据库 缓存 一致性

首页推荐!阿里大佬带你一周刷完Java面试题1700页,offer拿到手软

做梦都在改BUG

Java java面试 Java八股文 Java面试题 Java面试八股文

JuiceFS 在携程海量冷数据场景下的实践_服务革新_InfoQ精选文章