学习spdk

学习SPDK,可以按照以下步骤进行:

  1. 了解SPDK的基本概念和原理,包括SPDK的优势、设计思路、应用场景等。
  2. 学习SPDK的编程模型和API,了解SPDK的核心组件和应用接口,熟悉SPDK的编程规范和使用方法。
  3. 进行SPDK的实践和应用,可以通过编写简单的SPDK应用程序来熟悉SPDK的使用,也可以参与SPDK社区的开源项目,了解SPDK的实现细节和技术难点。
  4. 参与SPDK社区的交流和讨论,可以通过SPDK的邮件列表、论坛、社交媒体等渠道,与SPDK的开发者和用户进行交流和分享,了解SPDK的最新发展和应用案例。

总之,学习SPDK需要有一定的编程经验和相关知识,需要不断地实践和探索,也需要积极参与社区的开发和交流。

SPDK的优势

  • 零拷贝:SPDK可以避免数据从用户空间到内核空间的复制,直接在用户空间操作I/O数据,提高I/O操作效率。
  • 高性能:SPDK使用异步I/O操作和多线程技术,充分利用多核CPU的性能,提高I/O操作的吞吐量和响应速度。
  • 可扩展性:SPDK支持多种硬件加速技术,如RDMA、NVMe等,可以在不同的硬件平台上实现高性能的存储服务。
  • 开源:SPDK是一个开源项目,可以自由获取、使用和修改,有广泛的社区支持和应用案例。

SPDK的设计思路

  • 用户空间I/O:SPDK将I/O操作从内核空间转移到用户空间,避免了复杂的内核调度和同步机制,提高了I/O操作的效率。
  • 异步I/O:SPDK使用异步I/O操作,可以在I/O操作等待时执行其他任务,提高了系统的并发性和响应速度。
  • 多线程:SPDK采用多线程技术,充分利用多核CPU的性能,提高I/O操作的吞吐量和响应速度。
  • 零拷贝:SPDK可以避免数据从用户空间到内核空间的复制,直接在用户空间操作I/O数据,提高I/O操作效率。

SPDK的应用场景

  • 存储系统:SPDK可以支持高性能的存储系统,如块存储、文件存储、对象存储等。
  • 数据库系统:SPDK可以支持高性能的数据库系统,如NoSQL数据库、分布式数据库等。
  • 数据分析系统:SPDK可以支持高性能的数据分析系统,如Hadoop、Spark等。
  • 云计算平台:SPDK可以支持高性能的云计算平台,如OpenStack、Kubernetes等。

SPDK的编程模型和API

SPDK的编程模型基于异步I/O和事件驱动,开发者需要使用SPDK提供的异步I/O API来执行I/O操作,使用事件驱动机制来处理I/O完成事件。SPDK提供了一系列异步I/O API,包括I/O通道、I/O缓冲区、I/O队列、I/O完成事件等。开发者需要使用这些API来构建自己的存储服务或应用程序。

SPDK的核心组件和应用接口

SPDK的核心组件包括了多个模块,包括块设备模块、NVMe设备模块、事件模块、异步I/O模块、内存模块、日志模块等。SPDK还提供了多个应用接口,包括初始化接口、块设备接口、NVMe设备接口、I/O通道接口、I/O队列接口、异步I/O接口等。开发者可以使用这些接口来构建自己的存储服务或应用程序。

SPDK的编程规范和使用方法

为了保证代码质量和可维护性,SPDK社区制定了一系列编程规范和使用方法,包括代码风格、注释规范、函数命名规范、错误处理规范、内存管理规范等。开发者需要遵循这些规范和方法来进行开发工作,以便其他开发者或社区成员能够更好地理解和维护代码。
此外,为了让开发者更容易上手SPDK的开发工作,SPDK还提供了完整的文档和教程,包括API文档、用户指南、示例代码、视频教程等。开发者可以根据自己的需求选择合适的文档和教程来进行学习和实践。
以下是一些SPDK相关的详细链接,供参考:

SPDK官网:https://spdk.io/
SPDK GitHub仓库:https://github.com/spdk/spdk
SPDK文档中心:https://spdk.io/doc/
SPDK社区邮件列表:https://lists.01.org/mailman/listinfo/spdk
SPDK社区论坛:https://forum.spdk.io/
SPDK社区Slack频道:https://spdk.slack.com/archives/C029VC7M8GP
SPDK社区YouTube频道:https://www.youtube.com/channel/UCbX9lJfY6b2cKQyj6hBgySw
SPDK社区Twitter账号:https://twitter.com/SPDK_IO
Intel官方SPDK介绍视频:https://www.youtube.com/watch?v=L2_6NnYrKbY&t=11s
SPDK学习视频教程(中文):https://www.bilibili.com/video/BV1p54y1v7zT
SPDK最佳实践视频教程(英文):https://www.youtube.com/watch?v=Zv3qP-qo5A0&t=1s
SPDK NVMe-oF视频教程(英文):https://www.youtube.com/watch?v=7VU4pNl8GvU
SPDK在云计算中的应用视频教程(英文):https://www.youtube.com/watch?v=3xLZzCJH9yk&t=1s

spdk关于nvme模块的helloword实例代码

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
#include <fcntl.h>
#include <inttypes.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <rte_config.h>
#include <rte_eal.h>
#include <rte_pci.h>
#include <rte_bus_pci.h>
#include <rte_memory.h>
#include <spdk/nvme.h>
static bool g_shutdown = false;
static void sig_handler(int signum)
{
    if (signum == SIGINT || signum == SIGTERM) {
        g_shutdown = true;
    }
}
int main(int argc, char **argv)
{
    struct spdk_nvme_ctrlr *ctrlr;
    struct spdk_nvme_ns *ns;
    struct spdk_nvme_qpair *qpair;
    struct spdk_nvme_ctrlr_opts opts;
    struct spdk_pci_addr pci_addr;
    uint32_t nsid;
    int rc;
    signal(SIGINT, sig_handler);
    signal(SIGTERM, sig_handler);
    rc = rte_eal_init(argc, argv);
    if (rc < 0) {
        fprintf(stderr, "Failed to initialize EAL\n");
        return -1;
    }
    memset(&opts, 0, sizeof(opts));
    opts.num_io_queues = 4;
    ctrlr = spdk_nvme_connect(NULL, &opts, sizeof(opts));
    if (ctrlr == NULL) {
        fprintf(stderr, "Failed to connect to NVMe controller\n");
        return -1;
    }
    pci_addr = spdk_nvme_ctrlr_get_pci_controller(ctrlr)->addr;
    printf("Connected to NVMe controller at %!!(MISSING)x(MISSING):%!!(MISSING)x(MISSING):%!!(MISSING)x(MISSING).%!!(MISSING)x(MISSING)\n",
           pci_addr.domain, pci_addr.bus, pci_addr.devid, pci_addr.function);
    nsid = spdk_nvme_ctrlr_get_first_active_ns(ctrlr);
    if (nsid == 0xffffffff) {
        fprintf(stderr, "No active namespace found\n");
        spdk_nvme_detach(ctrlr);
        return -1;
    }
    ns = spdk_nvme_ctrlr_get_ns(ctrlr, nsid);
    if (ns == NULL) {
        fprintf(stderr, "Failed to get namespace %!!(MISSING)u(MISSING)\n", nsid);
        spdk_nvme_detach(ctrlr);
        return -1;
    }
    printf("Connected to NVMe namespace %!!(MISSING)u(MISSING)\n", nsid);
    qpair = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, NULL, 0);
    if (qpair == NULL) {
        fprintf(stderr, "Failed to allocate I/O queue pair\n");
        spdk_nvme_ns_detach(ns);
        spdk_nvme_detach(ctrlr);
        return -1;
    }
    while (!g_shutdown) {
        printf("Hello, World!\n");
        sleep(1);
    }
    spdk_nvme_ctrlr_free_io_qpair(qpair);
    spdk_nvme_ns_detach(ns);
    spdk_nvme_detach(ctrlr);
    return 0;
}

此示例程序将连接到系统中的第一个NVMe控制器,打开其第一个活动命名空间,并分配一个I/O队列对。然后在循环中打印“Hello, World!”,直到接收到SIGINT或SIGTERM信号时退出程序。

详细讲解

首先,在main函数中,我们进行了一些初始化操作。首先,使用rte_eal_init函数对EAL(Environment Abstraction Layer)进行初始化,这是DPDK(Data Plane Development Kit)的一部分,用于抽象出底层平台的特定性,使得DPDK可以在不同的平台上运行。初始化后,我们使用memset函数将opts(struct spdk_nvme_ctrlr_opts结构体类型)的所有成员都初始化为0。然后,我们使用spdk_nvme_connect函数连接到系统中的第一个NVMe控制器,这个函数的第一个参数为NULL,表示使用默认的选项进行连接;第二个参数为opts,表示我们使用之前初始化的opts结构体作为选项;第三个参数是opts的大小。如果连接失败,我们会输出错误信息并直接退出程序。

    struct spdk_nvme_ctrlr *ctrlr;
    struct spdk_nvme_ns *ns;
    struct spdk_nvme_qpair *qpair;
    struct spdk_nvme_ctrlr_opts opts;
    struct spdk_pci_addr pci_addr;
    uint32_t nsid;
    int rc;
    signal(SIGINT, sig_handler);
    signal(SIGTERM, sig_handler);
    rc = rte_eal_init(argc, argv);
    if (rc < 0) {
        fprintf(stderr, "Failed to initialize EAL\n");
        return -1;
    }
    memset(&opts, 0, sizeof(opts));
    opts.num_io_queues = 4;
    ctrlr = spdk_nvme_connect(NULL, &opts, sizeof(opts));
    if (ctrlr == NULL) {
        fprintf(stderr, "Failed to connect to NVMe controller\n");
        return -1;
    }

接下来,我们获取连接上的NVMe控制器的PCI地址,并将其打印出来。

    pci_addr = spdk_nvme_ctrlr_get_pci_controller(ctrlr)->addr;
    printf("Connected to NVMe controller at %!!(MISSING)!(MISSING)x(MISSING):%!!(MISSING)!(MISSING)x(MISSING):%!!(MISSING)!(MISSING)x(MISSING).%!!(MISSING)!(MISSING)x(MISSING)\n",
           pci_addr.domain, pci_addr.bus, pci_addr.devid, pci_addr.function);

然后,我们打开第一个活动的命名空间(namespace)。

    nsid = spdk_nvme_ctrlr_get_first_active_ns(ctrlr);
    if (nsid == 0xffffffff) {
        fprintf(stderr, "No active namespace found\n");
        spdk_nvme_detach(ctrlr);
        return -1;
    }
    ns = spdk_nvme_ctrlr_get_ns(ctrlr, nsid);
    if (ns == NULL) {
        fprintf(stderr, "Failed to get namespace %!!(MISSING)!(MISSING)u(MISSING)\n", nsid);
        spdk_nvme_detach(ctrlr);
        return -1;
    }
    printf("Connected to NVMe namespace %!!(MISSING)!(MISSING)u(MISSING)\n", nsid);

最后,我们分配一个I/O队列对,并在循环中打印“Hello, World!”,直到接收到SIGINT或SIGTERM信号时退出程序。需要注意的是,这里我们使用了spdk_nvme_ctrlr_alloc_io_qpair函数来分配I/O队列对,而不是使用spdk_nvme_ctrlr_get_default_io_qpair函数,是因为前者可以为I/O队列对设置一些选项,而后者则不能。

    qpair = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, NULL, 0);
    if (qpair == NULL) {
        fprintf(stderr, "Failed to allocate I/O queue pair\n");
        spdk_nvme_ns_detach(ns);
        spdk_nvme_detach(ctrlr);
        return -1;
    }
    while (!g_shutdown) {
        printf("Hello, World!\n");
        sleep(1);
    }
    spdk_nvme_ctrlr_free_io_qpair(qpair);
    spdk_nvme_ns_detach(ns);
    spdk_nvme_detach(ctrlr);

当程序退出时,我们需要使用spdk_nvme_ctrlr_free_io_qpair函数释放I/O队列对,然后分别使用spdk_nvme_ns_detach和spdk_nvme_detach函数分离命名空间和控制器。

推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习

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
发出的红包

打赏作者

我也要当昏君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值