跳到主要内容

Curvine 压测:3 亿文件仅占 38G 内存,开源项目天花板

· 阅读需 5 分钟

在分布式文件系统领域,元数据的内存效率、并发处理能力、小文件吞吐性能,一直是衡量产品核心能力的关键指标。近期,Curvine 完成了一组高规格元数据压测,结果显示:Curvine 的元数据内存效率达到了开源项目中的顶尖水平,核心能力可与商业版分布式存储产品相当。

🔥 开篇结论

  • 内存高效利用:在 80 万目录3 亿文件、每个文件写入一个 block 的条件下,Curvine 仅占用 38G 内存,与参考材料 [1] 中 JuiceFS 商业版的元数据能力大致相当。
  • 高并发低延迟:在 10 万客户端 循环操作的压力下,QPS 稳定在 5.3 万每秒,命令操作平均时延低于 2msP99 时延低于 9ms
  • 小文件高吞吐:高并发写入大量小文件时,Curvine 可实现每小时写入 1200 万小文件,平均写入一个小文件仅需 0.3ms

📝 测试条件

  • Curvine 集群:一台 Master,一台 Worker
  • 测试机型:阿里云 ecs.i5.8xlarge,32 核,256G 内存
  • 客户端:10 万个 FUSE 客户端
  • 操作:客户端循环执行 mkdirtouch、写文件、ls 等高频命令

📊 核心压测数据

🧠 内存效率:开源第一梯队

  • 管理规模:80 万目录 + 3 亿文件
  • 单文件写入:1 个 block
  • 内存占用:仅 38G
  • 对标结论:与 JuiceFS 商业版的元数据内存能力相当

内存效率压测

⏱️ 高并发低延迟:10 万客户端快跑稳跑

  • 并发客户端:10 万 FUSE 客户端
  • 稳定吞吐:5.3 万次/秒
  • 平均时延:不超过 2ms
  • P99 时延:不超过 9ms

高并发 QPS

高并发时延

连接开销同样很低:10 万连接仅消耗 1.1G 内存,平均每个连接约 11.5KB

连接开销

压测停止后,Master 内存会立刻从 39.1G 回落到 38G

压测停止后的 Master 内存

🚀 小文件高吞吐:海量场景无压力

  • 每小时写入:1200 万小文件
  • 单文件平均写入时延:0.3ms
  • 高并发下吞吐持续打满

15:00 时,Curvine 已写入 2.87 亿文件

15 点文件总量

16:00 时,文件总量达到 2.99 亿

16 点文件总量

🏗️ 元数据架构

Curvine 的元数据能力不仅在大规模内存效率和高并发性能上表现突出,与其他开源产品相比也具备明显优势。其背后是一套经过精心设计的元数据架构。

Curvine 元数据架构概览

💡 设计理念

  1. 单 Master 支撑大规模文件与海量小文件。
  2. 以高并发、低延迟应对频繁的创建、删除、修改等高频元数据操作。
  3. 尽量减少对外部组件的依赖,降低运维复杂度,同时保证系统稳定性。

基于这些目标,Curvine 选择了 内存目录树 + 单机 RocksDB + Raft 一致性机制 的三层组合,在性能、规模和稳定性之间取得平衡。

层次核心职责设计动机
内存目录树存储目录结构信息,包括目录名、父子关系,并处理路径解析、目录列举等高频操作将高频命名空间操作放在内存中,把目录查询和路径匹配延迟控制在微秒级;只维护轻量目录结构,最大化可支撑规模
元数据 RocksDB(inode 引擎)持久化文件和目录的完整元数据,包括文件大小、权限、mtime、block 位置以及完整目录关系通过列族机制拆分不同类型的元数据,提升读写效率,并更好地适配频繁的元数据更新
Raft 日志 RocksDB持久化所有元数据修改日志,包括创建、删除、更新等操作,并按顺序用于多节点同步将日志存储与元数据存储完全隔离,避免互相干扰,同时便于同步、压缩、清理和故障恢复

🛡️ FsMode:与 UFS 协同,保障数据兜底安全

Curvine 支持 FsMode,会将元数据和文件数据同步到底层统一文件系统(UFS),形成本地存储 + 磁盘兜底的双重保障,在不影响系统性能的前提下避免数据丢失。

🚀 未来演进方向

Curvine 的元数据能力还会继续向前推进,重点包括三个方向:

  1. 单机百亿:继续深挖单机能力,让普通 512G 内存 机器也能支撑 百亿级文件元数据
  2. 联邦 Federation:增强元数据集群扩展性,采用类似 HDFS Federation 的模式,通过目录拆分支撑 千亿级以上 的规模。该模式对 mvls 等集中式元数据操作尤其友好,但需要在初始化时规划目录结构。
  3. 插件式元数据管理:抽象元数据接口,支持插件化元数据后端,进一步提升灵活性和适配能力。

📚 参考材料

  1. https://mp.weixin.qq.com/s/zbBUQ4P53PPWQjOHQmw8uw
  2. https://hadoop.apache.org/docs/r3.4.0/hadoop-project-dist/hadoop-hdfs-rbf/HDFS%20RouterFederation.html

👇 关注我们

我们会持续分享分布式存储、元数据优化和高并发压测等实战内容。

GitHub:https://github.com/CurvineIO/curvine

Curvine:下一代统一数据接入层,兼顾 Posix 和高速缓存

· 阅读需 8 分钟

在分布式缓存的实践过程中,我们发现用户面临着 POSIX 语义支持不足、资源消耗高、运维复杂等核心痛点。为了更好地解决这些问题,我们对 Curvine 的模式和发展路线进行了全新调整,打造这一兼具强 POSIX 语义与高性能缓存的下一代统一数据接入层,让远程数据访问体验迎来质的提升。

两种核心挂载模式,适配多样业务需求

Curvine 将数据读写模式优化为简洁的 CacheModeFsMode 两种挂载点读写模式,分别对应不同的业务场景诉求,兼顾缓存加速与完整语义支持,让用户可以根据实际需求灵活选择。

CacheMode:轻量读缓存加速,与 UFS 强绑定

CacheMode 以 UFS(底层文件系统)为核心,主要承担 UFS 的读缓存加速和统一代理角色。读写操作均以 UFS 为基准:

  • 元数据缓存可有效加速 ls 等常用操作
  • 写数据时直接写入 UFS
  • 用户能对 UFS 形成强感知,无需改变原有数据操作习惯

这是轻量提升 UFS 读取性能的优选方案。

FsMode:全量性能加速,强 POSIX 语义加持

FsMode 则以 Curvine 自身为核心,元数据由 Curvine 独立管理,其路径与 UFS 实现一一映射,UFS 仅作为 Curvine 的冷存层。该模式提供:

  • 全方位的读写缓存加速
  • 更好地支持 POSIX 语义读写
  • 完美适配大规模文件的性能加速需求
  • 是对语义完整性和性能均有高要求场景的最佳选择

FsMode 深度解析:分层设计,兼顾性能与一致性

作为 Curvine 的核心模式,FsMode 采用分层文件系统的挂载写入设计,通过清晰的语义定义和流程规划,实现了性能、语义与数据一致性的平衡。下面为大家拆解其核心设计细节。

核心语义规则

  1. 统一 IO 入口:所有数据读写操作均通过 Curvine 完成,应用仅使用 Curvine 路径,不建议直接访问 UFS,否则将无法保障数据一致性。

  2. 异步写入冷存:写数据时先落地 Curvine(包含元数据 + 块),由 Master 侧根据策略在后台定期提交 Load/Dump 任务,将数据异步刷新到 UFS(如 S3),让前端写入操作更高效。

  3. 智能读取回填:读数据时优先从 Curvine 读取;若数据已被淘汰或仅存在于 UFS,则通过 Load 操作将 UFS 数据回填至 Curvine,本次读取则直接透读 UFS,兼顾读取速度与数据可用性。

  4. 灵活副本形态:允许仅 UFS 存在数据的状态,此时 UFS 中的数据将作为该文件的唯一数据副本,最大化利用存储资源。

  5. 按需元数据同步:mount 操作时会同步目录下所有元数据,后期不再主动做全量同步;若需同步,可通过 mount resync 命令手动更新挂载点元数据(仅同步仅在 UFS 存在的文件元数据)。

  6. 缓存懒加载机制:若读取的文件在 Curvine 无元数据但在 UFS 存在,首次读取会失败,重试时将主动获取 UFS 文件;也可提前手动触发 mount resync 命令同步元数据,避免读取失败。

  7. 故障容错设计:master 故障时,用户可通过 UFS 接口正常访问数据;worker 故障时,多副本场景可访问其他副本,单副本场景则直读 UFS,保障业务连续性。

一致性设计:当下可用,未来更优

目前 FsMode 的一致性实现方案为:

  • UFS 路径首次挂载到 Curvine 时,会将该目录下的元数据整体映射至 Curvine
  • 若绕开 Curvine 直接向 UFS 写入文件,Curvine 无法自动感知
  • 可通过同步命令手动重新同步

未来规划:Curvine 将实现自动感知 UFS 的元数据变化 event 消息,准实时同步 UFS 元数据,从技术层面彻底保障数据一致性,让用户无需关注同步操作,实现无感使用。

FsMode 核心设计目标

FsMode 的所有设计均围绕明确的目标展开,确保每一项能力都能精准解决业务痛点:

  • 统一入口:所有操作通过 Curvine 路径进行,应用无需适配 UFS,降低开发和运维成本。
  • POSIX 语义:支持完整的 POSIX 文件系统语义,包含目录树、随机读写、重命名、原子性、强一致性等,适配各类传统及新型应用。
  • 分层存储:Curvine 层存储热数据(元数据 + 可选本地块),UFS 作为持久/冷副本,实现热冷数据分离,提升存储效率和访问性能。
  • 后台刷新:Master 根据业务操作与预设策略,定期提交 Load/Dump 任务,将 Curvine 数据异步刷新到 UFS,不影响前端业务。
  • 仅 UFS 副本:支持数据仅存在于 UFS(如 S3)的场景,读数据时按需回填或透读,兼顾存储灵活性与数据访问性。

CacheMode vs FsMode:一张表看懂核心差异

为了让大家更清晰地分辨两种模式的区别,精准匹配业务场景,我们整理了核心对比维度,一目了然:

对比项CacheModeFsMode
语义支持仅支持 UFS 本身语义支持完整 POSIX 语义(目录树、随机读写、重命名、原子性、强一致性等)
写入方式数据直接写 UFS,应用与 UFS 强耦合数据写 Curvine,由 JM 异步刷新到 UFS,应用仅面向 Curvine
元数据管理元数据缓存,但是与 UFS 保持强一致性元数据由 Curvine Master 维护,定期同步到 UFS,冲突以 Curvine 为准;其他接口修改 UFS 不会被 Curvine 主动感知
读取逻辑缓存存在则从 Curvine 读;无缓存则提交异步任务加载到 Curvine,本次直接从 UFS 读取优先从 Curvine 读;Curvine 无数据时由 Master 标记热数据并回填 Curvine,本次直接从 UFS 读取
数据过期处理删除 Curvine 中元数据和数据块仅删 Curvine 数据块,保留元数据
一致性保障受 UFS 约束(如 S3 最终一致性)Curvine 侧强一致;与 UFS 间通过异步任务实现最终一致

极致资源优化,轻量运行更友好

除了功能和性能的打磨,Curvine 在资源消耗上也做了深度优化,从底层技术栈到实现手段进行全方位升级:

Curvine 基于 Rust 语言构建,天生具备高性能、低资源消耗的特性;同时采用 异步零拷贝 等前沿优化手段,进一步降低资源占用。

线上实践数据显示:Curvine 的单 worker 进程占用内存资源不足 1G。在大规模集群部署时,能有效减少服务器资源投入,降低运维成本,即使是资源紧张的场景也能轻松适配。

产品哲学:不做替代,只做更好的数访方式

Curvine 从一开始就有着清晰的产品定位:

不追求成为通用 POSIX 文件系统,也不试图替代任何存储产品。

我们始终专注于一件事:在不改变用户原有数据操作习惯的前提下,让远程数据访问快到感觉不到"远程"。这不仅是技术层面的挑战,更是 Curvine 的核心产品哲学——最好的基础设施,就是让人感觉不到它的存在。

在 AI 时代,数据量呈爆炸式增长,远程数据访问的性能和体验成为影响业务效率的关键因素。Curvine 融合了分布式缓存技术智慧与分布式文件系统的 POSIX 完整性,同时坚守"元数据透明、文件结构不变"的核心原则,无需用户对现有业务系统做大幅改造,即可实现远程数据访问性能的跃升。

未来,Curvine 将持续深耕统一数据接入层领域,不断优化性能、稳定性、完善语义支持、简化运维流程,致力于成为 AI 时代数据基础设施的关键一环,为各类业务的数字化升级提供高效、稳定、轻量的数据访问支撑。

最后,希望更多的存储、Rust 领域的开源爱好者共同加入,共建共享!


Powered by OPPO Bigdata.

分布式缓存之殇:理想与现实

· 阅读需 6 分钟

在经历了半年的开源之旅,调研了多个用户,我们对分布式缓存这个模式的利弊有了清晰的认识。针对分布式缓存的应用场景局限性,这里做一个简单的反思。

在大数据与人工智能蓬勃发展的今天,"存算分离"已成为云原生数据架构的主流范式。计算资源可以弹性伸缩,而数据则统一沉淀于低成本的对象存储(如 S3、OSS)中。然而,这一架构带来了一个致命痛点:对象存储的高延迟与低吞吐,严重拖累计算性能。于是,分布式缓存层应运而生——它被寄予厚望,要成为连接"灵活计算"与"廉价存储"的高速桥梁。

分布式文件缓存系统,能"透明加速"对远程存储的访问,并提供统一命名空间。然而,当企业满怀期待将其引入生产环境后,却常常陷入性能未达预期、运维复杂、语义不符的困境。本文将深入剖析分布式缓存的技术理想与其落地现实之间的鸿沟,揭示分布式缓存在通用场景下的结构性局限。

一、分布式缓存的理想:统一、透明、高性能

设计初衷极具吸引力:

  • 统一命名空间:将 HDFS、S3、GCS 等异构存储挂载到单一目录树下,应用只需访问 xx://
  • 透明缓存:首次读取远程数据后自动缓存至内存/SSD,后续访问毫秒级响应;
  • 生态兼容:无缝集成 Spark、Presto、Pytorch 等主流计算引擎,无需修改代码;
  • 分层存储:支持内存 → SSD → HDD 的多级缓存,平衡性能与成本。

在演示环境中,分布式缓存确实能大幅提升对象存储的访问性能,尤其是在模型训练反复读取输入的场景下。

二、现实之殇:三大结构性缺陷

然而,理想丰满,现实骨感。分布式缓存在真实业务场景中暴露出三大难以回避的缺陷。

殇之一:POSIX 语义残缺,通用性受限

分布式缓存通过 FUSE 提供类 POSIX 接口,使传统应用可像访问本地文件一样读取远程数据。但其对 POSIX 语义的支持是高度残缺的:

  • 不支持随机写:无法在文件中间修改字节,仅允许创建新文件或全量覆盖;
  • 不支持 truncate、硬链接、文件锁
  • ⚠️ 强一致性缺失:多客户端可能读到过期缓存,需手动刷新元数据。

这意味着,分布式缓存根本无法运行数据库、日志系统或任何需要原地更新的程序。它本质上是一个为 WORM(Write-Once-Read-Many),而非通用文件系统。许多团队在尝试将现有业务"无缝迁移"到分布式缓存后,才发现应用因写操作失败而崩溃。

真相:分布式缓存不是"分布式 POSIX 文件系统",而是"面向批处理优化的数据编排层"。

殇之二:资源占用高

目前使用 Java 或者 Go 语言的分布式缓存系统,普遍存在资源占用比较高的问题。

例如 Java 进程动辄占用几十 G 的内存,对于使用内存作为缓存的系统来讲,属实有点浪费资源。

殇之三:运维复杂,ROI 难以兑现

分布式缓存的部署涉及 Master、Worker、Journal、UFS 连接器等多个组件,资源调优(内存分配、缓存策略、网络配置)极其复杂。更致命的是:

  • 缓存命中率依赖数据访问模式:若作业为一次性扫描(如 ETL),缓存毫无价值;
  • 资源竞争:Worker 占用的内存/SSD 与 Spark Executor 争抢节点资源;
  • 故障排查困难:缓存不一致、块丢失、UFS 同步失败等问题需深入源码才能定位。

许多团队投入数月搭建调优缓存集群,最终发现性能提升有限,但运维负担倍增,不得不弃用。

三、反思:分布式缓存是否可以代替文件系统

分布式缓存的困境折射出一个更深层问题:试图用一个通用中间层解决所有 I/O 问题,本身就是一种技术偏执。

分布式缓存在大数据和 AI 训练等大规模数据 IO 场景有明显的作用,但是,作为一个公司,采购或者部署一套分布式缓存集群,无法做到各个场景通用,无法做到物尽其用,充分发挥其作用。

趋势:"专用优于通用" —— 与其维护一个重量级分布式集群,不如构建更具通用性的分层文件系统,中间提供缓存加速层,以文件系统语义提供更通用支持。

四、出路:理性选择,场景驱动

分布式缓存并非一无是处。在以下场景中,它仍具价值:

  • 混合云/多云架构:统一访问不同云厂商的对象存储;
  • 高复用只读数据集:如 AI 训练中反复使用的基准数据集;
  • 有专职平台团队:能承担其运维与调优成本。

但对于大多数企业,更务实的路径是:

  1. 先评估 I/O 是否真为瓶颈:通过 Profiling 确认;
  2. 优先优化数据格式与查询逻辑:用 Iceberg/Lance 替代原始文件;
  3. 避免"为了用缓存而用缓存":缓存是手段,不是目的;
  4. 构建通用性文件系统能力:构建比肩文件系统能力的缓存,充分挖掘通用性。

结语

分布式缓存是一个阶段性的技术实验,它推动了数据编排理念的发展。但它的"殇"也警示我们:没有银弹,只有权衡。在追求高性能的道路上,盲目引入通用中间件往往适得其反。真正的工程智慧,在于理解业务本质,选择最匹配的工具,哪怕它不够"酷"。

分布式缓存不该是架构的标配,而应是特定场景下的精准手术刀。构建更通用、更轻量、更高效的分层文件系统,我们才能避免陷入"缓存之殇",让数据真正流动起来,而非困在层层抽象之中。


Powered by OPPO Bigdata.

Curvine 可观测性建设

· 阅读需 7 分钟

Curvine 作为一款高性能分布式缓存系统,对性能、稳定性和可靠性有着严苛的要求。 为确保系统在各种负载条件下保持最优性能,并快速定位和解决潜在问题,我们构建了基于 Prometheus 和 Grafana 的全方位监控解决方案。该监控体系为 Master 节点、Worker 节点、Fuse 节点和 S3 Gateway 提供深度可观测性能力,通过收集各组件的关键指标,实现对缓存集群规模、运行状态、性能表现和资源使用情况的实时监控。

监控架构

本监控系统采用以下核心组件:

  • Prometheus: 负责指标收集、存储和查询
  • Grafana: 提供数据可视化和仪表板展示

可观测性指标

Master 节点指标

Master 节点作为集群的元数据管理中心,提供以下关键指标:

容量指标

容量指标是评估系统存储资源使用状况的基础,对容量规划、资源优化和预防性维护至关重要。通过监控这些指标,可以及时发现存储瓶颈,预测容量需求,确保系统有足够空间应对业务增长。

容量指标

指标名称描述
inode_dir_num目录数量
inode_file_num文件数量
num_blocksblock 总数
blocks_size_avgblock 平均大小
capacity总存储容量
available可用存储空间
fs_used文件系统已用空间

资源指标

资源指标反映了系统对计算资源的使用情况,对性能调优、资源分配和故障预防具有重要意义。内存使用情况直接影响系统性能和稳定性,特别是 RocksDB 作为核心存储引擎,其内存占用需要精确监控以避免内存溢出和性能下降。

资源指标

指标名称描述
used_memory_bytes已用内存字节数
rocksdb_used_memory_bytesrocksdb 内存占用

集群状态指标

集群状态指标提供了系统整体健康状况的实时视图,对保障高可用性和数据一致性至关重要。通过监控 Worker 节点状态和复制任务执行情况,可以快速发现节点故障、数据不一致等问题,确保分布式缓存系统的可靠运行。

集群状态

指标名称描述
worker_numworker 数量(按状态分类)
replication_staging_number等待复制的块数量
replication_inflight_number正在进行复制的块数量
replication_failure_count累计复制失败的总次数

性能指标

性能指标是衡量系统响应能力和处理效率的核心指标,对性能优化和容量规划具有关键作用。RPC 请求的总计数和总耗时可以计算出平均响应时间,直接反映系统的处理能力,而各类操作的耗时分析有助于识别性能瓶颈,指导系统优化。

性能指标

指标名称描述
rpc_request_total_countRPC 总请求计数
rpc_request_total_timeRPC 总请求时间
operation_duration操作耗时(按类型分类,不包括心跳)

Journal 系统指标

Journal 系统是保证数据一致性和故障恢复的关键组件,其性能直接影响系统的写入性能和数据可靠性。监控 Journal 队列长度和刷新性能可以及时发现写入瓶颈,预防数据丢失风险,确保系统在高并发写入场景下的稳定性。

journal指标

指标名称描述
journal_queue_lenJournal 队列长度
journal_flush_countJournal 刷新次数
journal_flush_timeJournal 刷新时间

Client 指标(Fuse/S3 Gateway)

Fuse 和 S3 Gateway 的指标通过 Client 收集

缓存指标

缓存指标直接反映了缓存系统的核心价值——提升访问性能。挂载缓存的命中率是衡量缓存效果的关键指标,高命中率意味着更少的后端访问和更快的响应速度。这些指标对评估缓存策略有效性、优化缓存配置至关重要。

缓存指标

指标名称描述
client_mount_cache_hits挂载缓存命中数
client_mount_cache_misses挂载缓存未命中数

I/O 指标

I/O 指标是评估系统读写性能的核心数据,对性能调优和容量规划具有指导意义。通过监控读写字节数和耗时,可以计算出读写吞吐量,准确评估系统的 I/O 性能瓶颈,优化存储策略,确保在高并发访问场景下的稳定性能。

I/O指标

指标名称描述
client_write_bytes写入字节数
client_write_time_us写入时间(微秒)
client_read_bytes读取字节数
client_read_time_us读取时间(微秒)

元数据操作指标

元数据操作性能直接影响文件系统的响应速度,对提升用户体验和系统整体性能至关重要。元数据操作的耗时分析有助于识别元数据管理瓶颈,优化目录结构,提升文件系统操作效率。

元数据操作指标

指标名称描述
client_metadata_operation_duration元数据操作耗时

Worker 节点指标

Worker 节点作为数据存储节点,提供全面的存储和性能指标:

容量指标

Worker 节点的容量指标是数据存储管理的核心,对负载均衡、数据迁移和容量规划具有关键作用。通过监控各节点的存储使用情况,可以实现智能的数据分布,防止单点过载,确保整个缓存集群的存储资源得到最优利用。

容量指标

指标名称描述
capacity总存储容量
available可用存储空间
fs_used文件系统已用空间
num_blocksblock 总数
num_blocks_to_delete待删除 block 数

I/O 指标

Worker 节点的 I/O 指标反映了数据存储的实际性能,对评估存储硬件效率、优化数据访问模式至关重要。详细的读写统计信息有助于识别热点数据、优化数据布局,提升整体存储性能和响应速度。

I/O指标

指标名称描述
write_bytes写入字节数
write_time_us写入时间(微秒)
write_count写入次数
write_blocks写入块数(按类型分类)
read_bytes读取字节数
read_time_us读取时间(微秒)
read_count读取次数
read_blocks读取块数(按类型分类)

资源指标

Worker 节点的资源使用情况直接影响数据存储服务的稳定性和性能,对资源调度和性能优化具有重要意义。合理的内存使用是保证数据缓存效率的基础,需要精确监控以避免资源竞争和性能下降。

资源指标

指标名称描述
used_memory_bytes已用内存字节数

硬件状态指标

硬件状态指标是保障数据可靠性和系统可用性的重要监控维度,对预防性维护和故障快速响应至关重要。通过实时监控磁盘健康状态,可以提前发现硬件故障风险,及时进行数据迁移和硬件更换,确保缓存系统的数据安全和持续可用。

硬件状态指标

指标名称描述
failed_disks异常存储数量
total_disks存储磁盘数量

全局面板

Master

Master

Worker

Worker

Client

Client

总结

Curvine 分布式缓存系统的可观测性设计覆盖了从元数据管理到数据存储的完整链路,通过细粒度的指标收集实现了:

  • 全链路监控: 从客户端请求到数据存储的完整监控,确保每个环节的性能和状态都可观测
  • 多维度观测: 涵盖性能、容量、状态等多个维度,提供系统健康度的全面视图
  • 实时告警: 基于关键指标的实时监控和告警,及时发现异常并快速响应
  • 故障诊断: 详细的指标数据支持快速故障定位,缩短故障恢复时间
  • 性能优化: 通过持续监控和分析,为系统性能调优提供数据支撑
  • 容量规划: 基于历史趋势和实时数据,为容量扩展和资源优化提供决策依据

通过这套完善的监控体系,Curvine 能够在复杂的分布式环境中保持高可用性和高性能,为用户提供稳定可靠的缓存服务。

Curvine 分布式缓存系统使用指南

· 阅读需 13 分钟

Version License Documentation

📚 目录


🎯 系统概述

Curvine 是一个高性能、云原生的分布式缓存系统,专为现代数据密集型应用设计。它在底层存储(UFS)和计算引擎之间提供一个智能缓存层,显著提升数据访问性能。

🏆 性能优势

相比传统存储访问方式,Curvine 可以提供:

指标云存储Curvine 缓存性能提升
读取延迟100-500ms1-10ms10-50x
吞吐量100-500 MB/s1-10 GB/s10-20x
IOPS1K-10K100K-1M100x
并发连接100-1K10K-100K100x

核心组件

  • Master 集群: 元数据管理、缓存调度、一致性保障
  • Worker 节点: 数据缓存、I/O 处理、任务执行
  • Client SDK: 多语言客户端,支持Rust、Fuse、Java、Python
  • Job Manager: 分布式任务调度和管理
  • Metrics 系统: 实时监控和性能分析

📂 路径挂载管理

挂载是使用 Curvine 缓存的第一步,它建立了底层存储(UFS)与缓存路径的映射关系。

挂载模式详解

Curvine 支持两种灵活的挂载模式:

🎯 CST 模式(一致路径模式)

# 路径保持一致,便于管理和维护
bin/cv mount s3://bucket/data /bucket/data --mnt-type cst

适用场景:

  • 路径结构清晰的数据湖场景
  • 需要直观路径映射的生产环境
  • 多团队协作的数据平台

🔀 Orch 模式(编排模式)

# 灵活路径映射,支持复杂的路径变换
bin/cv mount s3://complex-bucket/deep/nested/path /simple/data --mnt-type orch

适用场景:

  • 复杂的存储层次结构
  • 需要路径抽象的场景
  • 多云存储统一访问

完整挂载示例

# 挂载 S3 存储到 Curvine(生产级配置)
bin/cv mount \
s3://bucket/warehouse/tpch_500g.db/orders \
/bucket/warehouse/tpch_500g.db/orders \
--ttl-ms 24h \
--ttl-action delete \
--replicas 3 \
--block-size 128MB \
--consistency-strategy always \
--storage-type ssd \
-c s3.endpoint_url=https://s3.ap-southeast-1.amazonaws.com \
-c s3.credentials.access=access_key \
-c s3.credentials.secret=secret_key \
-c s3.region_name=ap-southeast-1

挂载参数详解

参数类型默认值说明示例
--ttl-msduration0缓存数据过期时间24h, 7d, 30d
--ttl-actionenumnone过期策略:delete/nonedelete
--replicasint1数据副本数(1-5)3
--block-sizesize128MB缓存块大小64MB, 128MB, 256MB
--consistency-strategyenumalways一致性策略none/always/period
--storage-typeenumdisk存储介质类型mem/ssd/disk

挂载点管理

# 查看所有挂载点
bin/cv mount

# 卸载路径
bin/cv unmount /bucket/warehouse/tpch_500g.db/orders

💾 智能缓存策略

Curvine 提供多种智能缓存策略,从被动响应到主动预测,全方位优化数据访问性能。

主动数据预加载

主动加载让您可以在业务高峰前预热缓存,确保最佳性能:

# 基础加载
bin/cv load s3:/bucket/warehouse/critical-dataset

# 带进度监控的同步加载
bin/cv load s3:/bucket/warehouse/critical-dataset -w

自动缓存策略

Curvine 的自动缓存系统相比传统方案具有显著优势:

✨ Curvine 智能缓存架构

curvine

核心优势对比

特性开源竞品Curvine优势说明
加载粒度Block级别File/Directory级别避免碎片化,保证完整性
重复处理存在重复加载智能去重节省带宽和存储资源
任务调度简单队列分布式Job Manager高效并发,负载均衡
一致性保障被动检查主动感知实时数据同步

🔄 数据一致性保障

数据一致性是缓存系统的核心挑战,Curvine 提供多层次的一致性保障机制。

一致性策略详解

1. 🚫 None 模式 - 最高性能

bin/cv mount s3://bucket/path /bucket/path --consistency-strategy=none
  • 适用场景: 静态数据、归档数据、只读数据集
  • 性能: ⭐⭐⭐⭐⭐ (最快)
  • 一致性: ⭐⭐ (依赖TTL)

2. ✅ Always 模式 - 强一致性

bin/cv mount s3://bucket/path /bucket/path --consistency-strategy=always
  • 适用场景: 经常更新的业务数据、关键业务系统
  • 性能: ⭐⭐⭐ (有开销)
  • 一致性: ⭐⭐⭐⭐⭐ (强一致性)

3. 🕰️ Period 模式 - 平衡方案

bin/cv mount s3://bucket/path /bucket/path \
--consistency-strategy=period \
--check-interval=5m
  • 适用场景: 更新频率可预期的数据
  • 性能: ⭐⭐⭐⭐ (较好)
  • 一致性: ⭐⭐⭐⭐ (定期保证)

缓存性能监控

监控缓存命中率是评估一致性策略效果的重要手段:

# 获取缓存命中率
curl -s http://master:9001/metrics | grep -E "(cache_hits|cache_misses)"
client_mount_cache_hits{id="3108497238"} 823307
client_mount_cache_misses{id="3108497238"} 4380

🤖 AI/ML 场景应用

AI 和机器学习工作负载对存储性能有极高要求,Curvine 为此提供了专门优化的功能。

深度学习训练优化

# 为 GPU 集群优化的数据加载
bin/cv mount s3://datasets/imagenet /datasets/imagenet \
--storage-type=mem \
--block-size=1GB \
--replicas=2 \

模型服务场景

# 模型文件缓存(低延迟访问)
bin/cv mount s3://model/bert-large /models/bert-large \
--storage-type=mem \
--ttl-ms=none \
--consistency-strategy=always \

# 推理数据缓存
bin/cv mount s3://inference/input /inference/input \
--storage-type=ssd \
--ttl-ms=1h \
--consistency-strategy=none

🔗 POSIX 语义与 FUSE 访问

Curvine 完美支持 POSIX 语义,通过 FUSE(Filesystem in Userspace)接口,可以将 Curvine 集群挂载为本地文件系统,为 AI/ML 应用提供透明的文件访问体验。

AI/ML 训练中的 FUSE 使用

1. 深度学习训练数据访问
# PyTorch 训练脚本
import torch
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
from PIL import Image
import os

class CurvineImageDataset(Dataset):
def __init__(self, root_dir, transform=None):
"""
通过 FUSE 挂载点直接访问 Curvine 中的数据
root_dir: FUSE 挂载点路径,如 /curvine-fuse/datasets/imagenet
"""
self.root_dir = root_dir
self.transform = transform
self.image_paths = []

# 直接遍历 FUSE 挂载的目录
for class_dir in os.listdir(root_dir):
class_path = os.path.join(root_dir, class_dir)
if os.path.isdir(class_path):
for img_file in os.listdir(class_path):
if img_file.lower().endswith(('.png', '.jpg', '.jpeg')):
self.image_paths.append(os.path.join(class_path, img_file))

def __len__(self):
return len(self.image_paths)

def __getitem__(self, idx):
# 通过标准文件操作访问数据,享受 Curvine 缓存加速
img_path = self.image_paths[idx]
image = Image.open(img_path).convert('RGB')

if self.transform:
image = self.transform(image)

# 从路径提取标签
label = os.path.basename(os.path.dirname(img_path))
return image, label

# 使用示例
transform = transforms.Compose([
transforms.Resize((224, 224)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])

# 直接使用 FUSE 挂载点的路径
dataset = CurvineImageDataset(
root_dir='/curvine-fuse/datasets/imagenet/train',
transform=transform
)

dataloader = DataLoader(
dataset,
batch_size=64,
shuffle=True,
num_workers=8,
pin_memory=True
)

# 训练循环
for epoch in range(num_epochs):
for batch_idx, (data, targets) in enumerate(dataloader):
# 数据通过 FUSE 自动从 Curvine 缓存加载
# 享受接近内存的访问速度
outputs = model(data.cuda())
loss = criterion(outputs, targets.cuda())
# ... 训练逻辑
2. TensorFlow/Keras 数据管道
import tensorflow as tf
import os

def create_curvine_dataset(data_dir, batch_size=32):
"""
通过 FUSE 挂载点创建 TensorFlow 数据管道
data_dir: FUSE 挂载的数据目录
"""

# 直接使用标准文件 API 访问 FUSE 挂载的数据
def load_and_preprocess_image(path):
# TensorFlow 通过 FUSE 透明访问 Curvine 缓存
image = tf.io.read_file(path)
image = tf.image.decode_jpeg(image, channels=3)
image = tf.image.resize(image, [224, 224])
image = tf.cast(image, tf.float32) / 255.0
return image

# 扫描 FUSE 挂载目录中的文件
image_paths = []
labels = []

for class_name in os.listdir(data_dir):
class_dir = os.path.join(data_dir, class_name)
if os.path.isdir(class_dir):
for img_file in os.listdir(class_dir):
if img_file.lower().endswith(('.png', '.jpg', '.jpeg')):
image_paths.append(os.path.join(class_dir, img_file))
labels.append(class_name)

# 创建数据集
path_ds = tf.data.Dataset.from_tensor_slices(image_paths)
label_ds = tf.data.Dataset.from_tensor_slices(labels)

# 应用预处理
image_ds = path_ds.map(
load_and_preprocess_image,
num_parallel_calls=tf.data.AUTOTUNE
)

# 组合数据和标签
dataset = tf.data.Dataset.zip((image_ds, label_ds))

return dataset.batch(batch_size).prefetch(tf.data.AUTOTUNE)

# 使用示例
train_dataset = create_curvine_dataset('/curvine-fuse/datasets/imagenet/train')
val_dataset = create_curvine_dataset('/curvine-fuse/datasets/imagenet/val')

# 模型训练
model.fit(
train_dataset,
validation_data=val_dataset,
epochs=50,
callbacks=[
tf.keras.callbacks.ModelCheckpoint('/curvine-fuse/models/checkpoints/'),
tf.keras.callbacks.TensorBoard(log_dir='/curvine-fuse/logs/')
]
)

🗄️ 大数据生态集成

Curvine 与主流大数据框架无缝集成,提供透明的缓存加速能力。

Hadoop 生态集成

基础配置

hdfs-site.xmlcore-site.xml 中添加:

<!-- Curvine FileSystem 实现 -->
<property>
<name>fs.cv.impl</name>
<value>io.curvine.CurvineFileSystem</value>
</property>

<!-- 单集群配置 -->
<property>
<name>fs.cv.master_addrs</name>
<value>master1:8995,master2:8995,master3:8995</value>
</property>

多集群支持

<!-- 集群1:生产环境 -->
<property>
<name>fs.cv.production.master_addrs</name>
<value>prod-master1:8995,prod-master2:8995,prod-master3:8995</value>
</property>

<!-- 集群2:开发环境 -->
<property>
<name>fs.cv.development.master_addrs</name>
<value>dev-master1:8995,dev-master2:8995</value>
</property>

<!-- 集群3:机器学习专用集群 -->
<property>
<name>fs.cv.ml-cluster.master_addrs</name>
<value>ml-master1:8995,ml-master2:8995,ml-master3:8995</value>
</property>

🔄 UFS透明代理

为了更好地支持现有Java应用无缝接入Curvine缓存,我们提供了UFS透明代理解决方案。该方案的核心优势是零代码修改,让现有应用可以立即享受Curvine的缓存加速效果。

✨ 透明代理核心特性

  • 🚫 零代码修改: 保留原有所有接口不变,业务代码无需任何修改
  • 🔍 智能路径识别: 仅在文件打开时判断路径是否已挂载到Curvine
  • ⚡ 自动缓存加速: 已挂载路径自动启用缓存加速,未挂载路径走原生S3访问
  • 🔄 平滑切换: 支持在运行时动态切换是否使用缓存,无需重启应用

🛠️ 配置方式

只需要替换Hadoop配置中的S3FileSystem实现类:

<!-- 传统S3访问配置 -->
<!--
<property>
<name>fs.s3a.impl</name>
<value>org.apache.hadoop.fs.s3a.S3AFileSystem</value>
</property>
-->

<!-- 替换为Curvine透明代理 -->
<property>
<name>fs.s3a.impl</name>
<value>io.curvine.S3AProxyFileSystem</value>
</property>

<property>
<name>fs.cv.impl</name>
<value>io.curvine.CurvineFileSystem</value>
</property>

<!-- Curvine集群配置 -->
<property>
<name>fs.curvine.master_addrs</name>
<value>master1:8995,master2:8995,master3:8995</value>
</property>

🔧 工作原理

Working Principle

🚀 使用示例

无需修改任何业务代码,原有代码直接享受加速:

// 业务代码完全不变!
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create("s3a://my-bucket/"), conf);

// 这个路径如果已挂载到Curvine,自动享受缓存加速
FSDataInputStream input = fs.open(new Path("s3a://my-bucket/warehouse/data.parquet"));

// 这个路径如果未挂载,走原生S3访问
FSDataInputStream input2 = fs.open(new Path("s3a://my-bucket/archive/old-data.parquet"));

Spark/MapReduce代码示例:

// Spark代码无需任何修改
Dataset<Row> df = spark.read()
.option("header", "true")
// 如果/warehouse/路径已挂载,自动使用缓存加速
.csv("s3a://data-lake/warehouse/customer_data/");

df.groupBy("region")
.agg(sum("revenue").alias("total_revenue"))
.orderBy(desc("total_revenue"))
.show(20);

Python PySpark示例:

# Python代码也无需修改
from pyspark.sql import SparkSession
from pyspark.sql.functions import sum, desc

spark = SparkSession.builder.appName("TransparentCache").getOrCreate()

# 自动判断是否使用缓存
df = spark.read \
.option("header", "true") \
.csv("s3a://data-lake/analytics/events/")

result = df.groupBy("event_type") \
.agg(sum("count").alias("total_events")) \
.orderBy(desc("total_events"))

result.show()

Apache Spark 优化配置

# Spark 应用启动配置
spark-submit \
--class com.example.SparkApp \
--master yarn \
--deploy-mode cluster \
--conf spark.hadoop.fs.cv.impl=io.curvine.CurvineFileSystem \
--conf spark.hadoop.fs.cv.master_addrs=master1:8995,master2:8995,master3:8995 \
--conf spark.sql.adaptive.enabled=true \
--jars curvine-hadoop-client.jar \
app.jar

Spark 代码示例

// Scala 示例
val spark = SparkSession.builder()
.appName("Curvine Demo")
.config("spark.hadoop.fs.cv.impl", "io.curvine.CurvineFileSystem")
.getOrCreate()

// 直接使用 cv:// 协议访问缓存数据
val df = spark.read
.option("multiline", "true")
.json("cv://production/warehouse/events/2024/01/01/")

df.groupBy("event_type")
.count()
.show()

// 多集群访问
val prodData = spark.read.parquet("cv://production/warehouse/sales/")
val mlData = spark.read.parquet("cv://ml-cluster/features/user_profiles/")
# Python 示例
from pyspark.sql import SparkSession

spark = SparkSession.builder \
.appName("Curvine Python Demo") \
.config("spark.hadoop.fs.cv.impl", "io.curvine.CurvineFileSystem") \
.config("spark.hadoop.fs.cv.master_addrs", "master1:8995,master2:8995") \
.getOrCreate()

# 读取缓存中的数据
df = spark.read.option("header", "true") \
.csv("cv://warehouse/customer_data/")

# 复杂查询自动享受缓存加速
result = df.groupBy("region") \
.agg({"revenue": "sum", "orders": "count"}) \
.orderBy("sum(revenue)", ascending=False)

result.show(20)

Trino/Presto 插件集成

Curvine 提供了智能路径替换插件,可以做到无侵入性实现缓存加速,不需要业务修改代码,实现完全透明的缓存加速:

插件工作流程

Plugin Workflow

spark 插件使用实例:

spark-submit \
--class main.scala.Tpch \
--name tpch_demo \
--conf spark.hadoop.fs.cv.impl=io.curvine.CurvineFileSystem \
--conf spark.hadoop.fs.cv.default.master_addrs=master1:8995,master2:8995 \
--conf spark.sql.extensions=io.curvine.spark.CurvineSparkExtension \
// Flink Table API 集成示例
TableEnvironment tableEnv = TableEnvironment.create(settings);

// 配置 Curvine FileSystem
Configuration config = new Configuration();
config.setString("fs.cv.impl", "io.curvine.CurvineFileSystem");
config.setString("fs.cv.master_addrs", "master1:8995,master2:8995");

// 创建 Curvine 表
tableEnv.executeSql(
"CREATE TABLE user_events (" +
" user_id BIGINT," +
" event_type STRING," +
" timestamp_ms BIGINT," +
" properties MAP<STRING, STRING>" +
") WITH (" +
" 'connector' = 'filesystem'," +
" 'path' = 'cv://streaming/events/'," +
" 'format' = 'json'" +
")"
);

// 实时查询享受缓存加速
Table result = tableEnv.sqlQuery(
"SELECT user_id, COUNT(*) as event_count " +
"FROM user_events " +
"WHERE timestamp_ms > UNIX_TIMESTAMP() * 1000 - 3600000 " +
"GROUP BY user_id"
);


💡 最佳实践

🎯 挂载策略最佳实践

按业务场景分层挂载

# 热数据:高频访问,使用内存缓存
bin/cv mount s3://bucket/hot /bucket/hot \
--storage-type=mem \
--replicas=3 \
--ttl-ms=1d \
--ttl-action=delete

# 温数据:定期访问,使用 SSD 缓存
bin/cv mount s3://bucket/warm /bucket/warm \
--storage-type=ssd \
--replicas=2 \
--ttl-ms=7d \
--ttl-action=delete


# 冷数据:低频访问,使用磁盘缓存
bin/cv mount s3://bucket/cold /bucket/cold \
--storage-type=disk \
--replicas=1 \
--ttl-ms=30d \
--ttl-action=delete

按数据类型优化

# 小文件密集型(如日志、配置)
bin/cv mount s3://bucket/logs /bucket/logs \
--block-size=4MB \
--consistency-strategy=none \

# 大文件型(如视频、模型)
bin/cv mount s3://bucket/models /bucket/models \
--block-size=1GB \
--consistency-strategy=always \

# 分析型数据(如 Parquet)
bin/cv mount s3://bucket/analytics /bucket/analytics \
--block-size=128MB \
--consistency-strategy=none \

🎯 总结

Curvine 作为新一代分布式缓存系统,通过智能缓存策略、强一致性保障和无缝生态集成,为现代数据密集型应用提供了卓越的性能提升。

🏆 核心价值

  • 🚀 性能提升: 10-100倍的访问加速,显著降低数据访问延迟
  • 💰 成本优化: 减少云存储访问费用,提高计算资源利用率
  • 🛡️ 数据安全: 多重一致性保障,确保数据准确性和完整性
  • 🌐 生态友好: 与主流大数据和 AI 框架无缝集成

Curvine - 让数据访问快如闪电 ⚡

从0到1构建Curvine集群&FIO测试

· 阅读需 2 分钟
Founder of Curvine
Barry
Senior Engineer

如何快速上手试试Curvine的效果?这篇文章将介绍如何从0到1构建一个本地小集群,让大家快速上手。

github: https://github.com/CurvineIO/curvine


1. 下载代码:

git clone https://github.com/CurvineIO/curvine.git

2.环境要求:

GCC: version 10 or later 
Rust: version 1.86 or later
Protobuf: version 3.x
Maven: version 3.8 or later
LLVM: version 12 or later
FUSE: libfuse2 or libfuse3 development packages
JDK: version 1.8 or later
npm: version 9 or later
Python: version 3.7 or later

参考

3. 编译&&运行

make all

为方便大家编译,我们做编译脚本里会提前做依赖组件检查,对于MacOS系统的用户,暂时会选择跳过FUSE的编译(目前没适配mac系统)。 感兴趣的朋友可以考虑使用macfuse项目,进行适配。

make-checkenv

4.编译完成,启动本地集群

cd build/dist
./bin/restart-all.sh

启动成功后,执行report命令,检查是否成功:


bin/cv report

active_master: localhost:8995
journal_nodes: 1,localhost:8996
capacity: 233.5GB
available: 105.0GB (44.99%)
fs_used: 0.0B (0.00%)
non_fs_used: 128.4GB
live_worker_num: 1
lost_worker_num: 0
inode_num: 0
block_num: 0
live_worker_list: 192.168.xxx.xxx:8997,105.0GB/233.5GB (44.99%)
lost_worker_list:

5. 查看本地master和worker的webui

http://localhost:9000/
http://localhost:9001/

webui

6. FIO测试

测试环境:阿里云 ecs.r8a.8xlarge 机型 master/woker/client 各一台

  • 32 核(vCPU)
  • 256 GiB 内存
  • 系统盘 和 数据盘 均为:ESSD 云盘 500 GiB(7800 IOPS)
  • 最大带宽:25Gb

准备数据(在worker机器):

bin/curvine-bench.sh fuse.write

fio顺序读测试,8并发

fio -iodepth=1 -rw=read -ioengine=libaio -bs=256k
-group_reporting -size=200gb
-filename=/curvine-fuse/fs-bench/0
-name=read_test --readonly -direct=1 --runtime=60
-numjobs=8

fio随机读测试,8并发


fio -iodepth=1 -rw=randread -ioengine=libaio -bs=256k
-group_reporting -size=200gb
-filename=/curvine-fuse/fs-bench/0
-name=read_test --readonly -direct=1 --runtime=60
-numjobs=8

最后,视频演示一下,做一下fio测试的效果:

高性能分布式缓存Curvine,低调开源

· 阅读需 2 分钟
Founder of Curvine

Curvine是什么

 Curvine是一套分布式缓存系统,基于Rust实现,具备 高并发,高吞吐,低延迟,资源消耗低等特点。不同于Redis、TiKV等KV缓存,Curvine只提供文件缓存能力。Curvine不是存储系统,只提供缓存能力,数据持久化还是需要底层文件或者对象存储系统支撑。

解决什么问题

  1. 大规模数据IO性能瓶颈
  2. 单机缓存系统容量瓶颈

实际应用中,有哪些场景适用Curvine加速?

Curvine Application Scenarios.

Fig. 1:Curvine Application Scenarios.

如上图所示,Curvine适用于以下五大场景:

  1. 大数据shuffle 中间数据加速
  2. 大数据热表数据缓存加速
  3. AI训练数据缓存加速
  4. 模型文件分发缓存加速
  5. 多云数据缓存,解决跨云专线性能瓶颈

以上场景总结,只是抛砖引玉,通俗的理解,Curvine其实就是解决: 日益增长的计算性能需求与分布式存储系统的IO能力瓶颈的矛盾。

架构简介

 Curvine架构设计理念:简单、极致、通用。

Curvine Architecture Diagram.

Fig. 2:Curvine Application Scenarios.

简单:简单轻量,缓存服务只有两个角色:master、worker。非性能瓶颈的模块,尽量复用开源或者已有的技术,代码最大可能轻量化。

极致:对性能影响较大的关键节点:底层rpc通信架构、Fuse 实现性能等关键组件,自主设计实现,以极致性能优化思维构建。

通用::兼容多种现有接入模式,底层存储兼容主流分布式文件和对象存储做到足够通用,易用。

关于开源

 我们在内部大数据高并发高吞吐场景下使用Curvine加速数据IO,取得比较大的收益。希望吸引外部的伙伴共同建设,一起加速基础设施向Rust转变。  https://github.com/curvineio/curvine

  由OPPO大数据提供支持。