拒绝硬盘静默错误,SPDK保护你的数据

作者简介

刘长鹏,资深存储工程师, 主要研究方向为虚拟化,新存储介质应用,负责SPDK开发和社区维护。

2018年某公有云厂商因为硬盘固件版本bug引起的硬盘静默错误致使文件系统元数据损坏,导致用户数据丢失,一度引起了热烈的讨论。

静默错误就是因为硬盘的潜在故障而导致的数据写入和读出不一致,在这个过程中,用户无法从任何一个方面得到通知或者异常报告。如果用户层(例如文件系统) 没有实现读写数据校验就会很难发现这样的错误。

既然硬盘因为硬件错误,固件bug,供电温度等原因的影响会导致静默错误的出现,那么对用户来讲有没有一种可以主动的检测到这样的静默错误的手段呢?

T10标准组织就定义了 DIF (Data Integrity Field) 和DIX (Data Integrity Extensions) 这两种标准,可以给用户提供一种端到端的数据保护方式,下面我们先来看一下DIF:

640?wx_fmt=png

图1:512 + 8 DIF格式

可以看到在硬盘512字节的数据区后面跟了一个连续的8字节数据,该8字节数据被定义为PI (Protection Information):

640?wx_fmt=png

图2:Protection Information定义

Guard:2 Bytes,保存数据块CRC16校验值,按照图1例子就是512字节数据区的CRC16校验值,适用所有的Type;

Reference Tag:4 Bytes,主要用来保护Misdirected Writes,Misdirected Write指的是目标LBA和实际写入的LBA不一致。Type1时保存目标Logical Block Address的低32Bit;当使用Type2时按照数据块单位递增,例如一个4KB的写命令包含8个扇区和8个PI,每个PI区域的Reference Tag按照初始LBA递增;

Application Tag:2 Bytes,顾名思义由应用程序自己填写;

标准组织还定义了三种数据保护Type:

Type1:Guard + Reference Tag,reference tag是该命令所指向的LBA低32地址;

Type2:Guard + Reference Tag,reference tag单位递增;

Type3:Guard;

这里在介绍下DIF和DIX的区别,DIF的PI信息是直接跟到数据后面,用户数据和PI共享一个数据buffer,而DIX的PI是一个单独的buffer,也就是说用户需要提供2个独立的buffer,一个是数据一个存放PI信息,假设硬盘block size是512字节,在PI使能时,存取8个block时,DIF需要申请(512+8) * 8字节的Buffer,而DIX需要申请512 * 8的数据Buffer以及 8 * 8的PI Buffer。

640?wx_fmt=jpeg

图3:DIF vs DIX

SPDK目前提供了比较全面的针对DIF的软件支持,包括DIF/DIX Library以及iSCSI target和NVMoF target端到端的DIF数据保护。这里提到了软件支持,因为在硬盘层面,比如Intel NVMe SSD都对DIF提供了全面的硬件支持,用户也可以直接利用该硬件特性保护自己的数据,如果需要直接利用NVMe硬件特性支持DIF,可以使用SPDK提供的NVMe存取API,如:spdk_nvme_ns_cmd_write/read_with_md,

详细信息请参见(https://spdk.io/doc/nvme.html#nvme_interface)。

下面我们看下SPDK提供的软件API如何实现数据的端到端保护的,下面看下常用的使用方法:

1. 用户无感知 :使用SPDK block API无论读写都可以按照之前的512 Bytes对齐的方式组织数据,SPDK自动在写操作(Write_Insert)时添加8字节Protection Information,并且在读操作(Read_Strip_Verify)时丢弃掉多余的8字节信息;当在读取之前写入的数据时出现CRC校验失败或者Reference Tag失效时,该读命令会返回给用户IOERR错误码,并提供详细的错误信息;

640?wx_fmt=jpeg

图4:PI Write_Insert和Read_Strip_Verify

2. 用户感知:数据和额外的Protection Information区域都由用户提供,SPDK只负责填充PI和校验PI;同样的当检测出数据不一致时,SPDK会返回IOERR给用户;

640?wx_fmt=jpeg

图5:PI Write_Fill和Read_Verify

有了以上两种方式的数据保护,硬盘的任何静默错误都会被通知到用户。当然需要明确的无论是DIF还是DIX仅是检测手段,这两种方法并不能用来恢复数据,用户收到IOERR的错误码需要自行添加对该错误的容错机制,例如软件的RAID或者用户本身就是分布式文件系统。

SPDK 端到端数据保护模块:

DIF Library: lib/util/dif.c,提供基本的DIF/DIX API调用,包括DIF/DIX Insert/Strip/Verify,并且支持Scatter-Gather List数据Buffer;

Intel ISA-L:提供高效的CRC16指令优化算法;

BDEV Layer:块层API抽象,iSCSI/NVMoF Target可以直接使用;

NVMe Bdev Module:数据存储层,用户也可以直接使用NVMe接口提供的DIF/DIX API;

iSCSI Target和NVMeoF Target:调用Bdev提供的API可以实现Write Insert以及Read Strip以及Read Verify功能;

Util:SPDK Perf tool和SPDK Fio plugin,用户可以用来进行DIF/DIX功能和性能评估;

下面我们看下在SPDK Full Stack下使用端到端数据保护DIF的示例,iSCSI的示例中在远端的Host测是不感知DIF存在的,而在NVMoF的示例中,Host端是感知的,但是Host端可以选择不填充任何数据到DIF字段,由SPDK Target测进行计算和校验。

640?wx_fmt=jpeg

图6:SPDK NVMoF和iSCSI Target使DIF使用示例 

SPDK本身作为软件层并不会保存数据的PI信息,这里要求后端的硬盘能够提供支持类似512+8或者4096+64等格式的硬件特性,Intel NVMe全系企业级硬盘均可支持到这种可变长度的数据存储格式。

640?wx_fmt=jpeg

 推荐阅读 

640?wx_fmt=jpeg

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SPDK(存储性能开发套件)官方文档中文版。 第一章 简介 1 1.1.什么是SPDK? 1 1.2.入门 1 1.3. Vagrant开发环境 3 1.4.更新日志(略) 6 第二章 概念 6 2.1. 用户空间驱动程序** 6 2.2. 来自用户空间的DMA** 7 2.3. 消息传递和并发** 9 2.4. NAND Flash SSD内部 13 2.5. 将I / O提交到NVMe设备** 15 2.5.1 NVMe规范 15 2.5.2 SPDK NVMe驱动程序I / O路径 15 2.6. 使用Vhost-user进行虚拟化I / O. 16 2.6.1 介绍 16 2.6.2 QEMU 17 2.6.3 设备初始化 18 2.6.4 I / O路径 19 2.6.5 SPDK优化 20 2.7. SPDK目录结构概述 20 2.8. SPDK移植指南 22 第三章 用户指南 22 3.1. 系统配置用户指南 22 3.1.1 IOMMU配置 22 3.2. SPDK应用程序概述 23 3.2.1 配置SPDK应用程序 23 3.3. iSCSI Target 26 3.3.1. iSCSI Target入门指南 26 3.3.2. 通过配置文件配置iSCSI Target 27 3.3.3. 通过RPC方法配置iSCSI Target 28 3.3.4. 配置iSCSI启动器 29 3.3.5. rpc配置示例*** 30 3.3.6. iSCSI 热插拔 32 3.4. NVMe over Fabrics Target 32 3.5. Vhost Target(略) 37 3.6 块设备用户指南 38 3.6.1 bdev介绍 38 3.6.2 通用RPC命令 38 3.6.3 Ceph RBD 39 3.6.4 压缩虚拟Bdev模块 40 3.6.5 加密虚拟Bdev模块 41 3.6.6 延迟vbdev模块 41 3.6.7 GPT(GUID分区表) 42 3.6.8 iSCSI bdev 43 3.6.9 Linux AIO bdev 43 3.6.10 OCF虚拟bdev 43 3.6.11 Malloc bdev 44 3.6.12 NULL bdev 44 3.6.13 NVMe bdev 44 3.6.14 逻辑卷Lvol 45 3.6.15 RAID 46 3.6.16 Passthru 46 3.6.17 Pmem 46 3.6.18 Virtio Block 47 3.6.19 Virtio SCSI 47 3.7 BlobFS(Blobstore文件系统) 48 3.7.1 RocksDB集成 48 3.7.2 FUSE插件 49 3.8 JSON-RPC方法(略) 49 第四章 程序员指南 49 4.1. Blobstore程序员指南 49 4.1.1 介绍 50 4.1.2 运作理论 50 4.1.3 设计注意事项 52 4.1.4 例子 54 4.1.5配置 54 4.1.6 组件细节 54 4.2. 块设备层编程指南 56 4.3 编写自定义块设备模块 58 4.3.1 介绍 58 4.3.2 创建一个新模块 59 4.3.3创建虚拟Bdev 60 4.4 NVMe over Fabrics目标编程指南 61 4.4.1 介绍 61 4.4.2 原语结构体 61 4.4.3 基础函数 62 4.4.4访问控制 62 4.4.5发现子系统 62 4.4.6 传输 63 4.4.7选择线程模型 63 4.4.8 跨CPU核心扩展 63 4.4.9 零拷贝支持 63 4.4.10 RDMA 63 4.5 Flash传输层 64 4.5.1 术语 64 4.5.2 使用方法 67 4.6 GDB宏用户指南 69 4.6.1 介绍 69 4.6.2 加载gdb宏 71 4.6.3 使用gdb数据目录 72 4.6.4 使用.gdbinit加载宏 72 4.6.5 为什么我们需要显式调用spdk_load_macros 72 4.6.6 以上可用的宏总结 73 4.6.7 添加新宏 73 4.7 SPDK “Reduce”块压缩算法 73 4.7.1 介绍 73 4.7.2 例子 74 4.8 通知库 78 第五章 基本信息 79 5.1 事件框架 79 5.1.1 事件框架设计注意事项 80 5.1.2 SPDK事件框架组件 80 5.1.3 应用框架 80 5.2 逻辑卷 81 5.2.1 术语 81 5.2.2 配置逻辑卷 84 5.3 矢量数据包处理(略) 86 第六章 杂项 86 6.1 介绍 86 6.2 NVMe的P2P API 86 6.3 确定设备支持 87 6.4 P2P问题 87 第七章 驱动程序 88 7.1 NVMe驱动程序*** 88 7.1.1 介绍 88 7.1.2 例子 88 7.1.3 公共接口 89 7.1.4 NVMe驱动程序设计 89 7.1.5 NVMe over Fabrics主机支持 91 7.1.6 NVMe多进程 91 7.1.7 NVMe Hotplug 92 7.2 I/OAT驱动程序 93 7.2.1 公共接口 93 7.2.2 关键功能 93 7.3 Virtio驱动程序 93 7.3.1 介绍 93 7.3.2 2MB大页面 93 第八章 工具 94 8.1 SPDK CLI 94 8.1.1 安装所需的依赖项 94 8.1.2 运行SPDK应用程序实例 94 8.1.3 运行SPDK CLI 94 8.1.4 可选 - 创建Python虚拟环境 94 8.2 nvme-CLI 95 8.2.1 nvme-cli with SPDK入门指南 95 8.2.2 使用场景 95 第九章 性能测试报告(略) 96 第十章NVMe-oF Target跟踪点*** 96 10.1 介绍 96 10.2 启用跟踪点 97 10.3 捕获事件的快照 97 10.4 捕获足够的跟踪事件 98 10.5 添加新的跟踪点 99

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值