跳转至

548_分布式文件系统设计


一句话说明

分布式文件系统将文件存储分散到多台机器,提供统一访问接口,解决单机存储容量和吞吐量瓶颈。


核心知识点

生信常用分布式存储系统

系统类型适合场景典型部署
HDFS分布式文件系统大文件顺序读写Hadoop生态
Lustre/GPFS并行文件系统HPC高性能计算超级计算机
Ceph统一存储对象+块+文件私有云
MinIO对象存储S3兼容,轻量自建云存储
AWS S3对象存储弹性扩展公有云
GlusterFS分布式文件中小规模开源私有部署

设计关键挑战

1. 数据一致性:文件写入后如何保证所有节点看到
2. 故障容错:节点宕机如何不丢数据
3. 大文件处理:生信单文件可达100GB+
4. 并发访问:多个Worker同时读一个大文件
5. 数据定位:如何快速找到文件存在哪个节点

HDFS 架构(经典分布式文件系统)

[客户端]
   │ 读写请求
[NameNode] ← 元数据服务(文件目录树、块位置)
   │ 返回DataNode地址
[DataNode集群]
  ├── DataNode1: Block1(副本1), Block5(副本2)
  ├── DataNode2: Block1(副本2), Block2(副本1)
  └── DataNode3: Block2(副本2), Block3(副本1)

HDFS默认:
  - 块大小:128MB(适合大文件)
  - 副本数:3(本机架1份+另一机架2份)
  - NameNode单点问题 → 用HA NameNode解决

实战代码/设计图/模板

MinIO 自建对象存储

# 单节点启动(测试环境)
docker run -d \
  --name minio \
  -p 9000:9000 \
  -p 9090:9090 \
  -v /data/minio:/data \
  -e MINIO_ROOT_USER=admin \
  -e MINIO_ROOT_PASSWORD=password123 \
  minio/minio server /data --console-address ":9090"

# 多节点分布式模式(生产环境)
# 在4个节点上运行:
MINIO_ROOT_USER=admin MINIO_ROOT_PASSWORD=password123 \
minio server \
  http://node{1...4}/data{1...2} \
  --console-address ":9090"

Python 操作 MinIO/S3

import boto3
from botocore.exceptions import ClientError
import os

class BioStorage:
    """生信数据存储客户端(兼容MinIO和S3)"""

    def __init__(self, endpoint_url=None):
        self.s3 = boto3.client(
            's3',
            endpoint_url=endpoint_url or os.getenv('S3_ENDPOINT'),
            aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID'),
            aws_secret_access_key=os.getenv('AWS_SECRET_ACCESS_KEY')
        )
        self.bucket = os.getenv('S3_BUCKET', 'bioinf-data')

    def upload_large_file(self, local_path: str, s3_key: str):
        """
        分片上传大文件(支持断点续传)
        适合FASTQ/BAM等大文件
        """
        # 使用S3 Transfer管理器,自动分片
        from boto3.s3.transfer import TransferConfig
        config = TransferConfig(
            multipart_threshold=1024*1024*100,  # 100MB以上用分片
            max_concurrency=10,                  # 10个并发上传
            multipart_chunksize=1024*1024*100    # 每片100MB
        )

        self.s3.upload_file(
            local_path,
            self.bucket,
            s3_key,
            Config=config,
            ExtraArgs={'StorageClass': 'STANDARD'}
        )
        print(f"上传完成: {s3_key}")

    def download_file(self, s3_key: str, local_path: str):
        """下载文件"""
        try:
            self.s3.download_file(self.bucket, s3_key, local_path)
        except ClientError as e:
            if e.response['Error']['Code'] == '404':
                raise FileNotFoundError(f"文件不存在: {s3_key}")
            raise

    def generate_presigned_url(self, s3_key: str, expiry=3600) -> str:
        """
        生成临时下载链接(无需登录即可下载)
        expiry:链接有效期(秒),默认1小时
        """
        url = self.s3.generate_presigned_url(
            'get_object',
            Params={'Bucket': self.bucket, 'Key': s3_key},
            ExpiresIn=expiry
        )
        return url

    def list_files(self, prefix: str) -> list:
        """列出指定前缀下的所有文件"""
        paginator = self.s3.get_paginator('list_objects_v2')
        files = []
        for page in paginator.paginate(Bucket=self.bucket, Prefix=prefix):
            files.extend(page.get('Contents', []))
        return [f['Key'] for f in files]

# 使用示例
storage = BioStorage(endpoint_url='http://minio:9000')
storage.upload_large_file('/data/sample1_R1.fastq.gz', 'project1/sample1/R1.fastq.gz')
url = storage.generate_presigned_url('project1/sample1/R1.fastq.gz', expiry=7200)
print(f"下载链接(2小时内有效): {url}")

HDFS 常用操作

# 创建目录
hdfs dfs -mkdir -p /bioinf/project1/raw

# 上传文件
hdfs dfs -put sample1_R1.fastq.gz /bioinf/project1/raw/

# 查看文件
hdfs dfs -ls /bioinf/project1/raw/

# 查看文件大小
hdfs dfs -du -h /bioinf/project1/

# 下载文件
hdfs dfs -get /bioinf/project1/raw/sample1_R1.fastq.gz ./

# 查看文件块信息
hdfs fsck /bioinf/project1/raw/sample1.bam -files -blocks -locations

# 检查集群状态
hdfs dfsadmin -report

面试常问点

问题参考答案
如何防止数据丢失?3副本策略,跨机架分布
生信用HDFS还是S3?云上用S3,HPC集群用GPFS/Lustre
如何处理小文件问题?合并小文件,HDFS对小文件低效
如何实现断点续传?分片上传,记录已传分片
对象存储 vs 文件系统?对象存储不支持随机写,适合一次写多次读

速查表

存储选型决策树:
  需要POSIX接口? → 并行文件系统(Lustre/GPFS)
  需要S3兼容?   → MinIO(私有)或AWS S3(公有云)
  Hadoop生态?   → HDFS
  简单对象存储?  → MinIO,部署简单

常见目录结构:
  /projects/{project_id}/
    raw/           # 原始FASTQ
    aligned/       # BAM文件
    variants/      # VCF文件
    results/       # 最终结果
    reports/       # HTML/PDF报告
    logs/          # 运行日志