Skip to content

BarrelKnight/raas

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RAAS (Random Access Archive Stream)

流式 tar 归档下载服务器,支持随机访问和 HTTP Range 请求。

项目背景

在工作中遇到了一个业务场景:需要提供一个将整个目录一次性打包下载的 HTTP 下载链接。这个场景面临以下挑战:

  1. 文件体积巨大: 目录下的文件非常大,传统的压缩方式需要占用双倍的存储空间(源目录 + 压缩文件)
  2. 必须保持原始目录结构: 不能简单地打平文件结构,需要完整保留目录层级
  3. 内容频繁更新: 源目录内容会不定期更新,如果采用预先压缩的方式,每次更新后都需要重新压缩,耗时耗力
  4. 临时压缩延迟高: 如果在用户请求时临时压缩,用户需要等待很长时间才能开始下载,体验极差
  5. 大文件下载可靠性: 由于文件非常大,下载过程中很容易因网络中断而失败,需要支持断点续传和多线程下载

基于这些实际需求,开发了这个项目。

项目概述

RAAS (Random Access Archive Stream) 是一个高性能的流式 tar 归档下载服务器,其核心功能是将整个目录打包成一个可下载的归档文件,解决了传统 HTTP 下载只能一次性下载单个资源的局限性。

与传统方案不同,RAAS 无需预先创建完整的 tar 文件即可实现流式传输。当客户端请求下载某个目录时,服务器会实时扫描目录结构、计算文件偏移量、构建虚拟索引,然后通过 HTTP 响应流式生成并传输 tar 归档数据。整个过程无需在磁盘上创建临时文件,内存占用极低,即使对于 GB 级别的大型目录也能高效处理。

核心特性:随机访问压缩流

RAAS 最具创新性的特性是支持对 tar 压缩流的随机访问。这意味着:

  • 不只是打包下载: 系统不仅能将整个目录打包成 tar 格式供客户端下载,更重要的是实现了对生成的 tar 流的任意位置访问能力
  • HTTP Range 协议完整支持: 基于随机访问能力,系统完整实现了 HTTP Range 协议,使客户端可以:
    • 多线程下载: 同时发起多个 Range 请求,并行下载归档的不同部分,显著提升下载速度
    • 断点续传: 网络中断后可以从断点位置继续下载,无需重新开始,对大文件下载尤为重要
    • 部分下载: 只下载归档文件中需要的特定字节范围,无需获取完整归档,节省带宽和时间

要点

  1. 随机访问压缩流: 实现了对 tar 流的任意位置访问,这是区别于传统 tar 服务器的核心能力
  2. 完全流式处理: 无需预创建完整归档文件,无需临时文件,边计算边传输,内存占用与目录大小无关
  3. 缓存机制:
    • 文件句柄缓存: 使用 RefCell 缓存当前文件句柄,避免重复打开文件的系统调用开销,请求结束后自动释放
    • 归档索引缓存: 缓存已扫描的目录结构和预计算的偏移量信息,减少重复扫描和计算
    • tar 头部缓存: 预计算并缓存每个文件的 tar 头部(包括 GNU LongLink 扩展),避免重复生成
  4. tar 格式规范:
    • 支持 GNU LongPath 扩展,处理超过 100 字符的长路径
    • 严格的 512 字节对齐处理
    • 正确的目录项和文件项区分
  5. 路径安全验证: 防止路径穿越攻击,确保访问路径在 DATA_ROOT 范围内

原理

当客户端请求一个目录的归档下载时,系统执行以下流程:

1. 目录扫描与元数据收集

  • 递归扫描目标目录,收集所有文件和子目录的元数据信息
  • 获取每个文件的相对路径、实际大小、类型(文件/目录)

2. 偏移量精确计算

  • 为每个文件创建 tar 头部,确定是否需要 GNU LongLink 扩展
  • 计算每个文件在 tar 流中的精确位置偏移量,包括:
    • tar 头部大小(标准 512 字节或带 LongLink 的扩展头部)
    • 文件内容大小
    • 内容后的 512 字节对齐填充
  • 所有偏移量存储在 file_index HashMap 中,形成虚拟索引

3. 虚拟归档索引构建

  • 构建包含所有文件元数据和偏移量的索引结构
  • 预计算并缓存每个文件的 tar 头部数据(包括 GNU LongLink 头部)
  • 计算归档文件的总大小(total_size)

4. 基于偏移量的随机访问

  • 当收到 Range 请求(如 Range: bytes=1024-2048)时,系统通过 file_index 快速定位到对应偏移量
  • 使用二分查找算法(find_file_by_position)确定指定位置属于哪个文件的哪个部分(头部/内容/填充)
  • 无需按顺序读取,可直接跳转到任意位置开始传输

5. 流式数据传输

  • RangeStreamWriter 实现了 std::io::Read trait,支持按需读取指定范围的数据
  • 根据当前位置判断需要读取的数据类型:
    • 头部区域: 直接从 header_cache 读取预计算的 tar 头部
    • 内容区域: 通过文件句柄缓存打开源文件,seek 到指定位置读取文件内容
    • 填充区域: 生成零字节填充数据以满足 512 字节对齐
  • 使用异步流(async_stream)将数据分块传输给 HTTP 响应体
  • 整个过程按需进行,内存中只保留当前读取的数据块

快速开始

编译

cargo build --release

运行

# 设置数据根目录(Windows PowerShell)
$env:DATA_ROOT="C:\your\data\directory"

# 设置监听地址(可选)
$env:BIND_ADDR="0.0.0.0:8080"

# 启动服务器
cargo run --release

使用示例

下载完整归档

curl -O http://127.0.0.1:8080/api/archive/download?path=my_folder

部分下载(Range 请求)

curl -H "Range: bytes=0-1023" http://127.0.0.1:8080/api/archive/download?path=my_folder

配置

环境变量

变量名 说明 默认值
DATA_ROOT 数据根目录 .
BIND_ADDR 监听地址 0.0.0.0:8080
MAX_CONCURRENT_REQUESTS 最大并发请求数 100
THREAD_POOL_SIZE 线程池大小 4
STREAM_READ_BUFFER_SIZE 流式读取缓冲区大小(字节) 8192
ARCHIVE_CACHE_MAX_CAPACITY 存档缓存最大容量 100

API 文档

GET /api/archive/download

流式下载目录为 tar 归档。

查询参数:

  • path (必需): 相对于 DATA_ROOT 的路径

响应头:

  • Content-Type: application/x-tar
  • Accept-Ranges: bytes
  • Content-Disposition: attachment; filename="<name>.tar"

支持 Range 请求:

  • 请求头: Range: bytes=start-end
  • 响应状态: 206 Partial Content
  • 响应头: Content-Range: bytes start-end/total

开发计划

1. 文件系统监听与缓存自动失效机制

目标: 实现文件系统变更自动检测,确保缓存数据与源目录保持一致

2. 零拷贝文件传输优化 (sendfile)

目标: 集成操作系统级零拷贝机制,大幅提升大文件传输性能

3. Zip 压缩格式支持

目标: 扩展归档格式选择,支持 Zip 格式同时保持随机访问特性

许可证

MIT

About

流式 tar 归档下载服务器,支持随机访问和 HTTP Range 请求。无需临时文件,内存占用低,完美应对大目录打包和断点续传。

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages