Files
markbase/docs/ISCSI_USERSPACE_FEASIBILITY.md
2026-05-18 17:02:30 +08:00

25 KiB
Raw Permalink Blame History

Userspace iSCSI Target 开发可行性研究

文档概述

创建时间: 2026-05-17 04:15
版本: 1.0
研究目的: 评估在MarkBase项目中使用Rust实现userspace iSCSI Target的技术可行性


核心结论

可行性评级: ★★★☆☆ (中等可行)

主要发现:

  1. iSCSI协议完全可以在userspace实现已有成功案例
  2. Rust已有iSCSI initiator实现iscsi-client-rs
  3. ⚠️ macOS缺少内核级iSCSI initiator需第三方工具
  4. ⚠️ 性能瓶颈在TCP处理和SCSI命令解析userspace开销~15-20%
  5. 无现成Rust iSCSI Target库需自行开发

iSCSI架构基础

1. iSCSI协议栈

┌─────────────────────────────────────┐
│  Application Layer                  │
│  ├─ SCSI Commands (READ/WRITE)      │ ← MarkBase文件系统
│  ├─ LUN Mapping                     │ ← SQLite node_id映射
│  └─ Lock Management                 │ ← WebDAV LOCK补充
└─────────────────────────────────────┘
           ↓ SCSI CDB封装
┌─────────────────────────────────────┐
│  iSCSI Protocol Layer               │
│  ├─ PDU (Protocol Data Unit)        │ ← RFC 7143标准
│  ├─ Login/Logout Phase              │ ← CHAP认证
│  ├─ Text Negotiation                │ ← 参数协商
│  └─ Error Recovery (ERL0/1/2)       │ ← 断线重连
└─────────────────────────────────────┘
           ↓ TCP/IP封装
┌─────────────────────────────────────┐
│  Transport Layer                    │
│  ├─ TCP连接管理                     │ ← Tokio async TCP
│  ├─ CRC32C校验                      │ ← Header/Data Digest
│  └─ Flow Control                    │ ← MaxBurstLength限制
└─────────────────────────────────────┘

2. Initiator vs Target对比

角色 功能 实现位置 MarkBase需求
Initiator(客户端) 发起SCSI命令 macOS Finder 需第三方工具
Target(服务端) 响应SCSI命令 MarkBase Server 需自行开发

关键认知:

  • iSCSI协议本身是双向的但角色固定
  • Initiator连接Target请求LUN访问
  • Target提供LUN响应读写请求
  • MarkBase需实现Target角色服务端

现有实现调研

1. Rust生态现状

项目名称 类型 成熟度 许可证 适用性
iscsi-client-rs Initiator ★★★☆☆ AGPL-3.0 仅参考
scst Target Interface ★★☆☆☆ MIT/Apache Linux内核依赖
vhost-device-scsi SCSI Backend ★☆☆☆☆ 未知 虚拟化场景

iscsi-client-rs分析:

关键发现: Rust生态缺少Target实现需从零开发

2. C/C++生态调研

项目名称 类型 成熟度 许可证 借鉴价值
libiscsi Initiator ★★★★★ LGPL-2.1/GPL-2.0 协议参考
LIO-Target Kernel Target ★★★★★ GPL-2.0 Linux内核实现
SCST Kernel Target ★★★★☆ GPL-2.0 性能基准
TGT Userspace Target ★★★☆☆ GPL-2.0 可借鉴

libiscsi关键特性:

  • GitHub: https://github.com/sahlberg/libiscsi (214 stars)
  • 支持: Linux, FreeBSD, Windows, macOS
  • 特性: CHAP认证, Header/Data Digest, IPv6
  • 用途: 作为Initiator实现参考client端

TGTUserspace Target案例:

  • 项目: https://github.com/fujita/tgt
  • 特点: 纯userspace实现无需内核模块
  • 性能: 相比kernel target降低~15-20%
  • 优势: 可移植性强,调试简单
  • 结论: TGT证明userspace Target可行

3. macOS平台特殊性

特性 Linux macOS 影响
内核Initiator 内置 无原生支持 需第三方工具
内核Target LIO/SCST 无原生支持 只能userspace
SCSI Pass-through sg_io ⚠️ 需IOKit Block设备访问受限
性能优化 DMA/TOE ⚠️ 仅TCP优化 吞吐上限受限

macOS iSCSI Initiator工具:

  • XTechSAN: 商业软件($49.95
  • GlobalSAN: 商业软件($24.95
  • libiscsi: 开源库(需编译)
  • 建议: 使用libiscsi作为Initiator基础

技术可行性分析

1. 协议实现难度

1.1 iSCSI PDU解析难度: ★★★☆☆)

RFC 7143核心结构:

// Basic Header Segment (BHS) - 48字节固定头部
struct BHS {
    opcode: u8,           // 操作码0x00-0x3F
    flags: u8,            // Final/Status/Reserved
    bytes_2_3: [u8; 2],   // 依赖opcode的字段
    total_length: u32,    // 总长度含AHS+Data
    logical_offset: u32,  // 数据偏移
    lun: u64,             // Logical Unit Number
    itt: u32,             // Initiator Task Tag
    bytes_24_47: [u8; 24], // 依赖opcode的字段
}

关键PDU类型:

Opcode 名称 用途 实现难度
0x00 NOP-Out 心跳检测 ★☆☆☆☆
0x01 SCSI Command 读写命令 ★★★★☆
0x02 SCSI Response 命令响应 ★★★☆☆
0x03 Login Request 登录请求 ★★★★★
0x04 Login Response 登录响应 ★★★★★
0x05 Text Request 参数协商 ★★★☆☆
0x06 Text Response 参数响应 ★★★☆☆
0x07 Data-Out 数据上传 ★★☆☆☆
0x08 Data-In 数据下载 ★★☆☆☆
0x09 Logout Request 断开请求 ★☆☆☆☆
0x0A Logout Response 断开响应 ★☆☆☆☆
0x1C Ready to Transfer R2T通知 ★★☆☆☆

实现建议:

// 使用iscsi-client-rs的PDU解析逻辑作为参考
use iscsi_client_rs::models::pdu::{Pdu, BHS};

// 自定义Target实现
struct MarkBaseTarget {
    lun_map: HashMap<u64, FileNode>,  // LUN → SQLite node_id
    sessions: HashMap<u32, Session>,  // ITT → Session状态
}

1.2 Login Phase实现难度: ★★★★★)

标准流程:

1. Security Negotiation Phase
   ├─ Initiator: Login Request (Stage 0)
   ├─ Target:    Login Response (Stage 0)
   ├─ CHAP认证可选
   └─ 判断是否继续

2. Operational Negotiation Phase
   ├─ Initiator: Login Request (Stage 1)
   ├─ Target:    Login Response (Stage 1)
   ├─ 协商参数MaxBurstLength, FirstBurstLength
   └─ 判断是否继续

3. Full Feature Phase
   ├─ Initiator: Login Request (Final Stage)
   ├─ Target:    Login Response (Status=Success)
   └─ 进入正常操作

关键参数协商:

参数名 用途 默认值 影响
MaxRecvDataSegmentLength 单次最大接收数据 65536 缓冲区大小
MaxBurstLength 单次最大突发数据 262144 吞吐瓶颈
FirstBurstLength 首次突发数据 65536 优化机会
InitialR2T 是否立即R2T Yes 写入流程
ImmediateData 是否立即数据 No 写入流程
HeaderDigest 头部校验 None/CRC32C CPU开销
DataDigest 数据校验 None/CRC32C CPU开销

实现难点:

  • CHAP认证需MD5计算可能被暴力破解
  • 参数协商需严格遵守RFC 7143规则
  • Session状态管理TSIH, CID, ITT计数器

1.3 SCSI命令处理难度: ★★★★☆)

SCSI CDB解析:

// READ(10) CDB示例
struct Read10CDB {
    opcode: u8,         // 0x28
    flags: u8,          // FUA/DPO/Protect
    lba: u32,           // Logical Block Address
    group: u8,          // Group Number
    transfer_length: u16, // 块数量
    control: u8,        // Control Byte
}

// WRITE(10) CDB示例
struct Write10CDB {
    opcode: u8,         // 0x2A
    flags: u8,
    lba: u32,
    group: u8,
    transfer_length: u16,
    control: u8,
}

关键SCSI命令:

Opcode 名称 用途 实现难度
0x00 TEST UNIT READY 设备检查 ★☆☆☆☆
0x03 REQUEST SENSE 错误查询 ★★☆☆☆
0x04 FORMAT UNIT 格式化 ★☆☆☆☆
0x12 INQUIRY 设备信息 ★★☆☆☆
0x1A MODE SENSE 模式查询 ★★☆☆☆
0x25 READ CAPACITY 容量查询 ★★☆☆☆
0x28 READ(10) 读取数据 ★★★★☆
0x2A WRITE(10) 写入数据 ★★★★☆
0x5A MODE SENSE(10) 扩展模式查询 ★★☆☆☆
0x88 READ(16) 扩展读取 ★★★★☆
0x8A WRITE(16) 扩展写入 ★★★★☆
0x9E SERVICE ACTION IN 扩展服务 ★★★☆☆

LUN映射设计:

// MarkBase特色SQLite node_id映射为LUN
struct LunMapping {
    lun_id: u64,              // iSCSI LUN例如1 << 48
    node_id: String,          // SQLite file_nodes.node_id
    block_size: u32,          // 块大小例如4096
    total_blocks: u64,        // 总块数(文件大小/块大小)
}

// 实现示例
impl MarkBaseTarget {
    fn handle_read10(&self, cdb: Read10CDB, lun: u64) -> Vec<u8> {
        let mapping = self.lun_map.get(&lun).unwrap();
        let offset = cdb.lba * mapping.block_size;
        let length = cdb.transfer_length * mapping.block_size;
        
        // 从SQLite查询文件路径
        let file_path = self.db.query_path(&mapping.node_id);
        
        // 读取文件内容
        let data = File::open(file_path)?
            .read_at(offset, length)?;
        
        data
    }
}

2. 性能瓶颈分析

2.1 Userspace开销

瓶颈点 开销估算 优化方案
TCP连接管理 ~5% Tokio async + Zero-copy
PDU解析 ~8% SIMD CRC32C计算
SCSI CDB解析 ~3% 静态解析优化
SQLite查询 ~10% 缓存node_id → path映射
文件读取 ~4% Direct I/O绕过kernel cache
总开销 ~30% 无法完全消除

对比Kernel Target性能:

  • LIO-Target: ~1500 MB/sDMA直接传输
  • TGT Userspace: ~1200 MB/s20%性能损失)
  • MarkBase预估: ~800 MB/sSQLite查询开销

2.2 macOS平台限制

限制 影响 解决方案
无DMA支持 无法Zero-copy 使用mmap优化
IOKit复杂性 Block设备访问受限 文件模拟Block设备
TCP栈优化有限 网络吞吐上限 启用TCP_NODELAY
缺少SCSI内核模块 性能上限固定 纯userspace实现

3. 开发工作量估算

模块 工作量 难度 依赖
PDU解析/构建 3000行代码 ★★★★☆ RFC 7143文档
Login Phase 2000行代码 ★★★★★ CHAP MD5库
Session管理 1500行代码 ★★★☆☆ Tokio async
SCSI命令处理 4000行代码 ★★★★☆ SCSI标准文档
LUN映射 2000行代码 ★★★☆☆ SQLite集成
错误恢复 1000行代码 ★★★☆☆ ERL0/1/2规范
测试覆盖 3000行代码 ★★★☆☆ libiscsi test-tool参考
文档编写 1000行文档 ★★☆☆☆ RFC文档整理
总计 ~16500行代码 ★★★★☆ 6-8周开发周期

实施方案对比

方案A: 纯Userspace Target推荐

架构设计:

┌─────────────────────────────────────┐
│  MarkBase iSCSI Target (Userspace)  │
│  ├─ TCP Server (Tokio)              │ ← 监听3260端口
│  ├─ PDU Parser                      │ ← RFC 7143实现
│  ├─ Session Manager                 │ ← ITT/TSIH/CID管理
│  ├─ SCSI Handler                    │ ← READ/WRITE响应
│  ├─ LUN Mapper                      │ ← SQLite node_id映射
│  └─ File Backend                    │ ← 读写实际文件
└─────────────────────────────────────┘
           ↓ TCP/IP
┌─────────────────────────────────────┐
│  macOS Initiator (第三方工具)        │
│  ├─ XTechSAN                        │ ← 商业软件
│  ├─ GlobalSAN                       │ ← 商业软件
│  └─ libiscsi CLI                    │ ← 开源工具
└─────────────────────────────────────┘

优势分析:

  • 完全userspace实现无需kernel模块
  • 可移植性强Linux/macOS/Windows
  • 调试简单标准Rust工具
  • 与WebDAV并行运行双协议支持
  • 可直接访问SQLite数据库

劣势分析:

  • ⚠️ 性能损失~20%相比kernel target
  • ⚠️ macOS需第三方Initiator工具
  • ⚠️ 开发周期长6-8周
  • ⚠️ 无现成Rust库需从零开发

适用场景: 文档协作、中等规模文件传输

方案B: WebDAV + NFS混合备选

架构设计:

┌─────────────────────────────────────┐
│  macOS Finder                       │
│  ├─ 文件锁WebDAV                   │ ← HTTP LOCK
│  ├─ 文件传输NFS                    │ ← TCP NFS
│  └─ 统一锁数据库                    │ ← SQLite共享
└─────────────────────────────────────┘
           ↓ 双协议
┌─────────────────────────────────────┐
│  MarkBase Server                    │
│  ├─ WebDAV Server (4919端口)        │ ← 已实现
│  ├─ NFS Server (2049端口)           │ ← 待实现
│  └─ SQLite锁数据库                  │ ← 共享LockManager
└─────────────────────────────────────┘

优势分析:

  • NFS性能优于HTTP~800 MB/s vs ~600 MB/s
  • Finder原生支持NFS无需第三方工具
  • 开发周期短2-3周
  • 有现成Rust NFS库nfs3_client_rs

劣势分析:

  • ⚠️ macOS NFS客户端稳定性问题
  • ⚠️ NFS需root权限配置/etc/exports
  • ⚠️ 用户需手动挂载NFS操作复杂度+
  • ⚠️ NFS锁机制不同NLM vs WebDAV LOCK

适用场景: 专业视频工作室、愿意手动配置的用户

方案C: HTTP/2优化快速方案

架构设计:

┌─────────────────────────────────────┐
│  macOS Finder                       │
│  └─ WebDAV (HTTP/2)                 │ ← 单一协议
└─────────────────────────────────────┘
           ↓ HTTP/2
┌─────────────────────────────────────┐
│  MarkBase WebDAV Server             │
│  ├─ HTTP/2多路复用                  │ ← Axum升级
│  ├─ Zero-copy传输                   │ ← sendfile优化
│  ├─ 异步锁查询                      │ ← 已实现
│  └─ RAID 5存储                      │ ← 已实现
└─────────────────────────────────────┘

优势分析:

  • 开发周期最短1周
  • 用户体验最优(无需额外配置)
  • 实现难度最低仅Axum升级
  • 维护成本最低(单一协议栈)
  • 性能提升显著600 → 1000 MB/s

劣势分析:

  • ⚠️ 性能仍有上限相比iSCSI Block传输
  • ⚠️ HTTP开销无法完全消除~15%
  • ⚠️ 不支持专业视频软件需Block-level访问

适用场景: 文档协作、小规模团队


决策矩阵

评估维度 方案A (iSCSI) 方案B (NFS混合) 方案C (HTTP/2优化) 权重
性能提升 +100% (800 MB/s) +33% (800 MB/s) +67% (1000 MB/s) 30%
用户体验 ★★☆☆☆ (需第三方工具) ★★☆☆☆ (需手动挂载) ★★★★★ (无额外配置) 25%
开发难度 ★★★★★ (6-8周) ★★★☆☆ (2-3周) ★★☆☆☆ (1周) 20%
维护成本 ★★☆☆☆ (复杂协议) ★★★☆☆ (双协议) ★★★★★ (单协议) 15%
扩展性 ★★★★☆ (Block-level) ★★★☆☆ (文件级) ★★☆☆☆ (HTTP限制) 10%
总分 3.5/5.0 3.2/5.0 4.5/5.0 100%

推荐方案: 方案CHTTP/2优化 → 方案BNFS混合 → 方案AiSCSI Target

理由:

  1. 方案C性价比最高短期收益快
  2. 方案B适用于专业用户中期扩展
  3. 方案A适合长期战略Block-level访问

技术路线图

Phase 1: HTTP/2优化Day 1-7

  • 升级Axum到HTTP/2版本
  • 实现Zero-copy传输
  • 性能测试验证
  • 用户文档更新

Phase 2: NFS并行服务Day 8-21

  • 实现NFS Server原型
  • SQLite锁数据库共享
  • macOS Finder兼容性测试
  • 部署文档编写

Phase 3: iSCSI Target研究Day 22-35

  • RFC 7143协议深度学习
  • TGT源码分析
  • 原型实现PDU解析
  • 性能基准测试

Phase 4: iSCSI Target开发Day 36-60

  • Login Phase实现
  • SCSI命令处理
  • LUN映射集成
  • 错误恢复机制
  • 测试覆盖(单元/集成)

Phase 5: 生产部署Day 61-70

  • 第三方Initiator集成测试
  • 多用户并发测试
  • 性能优化调优
  • 用户培训材料

风险评估

技术风险

风险项 概率 影响 缓解措施
PDU解析错误 参考libiscsi实现严格RFC验证
Session状态混乱 使用Tokio async lock仔细状态管理
性能不达标 启用Zero-copy优化SQLite查询
macOS Initiator兼容性 测试XTechSAN/GlobalSAN准备libiscsi备选
CHAP认证破解 使用强密码,定期更新密钥

业务风险

风险项 概率 影响 缓解措施
开发周期延期 分阶段交付优先HTTP/2方案
用户配置复杂 提供自动化脚本,详细文档
维护成本上升 代码模块化,自动化测试
竞品对比劣势 强调WebDAV优势差异化定位

开发资源需求

人力需求

角色 技能要求 工作量 优先级
Rust开发工程师 iSCSI协议熟悉 6-8周 必须
测试工程师 自动化测试 2-3周 必须
文档工程师 技术文档 1-2周 可选
UI设计师 用户界面(可选) 1周 可选

技术资源

资源 用途 获取方式
RFC 7143文档 协议规范 https://datatracker.ietf.org/doc/html/rfc7143
libiscsi源码 协议参考 https://github.com/sahlberg/libiscsi
TGT源码 Target实现参考 https://github.com/fujita/tgt
iscsi-client-rs Rust参考 https://github.com/Masorubka1/iscsI-client-rs
SCSI标准文档 命令规范 https://www.t10.org/
XTechSAN/GlobalSAN macOS Initiator 商业软件(需购买)

硬件资源

设备 用途 成本
M4 Mac mini 开发环境 已有
RAID测试盘 性能测试 已有sparseimage
macOS Initiator软件 测试 ~$50XTechSAN
网络测试工具 吞吐测试 免费AJA System Test

附录A: iSCSI协议关键参数

RFC 7143核心参数表

参数名 类型 范围 默认值 协商规则
MaxRecvDataSegmentLength Number 512-16777215 65536 双方最小值
MaxBurstLength Number 512-16777215 262144 双方最小值
FirstBurstLength Number 512-16777215 65536 双方最小值
InitialR2T Boolean Yes/No Yes 双方AND
ImmediateData Boolean Yes/No No 双方AND
DataPDUInOrder Boolean Yes/No Yes 双方AND
DataSequenceInOrder Boolean Yes/No Yes 双方AND
ErrorRecoveryLevel Number 0-2 0 双方最小值
HeaderDigest Text None/CRC32C None 双方共同支持
DataDigest Text None/CRC32C None 双方共同支持
MaxConnections Number 1-65535 1 双方最小值
TargetPortalGroupTag Number 0-65535 1 Target指定

参数协商示例

Initiator → Target:

HeaderDigest=None,CRC32C
DataDigest=None
MaxRecvDataSegmentLength=131072
InitialR2T=Yes
ImmediateData=No
MaxBurstLength=262144
FirstBurstLength=65536

Target → Initiator:

HeaderDigest=CRC32C
DataDigest=None
MaxRecvDataSegmentLength=65536
InitialR2T=Yes
ImmediateData=No
MaxBurstLength=262144
FirstBurstLength=65536

最终协商结果:

  • HeaderDigest = CRC32C双方支持
  • DataDigest = NoneInitiator不支持CRC32C
  • MaxRecvDataSegmentLength = 65536取最小值

附录B: SCSI命令实现示例

READ(10)实现

use std::fs::File;
use std::io::Read;

impl MarkBaseTarget {
    pub fn handle_read10(
        &self,
        lun: u64,
        cdb: Read10CDB,
    ) -> Result<Vec<u8>, ScsiError> {
        // 1. 检查LUN有效性
        let mapping = self.lun_map.get(&lun)
            .ok_or(ScsiError::InvalidLun)?
        
        // 2. 检查LBA范围
        let max_lba = mapping.total_blocks - 1;
        if cdb.lba > max_lba {
            return Err(ScsiError::IllegalBlockAddress);
        }
        
        // 3. 计算读取范围
        let start_offset = cdb.lba * mapping.block_size;
        let transfer_bytes = cdb.transfer_length * mapping.block_size;
        
        // 4. 检查文件大小
        let file_size = File::open(&mapping.file_path)?
            .metadata()?
            .len();
        if start_offset + transfer_bytes > file_size {
            return Err(ScsiError::IllegalBlockAddress);
        }
        
        // 5. 读取数据
        let mut file = File::open(&mapping.file_path)?;
        file.seek(SeekFrom::Start(start_offset))?;
        let mut buffer = vec![0u8; transfer_bytes];
        file.read_exact(&mut buffer)?;
        
        Ok(buffer)
    }
}

WRITE(10)实现

use std::fs::File;
use std::io::Write;

impl MarkBaseTarget {
    pub fn handle_write10(
        &self,
        lun: u64,
        cdb: Write10CDB,
        data: Vec<u8>,
    ) -> Result<(), ScsiError> {
        // 1-4步同READ(10)
        
        // 5. 写入数据
        let mut file = File::create(&mapping.file_path)?;
        file.seek(SeekFrom::Start(start_offset))?;
        file.write_all(&data)?;
        file.flush()?;
        
        // 6. 更新SQLite可选
        self.db.update_file_size(&mapping.node_id, file_size);
        
        Ok(())
    }
}

附录C: macOS Initiator工具对比

工具 类型 价格 优势 劣势 推荐指数
XTechSAN 商业软件 $49.95 稳定、官方支持 昂贵 ★★★☆☆
GlobalSAN 商业软件 $24.95 便宜、稳定 功能有限 ★★★★☆
libiscsi CLI 开源库 免费 灵活、可编程 需手动编译 ★★☆☆☆
自制Initiator 自行开发 免费 完全控制 开发成本高 ★☆☆☆☆

推荐选择: GlobalSAN性价比最佳或 libiscsi CLI开发测试


总结建议

短期策略1-2周

  1. 优先实施HTTP/2优化方案C
  2. 性能基准测试目标1000 MB/s
  3. 用户文档更新强调WebDAV优势

中期策略1个月

  1. NFS并行服务原型方案B
  2. 多用户并发测试10 users
  3. macOS兼容性验证

长期策略2-3个月

  1. ⚠️ iSCSI Target原型开发方案A
  2. ⚠️ SCSI命令完整实现
  3. ⚠️ 第三方Initiator集成测试

最终建议

不推荐立即开发iSCSI Target,原因:

  1. 性能收益有限800 vs 1000 MB/sHTTP/2已接近
  2. 开发成本高昂6-8周16500行代码
  3. macOS用户体验差需第三方工具
  4. 维护复杂度高(双协议栈)

推荐路径:

  • 第一步: HTTP/2优化立即可行1周完成
  • 第二步: NFS混合方案中期扩展2-3周
  • 第三步: 根据用户反馈决定是否开发iSCSI Target

如果必须实现iSCSI:

  • 优先参考TGT源码userspace实现
  • 使用libiscsi作为协议测试工具
  • 预留6-8周开发周期
  • 准备GlobalSAN作为macOS Initiator备选

文档状态: 已完成
下一步: 执行HTTP/2优化方案Phase 1
负责人: MarkBase开发团队
更新日志: 2026-05-17 初版创建