StrmVol 存储卷:如何解锁 K8s 对象存储海量小文件访问性能新高度?

本文涉及的产品
任务调度 XXL-JOB 版免费试用,400 元额度,开发版规格
应用实时监控服务-可观测链路OpenTelemetry版,每月50GB免费额度
应用实时监控服务-应用监控,每月50GB免费额度
简介: 本文介绍了阿里云容器服务(ACK)支持的StrmVol存储卷方案,旨在解决Kubernetes环境中海量小文件访问性能瓶颈问题。通过虚拟块设备与内核态文件系统(如EROFS)结合,StrmVol显著降低了小文件访问延迟,适用于AI训练集加载、时序日志分析等场景。其核心优化包括内存预取加速、减少I/O等待、内核态直接读取避免用户态切换开销,以及轻量索引快速初始化。示例中展示了基于Argo Workflows的工作流任务,模拟分布式图像数据集加载,测试结果显示平均处理时间为21秒。StrmVol适合只读场景且OSS端数据无需频繁更新的情况,详细使用方法可参考官方文档。

1.gif


对象存储 OSS 凭借其支持海量非结构化数据存储、按需付费的弹性成本以及基于标准 HTTP 协议的跨平台便捷访问特性,成为大数据场景的重要存储方案。在 Kubernetes(K8s)容器化业务中,提升 OSS 数据的访问性能能有效节省计算资源,提高业务效率。如何提升海量文件的数据读取速率,对于 AI 训练集管理、量化回测、时序日志分析等场景尤为重要。


阿里云容器服务(ACK) 支持 StrmVol 类型存储卷,基于底层虚拟块设备及内核态文件系统,如 ext4、EROFS(Extended Read-Only File System,扩展只读文件系统),显著降低海量小文件访问延迟。本文将简单介绍 StrmVol 存储方案的实现原理及适用场景,并以图片训练集读取场景为例,展示 StrmVol 存储卷的使用方式。


海量小文件数据的访问性能瓶颈


在 K8s 环境中,业务容器访问 OSS 的标准方式是通过存储卷机制。这一过程依赖于容器存储接口(CSI)驱动,目前主流的实现方案是通过 FUSE(Filesystem in Userspace)客户端挂载 OSS 数据。


FUSE 允许用户在用户态空间实现文件系统逻辑,通过内核与用户态的交互将对象存储的元数据和数据映射为本地文件系统接口(POSIX)。CSI 驱动通过 FUSE 客户端将 OSS 路径挂载为容器内的本地目录,业务应用可直接通过标准文件操作(如 open()read())访问数据。


针对顺序读写大文件场景,FUSE 客户端可通过预读、缓存等技术显著提升性能(例如视频流媒体、大数据文件处理)。但在小文件场景依然存在性能瓶颈,这是因为:


  • 频繁的内核态切换:每次文件操作(如 open()close())需在用户态 FUSE 进程与内核态之间多次上下文切换,导致额外开销。
  • 元数据管理压力:对象存储的元数据(如文件列表、属性)需通过 HTTP/REST API 查询,海量小文件的元数据请求会显著增加网络延迟和带宽占用。


StrmVol存储卷:虚拟块设备方案


为解决 FUSE 在海量小文件场景中的性能瓶颈,StrmVol 存储卷提出了一种基于虚拟块设备(Virtual Block Device)加内核态文件系统(如 EROFS的方案,通过消除 FUSE 中间层的性能损耗,使数据访问路径直接下沉至存储驱动层,提升数据的访问速度,特别适用于 AI 训练集加载、时序日志分析等需要快速遍历百万级小文件的业务场景。


核心机制与优化细节


  • 快速索引构建:仅元信息同步,加速初始化流程

初始化阶段仅拉取 OSS Bucket 挂载点下文件元信息(如文件名、路径、大小)并构建索引,不包含对象扩展信息(如自定义元数据、标签),显著缩短索引构建时间,提升部署效率。


  • 内存预取优化:并发读取提升数据访问效率

虚拟块设备通过预设内存空间作为临时存储介质,根据已构建的索引信息提前并发预取后续可能访问的数据块。这一机制减少 I/O 等待时间,尤其在海量小文件场景中可降低读取延迟。


  • 内核态文件系统加速:避免用户态切换,提升容器化业务读取性能

容器化业务通过内核态文件系统 直接从内存中读取数据,避免用户态与内核态的频繁切换带来的上下文开销。其中,默认使用的 EROFS 文件系统通过压缩与高效访问机制,进一步提升存储空间利用率和数据读取性能。


适用场景


  • 数据已存储在 OSS Bucket 中,且在业务运行期间数据无更新需求。
  • 业务对文件系统的扩展信息不敏感。
  • 只读场景,尤其是海量小文件或随机读场景。


图像数据集加载性能测试


本文示例通过 Argo Workflow 模拟分布式图像数据集加载场景。


数据集基于 ImageNet 部分数据,假设存储于 oss://imagenet/data/ 路径下,包含 4 个子目录(如 oss://imagenet/data/n01491361/),每个目录存放 10480 张图像,约 1.2G 大小。


安装strmvol-csi-driver


使用 strmvol 存储卷需要部署单独的 CSI 驱动(strmvol-csi-driver 组件),可直接在 ACK 应用市场中部署。部署后,该 CSI 驱动与 ACK 组件管理中维护的 csi-provisioner 与 csi-plugin 组件相互独立,不会产生冲突。



创建StrmVol存储卷


StrmVol 存储卷的 PVC 与 PV 定义与目前 ACK OSS 存储卷配置类似,本次测试中使用的存储卷 YAML 如下。


apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-strmvol
spec:
  capacity:
  # 挂载的OSS挂载点下最高可存储16 TiB数据。
    storage: 20Gi
  # 仅支持ReadOnlyMany访问模式。
  accessModes:
    - ReadOnlyMany
  persistentVolumeReclaimPolicy: Retain
  csi:
    driver: strmvol.csi.alibabacloud.com
    volumeHandle: pv-strmvol
    nodeStageSecretRef:
      name: strmvol-secret
      namespace: default
    volumeAttributes:
      bucket: imagenet
      path: /data
      url: oss-cn-hangzhou-internal.aliyuncs.com
      directMode: "false"
      resourceLimit: "4c8g"
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: pvc-strmvol
  namespace: default
spec:
  accessModes:
    - ReadOnlyMany
  resources:
    requests:
      storage: 20Gi
  volumeName: pv-strmvol


其中,比较重要的 PV 配置参数为 directMode resourceLimit


  • directMode: 是否开启 direct 模式。开启时,关闭预取与数据本地缓存,适合小文件随机读场景,如训练集的随机批量读取。本次示例使用简单的顺序读取,因此选择关闭 direct 模式。
  • resourceLimit: 挂载虚拟块设备后能使用节点的最大资源限制。"4c8g"表示该虚拟块设备最多能占用节点的 4 vCPU、8GiB 内存资源。


基于Argo Workflows创建数据集处理工作流任务


工作流分为三阶段:


1)list-shards 阶段:通过 Python 脚本列出挂载路径下的 4 个目录生成路径集合;

2)parallel-processing 阶段:并发启动 4 个子任务,每个任务通过 parallel -j4 指令对对应目录下的所有图像执行4线程并行读取操作(模拟加载);

3)calculate-averages 阶段:汇总各任务耗时,计算并输出平均处理时间。


Argo Workflows 组件可在 ACK 集群组件管理中快速安装。安装后,可使用 Argo CLI 或 kubectl 快速提交工作流【1】


apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: distributed-imagenet-training-
spec:
  entrypoint: main
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: "node-type"
                operator: In
                values:
                  - "argo"
  volumes:
  - name: pvc-volume
    persistentVolumeClaim:
      claimName: pvc-strmvol

  templates:
  - name: main
    steps:
    - - name: list-shards
        template: list-imagenet-shards
    - - name: parallel-processing
        template: process-shard
        arguments:
          parameters:
            - name: paths
              value: "{{item}}"
        withParam: "{{steps.list-shards.outputs.result}}"
    - - name: calculate-statistics
        template: calculate-averages

  - name: list-imagenet-shards
    script:
      image: mirrors-ssl.aliyuncs.com/python:latest
      command: [python]
      source: |
        import subprocess
        import json
        output = subprocess.check_output("ls /mnt/data", shell=True, text=True)
        files = [f for f in output.split('\n') if f]
        print(json.dumps(files, indent=2))
      volumeMounts:
        - name: pvc-volume
          mountPath: /mnt/data

  - name: process-shard
    inputs:
      parameters:
      - name: paths
    container:
      image: alibaba-cloud-linux-3-registry.cn-hangzhou.cr.aliyuncs.com/alinux3/alinux3:latest
      command: [/bin/bash, -c]
      args:
      - |
        yum install -y parallel
        SHARD_JSON="/mnt/data/{{inputs.parameters.paths}}"
        SHARD_NUM="{{inputs.parameters.paths}}"
        START_TIME=$(date +%s)

        echo "Processing shard $SHARD_JSON"
        find "$SHARD_JSON" -maxdepth 1 -name "*.JPEG" -print0 | parallel -0 -j4 'cp {} /dev/null'

        END_TIME=$(date +%s)
        ELAPSED=$((END_TIME - START_TIME))

        mkdir -p /tmp/output
        echo $ELAPSED > /tmp/output/time_shard_${SHARD_NUM}.txt
      resources:
        requests:
          memory: "4Gi"
          cpu: "1000m"
        limits:
          memory: "4Gi"
          cpu: "2000m"
      volumeMounts:
        - name: pvc-volume
          mountPath: /mnt/data
    outputs:
      artifacts:
        - name: time_shard
          path: /tmp/output/time_shard_{{inputs.parameters.paths}}.txt
          oss:
            key: results/results-{{workflow.creationTimestamp}}/time_shard_{{inputs.parameters.paths}}.txt
          archive:
            none: {}

  - name: calculate-averages
    inputs:
      artifacts:
        - name: results
          path: /tmp/output
          oss:
            key: "results/results-{{workflow.creationTimestamp}}"
    container:
      image: registry-vpc.cn-beijing.aliyuncs.com/acs/busybox:1.33.1
      command: [sh, -c]
      args:
      - |
        echo "开始合并结果..."

        TOTAL_TIME=0
        SHARD_COUNT=0
        echo "各分片处理时间统计:"

        for time_file in /tmp/output/time_shard_*.txt; do
          TIME=$(cat $time_file)
          SHARD_ID=${time_file##*_}
          SHARD_ID=${SHARD_ID%.txt}

          echo "分片 ${SHARD_ID}: ${TIME} 秒"
          TOTAL_TIME=$((TOTAL_TIME + TIME))
          SHARD_COUNT=$((SHARD_COUNT + 1))
        done

        if [ $SHARD_COUNT -gt 0 ]; then
          AVERAGE=$((TOTAL_TIME / SHARD_COUNT))
          echo "--------------------------------"
          echo "总分片数量: $SHARD_COUNT"
          echo "总处理时间: $TOTAL_TIME 秒"
          echo "平均处理时间: $AVERAGE 秒/分片"

          echo "Average: $AVERAGE seconds" > /tmp/output/time_stats.txt
        else
          echo "错误:未找到分片时间数据"
          exit 1
        fi

    outputs:
      artifacts:
        - name: test-file
          path: /tmp/output/time_stats.txt
          oss:
            key: results/results-{{workflow.creationTimestamp}}/time_stats.txt
          archive:
            none: {}


工作流的运行结果如图所示,列举所有图像并读取其数据的平均耗时为 21 秒。


开始合并结果...
各分片处理时间统计:
分片 1: 21 秒
分片 2: 21 秒
分片 3: 22 秒
分片 4: 21 秒
--------------------------------
总分片数量: 4
总处理时间: 85 秒
平均处理时间: 21 秒/分片



开源方案


阿里云也将基于

containerd/overlaybd[https://github.com/containerd/overlaybd]项目提供了该技术的开源实现,结合 OCI image volume 可以为容器挂载一个只读数据卷。详细介绍可参考 https://www.youtube.com/watch?v=XqL5lh32lr8&t=962s


StrmVol存储卷总结


核心优化

  • 内存预取加速数据访问,减少 I/O 等待;
  • 内核态直接读取避免用户态切换开销;
  • 轻量索引快速初始化,仅同步必要元数据。

适用场景

  • 海量小文件只读场景;
  • OSS 端数据存储无需频繁更新。


StrmVol 的详细使用方式与更多压测数据,可阅读官方文档使用 strmvol 存储卷优化 OSS 小文件读取性能【2】

【1】快速提交工作流https://help.aliyun.com/zh/ack/distributed-cloud-container-platform-for-kubernetes/user-guide/create-a-workflow#section-bz1-rq8-7rz【2】使用strmvol存储卷优化OSS小文件读取性能https://help.aliyun.com/zh/ack/ack-managed-and-ack-dedicated/user-guide/use-strmvol-storage-volumes

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
StrmVol存储卷:如何解锁K8s对象存储海量小文件访问性能新高度?
如何提升海量文件的数据读取速率,对于AI训练集管理、量化回测、时序日志分析等场景尤为重要。阿里云容器服务(ACK))支持StrmVol类型存储卷,基于底层虚拟块设备及内核态文件系统,显著降低海量小文件访问延迟。
阿里云对象存储oss怎么收费?存储费用+流量收费标准
阿里云对象存储OSS收费标准包含存储费、流量费及请求费等,支持按量付费与包年包月两种模式。标准型本地冗余存储按量付费价格为0.09元/GB/月,包年包月500GB预留空间优惠价118元/年。流量费仅收取公网出方向费用,忙时0.50元/GB,闲时0.25元/GB。更多详情可参考官方页面。
阿里云对象存储OSS收费标准:500G存储118元1年、
阿里云对象存储OSS 2025年收费标准涵盖存储、流量及请求等费用,支持按量付费与包年包月两种模式。标准型存储按量价格为0.09元/GB/月,包年包月如9元享40GB体验价。流量费仅收取公网出方向,忙时0.50元/GB,闲时0.25元/GB。此外提供多种存储类型(低频、归档等)及流量包优惠方案,未使用功能不收费。详情见阿里云OSS官网。
371 6
阿里云对象存储OSS收费标准,存储、流量和请求等多个计费项
阿里云对象存储OSS收费标准涵盖存储、流量及请求费用,提供按量付费和包年包月两种模式。标准型OSS按量付费为0.09元/GB/月,包年包月40GB仅9元/年,500GB优惠价118元/年。流量费仅收取公网流出方向,内网流入流出免费。
303 13
基于阿里云 EMR Serverless Spark 版快速搭建OSS日志分析应用
基于阿里云 EMR Serverless Spark 版快速搭建OSS日志分析应用
人工智能平台PAI使用问题之怎么将DLC的数据写入到另一个阿里云主账号的OSS中
阿里云人工智能平台PAI是一个功能强大、易于使用的AI开发平台,旨在降低AI开发门槛,加速创新,助力企业和开发者高效构建、部署和管理人工智能应用。其中包含了一系列相互协同的产品与服务,共同构成一个完整的人工智能开发与应用生态系统。以下是对PAI产品使用合集的概述,涵盖数据处理、模型开发、训练加速、模型部署及管理等多个环节。
阿里云MaxCompute-XGBoost on Spark 极限梯度提升算法的分布式训练与模型持久化oss的实现与代码浅析
本文介绍了XGBoost在MaxCompute+OSS架构下模型持久化遇到的问题及其解决方案。首先简要介绍了XGBoost的特点和应用场景,随后详细描述了客户在将XGBoost on Spark任务从HDFS迁移到OSS时遇到的异常情况。通过分析异常堆栈和源代码,发现使用的`nativeBooster.saveModel`方法不支持OSS路径,而使用`write.overwrite().save`方法则能成功保存模型。最后提供了完整的Scala代码示例、Maven配置和提交命令,帮助用户顺利迁移模型存储路径。
阿里云EMR数据湖文件系统问题之OSS-HDFS全托管服务的问题如何解决
阿里云EMR数据湖文件系统问题之OSS-HDFS全托管服务的问题如何解决
116 1
DataWorks产品使用合集之如何使用Python和阿里云SDK读取OSS中的文件
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。

云原生

+关注