主流存储产品剖析 | 青训营笔记

260 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 10 天,今天学习的课程是主流存储产品剖析

什么是SPDK,以及什么场景需要它

首先要明确spdk是一个框架,而不是一个分布式系统,spdk的基石(官网用了bedrock 这个词)是用户态(user space)、轮询(polled-mode)、异步(asynchronous)、无锁(lockless)的NVMe驱动,其提供了零拷贝、高并发直接从用户态访问ssd的特性。其最初的目的是为了优化块存储落盘。但随着spdk的持续演进,大家发现spdk可以优化存储软件栈的各个方面。

很多分布式存储系统都在思考如何吸纳spdk框架,或是采用spdk代表的高性能存储技术,来优化整条IO链路。

spdk的设计理念

spdk主要通过引入以下技术,实现其高性能方案。

  1. 将存储用到的驱动转移到用户态,从而避免系统调用带来的性能损耗,顺便可以直接使用用户态内存落盘实现零拷贝
  2. 使用polling模式
    1. 轮询硬件队列,而不像之前那样使用中断模式,中断模式带来了不稳定的性能和延时的提升
    2. 任何业务都可以在spdk的线程中将轮询函数注册为poller,注册之后该函数会在spdk中周期性的执行,避免了epoll等事件通知机制造成的overhead。
  3. 避免在IO链路上使用锁。使用无锁队列传递消息/IO
    1. spdk设计的主要目标之一就随着使用硬件(e.g. SSD,NIC,CPU)的增多而获得性能的线性提升,为了达到这目的,spdk的设计者就必须消除使用更多的系统资源带来的overhead,如:更多的线程、进程间通信,访问更多的存储硬件、网卡带来的性能损耗。
    2. 为了降低这种性能开销,spdk引入了无锁队列,使用lock-free编程,从而避免锁带来的性能损耗。
    3. spdk的无锁队列主要依赖的dpdk的实现,其本质是使用cas(compare and swap)实现了多生产者多消费者FIFO队列。

通俗的来讲spdk运行时会占用满指定的CPU core,其本质就是一个大的while死循环,占满一个cpu core。去连续的跑用户指定的poller,轮询队列、网络接口等等。因此,spdk编程最基本的准则,就是避免在spdk核上出现进程上下文切换。其会打破spdk高性能框架,造成性能降低甚至不能工作。

进程上下文切换会因为很多原因导致,大致列举如下,我们在spdk编程时切忌要避免。笔者就曾遇到因为spdk线程中一个不起眼的系统调用mmap进入了内核,导致整个spdk进程不可服务直到宕机。

  • cpu时间片耗尽
  • 进程在系统资源不足(比如内存不足)时,要等到资源满足后才可以运行,这个时候进程也会被挂起,并由系统调度其他进程运行。
  • 进程主动调用sleep等函数让出cpu使用权。
  • 当有优先级更高的进程运行时,为了保证高优先级进程的运行,当前进程会被挂起,由高优先级进程来运行。
  • 硬件中断会导致CPU上的进程被挂起,转而执行内核的中断服务程序。