掌握SPDK 常用的API是深入理解SPDK的好方法。下面总结了SPDK 最主要的一些API。

public Interface

spdk/nvme.h
Key Functions 	Description
spdk_nvme_probe() 	Enumerate the bus indicated by the transport ID and attach the userspace NVMe driver to each device found if desired.
spdk_nvme_ctrlr_alloc_io_qpair() 	Allocate an I/O queue pair (submission and completion queue).
spdk_nvme_ctrlr_get_ns() 	Get a handle to a namespace for the given controller.
spdk_nvme_ns_cmd_read() 	Submits a read I/O to the specified NVMe namespace.
spdk_nvme_ns_cmd_readv() 	Submit a read I/O to the specified NVMe namespace.
spdk_nvme_ns_cmd_read_with_md() 	Submits a read I/O to the specified NVMe namespace.
spdk_nvme_ns_cmd_write() 	Submit a write I/O to the specified NVMe namespace.
spdk_nvme_ns_cmd_writev() 	Submit a write I/O to the specified NVMe namespace.
spdk_nvme_ns_cmd_write_with_md() 	Submit a write I/O to the specified NVMe namespace.
spdk_nvme_ns_cmd_write_zeroes() 	Submit a write zeroes I/O to the specified NVMe namespace.
spdk_nvme_ns_cmd_dataset_management() 	Submit a data set management request to the specified NVMe namespace.
spdk_nvme_ns_cmd_flush() 	Submit a flush request to the specified NVMe namespace.
spdk_nvme_qpair_process_completions() 	Process any outstanding completions for I/O submitted on a queue pair.
spdk_nvme_ctrlr_cmd_admin_raw() 	Send the given admin command to the NVMe controller.
spdk_nvme_ctrlr_process_admin_completions() 	Process any outstanding completions for admin commands.
spdk_nvme_ctrlr_cmd_io_raw() 	Send the given NVM I/O command to the NVMe controller.
spdk_nvme_ctrlr_cmd_io_raw_with_md() 	Send the given NVM I/O command with metadata to the NVMe controller. 

NVME Driver Design

NVME IO 提交

nvme_ns_cmd_xxx :以 nvme submittin queue entry 的形式 提交IO请求到queue pair; 无阻塞,提交完先于IO完成返回;

spdk_nvme_qpair_process_completions():应用程序通过这个API 在每个queue pair 上polling查询在飞 的IO是否完成;

扩展的性能

NVME 驱动内部的内存使用

  • 数据路径上zero-copy, 这事因为IO commands没有data buffer; 但是admin queue 可能含有数据copy,取决于用户使用的API;

  • 每一个queue队列 拥有一组跟踪调用者提交的命令的tracker;

  • tracker的数量 取决于用户输入(指定的) queue size 和从capacitity 寄存器Maximum Queue Entries Supported(MQES, 0 based value) 字段读回的值;

  • 每个tracker 4096 Bytes (4KB), 最大的maximum memory used for each I/O queue is: (MQES + 1) * 4 KiB.

  • spdk_nvme_qpair_process_completions().

  • SQE 64B (submit queue entry size)

  • CQE 16B (completion queue size)

  • 每个IO queue pair 最多需要的内存大小: (MQES + 1) * (64 + 16) Bytes

  • 上面的内存可以可以分配到host memory; 一些可能把它放到PCI memory bar上

SPDK 内部代码层次

代码是被分层的:

  • 底层: nvme 命令层; API包括spdk_nvme_xxxx: 所在文件在: 示例程序:examples/nvme/hello_world/hello_world.c

  • 中间层: spdk bdev 层,疯转了好需要更多细节的nvme command ,提供对外的类似操作块一样的接口:spdk_blk_xxxx; 示例程序:.//examples/bdev/hello_world/hello_bdev.c

  • 上层:blob 实现了上面类似于快的块资源分配的功能; 示例程序:.//examples/blob/hello_world/hello_blob.c

  • 应用层: blobfs 实现了非POSIX的资源管理和申请、分配; ( demo用那种形式写块?可读性高?)

问题:上面基于nvme. 命令和bdev接口的对nvme SSD的读写的对比,性能方便回有什么损失么?为什么?