But the way you tested is almost certainly valid.
298 karma · joined April 16, 2016
But the way you tested is almost certainly valid.
And as noted in the other comments, this is about simplifying support for things like connectors, LEDs, expanders, and software in data centers where they're mixing NVMe SSDs and HDDs today. It's just simpler to have fewer parts and software differences.
NVMe-oF can do both TCP (akin to iSCSI) and RDMA (akin to iSER). There are likely several reasons NVMe-oF is faster, but one big one is that each connection within a session shares state in iSCSI, so you either process all connections for a session on a single thread or you take locks. In NVMe-oF, it's possible to keep every connection entirely independent, so the NVMe-oF implementations scale better.
Recently, a new protocol to replace virtio has been defined. It is modeled on vfio ioctls and currently only can forward to another user space process, so we're calling it vfio-user. With this protocol, it's possible to emulate any PCI device rather than only virtio devices. Projects like SPDK (what I work on) can now use this to present fully emulated NVMe devices into guests and back them with whatever actual storage is available (a file, something over the network, a real NVMe SSD, etc). This allows an OS, including Windows, to boot from the virtual disk using it's in-box NVMe driver. This hasn't quite made it into a QEMU release yet, but it's close!
But that assumes the person using this process is acting in bad faith to begin with (they're not pursuing the best idea, but rather their idea). If this technique is used in good faith with an open mind, it's one of the most effective ways to deal with large organizations.
One of these tests is to run shellcheck against all of the scripts in the repo. We don't allow any modifications to scripts without shellcheck giving them the green light now. The quality of our tests has increased dramatically since this was instituted - it's a really great tool.
For at least reads, if you don't hit a CPU limit you'll get 8x more IOPS with 512B than you will with 4KiB with SPDK. It's more or less perfect scaling. There's some additional hardware overheads in the MMU and PCIe subsystems with 512B because you're sending more messages for the same bandwidth, but my experience has been that it is mostly negligible.
The benchmark builds to build/examples/perf and you can just run it with -h to get the help output. Random 4KiB reads at 32 QD to all available NVMe devices (all devices unbound from the kernel and rebound to vfio-pci) for 60 seconds would be something like:
perf -q 32 -o 4096 -w randread -t 60
You can specify only test specific devices with the -r parameter (by BUS:DEVICE:FUNCTION essentially). The tool can also benchmark kernel devices. Using -R will turn on io_uring (otherwise it uses libaio), and you simply list the block devices on the command line after the base options like this:
perf -q 32 -o 4096 -w randread -t 60 -R /dev/nvme0n1
You can get ahold of help from the SPDK community at https://spdk.io/community. There will be lots of people willing to help.
Excellent post by the way. I really enjoyed it.
But while SPDK does have an fio plug-in, unfortunately you won't see numbers like that with fio. There's way too much overhead in the tool itself. We can't get beyond 3 to 4 million with that. We rolled our own benchmarking tool in SPDK so we can actually measure the software we produce.
Since the core is CPU bound, 512B IO are going to net the same IO per second as 4k. The software overhead in SPDK is fixed per IO, regardless of size. You can also run more threads with SPDK than just one - it has no locks or cross thread communication so it scales linearly with additional threads. You can push systems to 80-100M IO per second if you have disks and bandwidth that can handle it.
This is using SPDK to eliminate all of the overhead the author identified. The hardware is far more capable than most people expect, if the software would just get out of the way.
As background, vfio-user was at least partially born of some discussions and a proof of concept last summer for using SPDK to provide virtual NVMe devices into QEMU. These are intended to be high performance devices.
Except SPDK is written in C. So maybe the title should be rewrite SPDK in Rust!
Is it possible to only encrypt the QUIC headers but leave the data unmodified? That idea just popped into my head and I'm not sure it makes any sense, but maybe that would provide the best of both worlds.
First, the IO threads in RocksDB are a thread pool that assume they perform blocking operations. That doesn't jive with SPDK's async model (nor io_uring's). We're having to message pass to an async thread and block on semaphores in the IO threads.
Second, RocksDB was heavily reliant on the kernel page cache to make it fast.
Both of these things could have changed since we last worked on the integration. I haven't kept up with RocksDB development recently.
source: am SPDK maintainer
However, there's still lots of reasons to use SPDK. Performance is still significantly better[0], and you can directly access all the of the NVMe features on the device without going through any abstraction layers.
*I was recently part of an effort to add FreeBSD testing to DPDK because SPDK's FreeBSD test agent kept failing when we updated DPDK. I'm a core maintainer for SPDK, which is basically DPDK for storage.
"Writing to flash is destructive. If a filesystem repeatedly writes to the same block, eventually that block will wear out. Filesystems that don't take wear into account can easily burn through blocks used to store frequently updated metadata and cause a device's early death."
This isn't true. It's only true for filesystems that aren't running on a regular block storage device. It's even more egregious to use the word block because almost everyone assumes that means a logical block. They must be using it to mean a NAND page, which has entirely different behavior and does wear out.
Given that, I don't understand the discussion of wear leveling in this FS. Maybe someone can explain further.
Said another way, on a recent Xeon CPU you can expect to drive somewhere around 3 million 4k I/O per second with SPDK per core. With libaio, you can do about 450,000 per core off the top of my head.
SPDK has no locks or cross core communication required, so it scales linearly with additional CPU cores. Blk-mq in the kernel also helped the kernel scaling problem significantly, but I'm not sure if it is perfectly linear yet.
Most applications need something like a filesystem to function - there is no denying that. Using SPDK requires applications to implement at least the minimal set of features in the filesystem that their application needs. Many databases and storage services already bypass the filesystem or use the filesystem as a block allocator only, so it is not a big leap from there to SPDK.
You, as the application developer, have a distinct advantage though - you only need to solve the problem for your application, and using that knowledge can often lead to more efficient solutions. This may mean dedicating cores to the network or disk, or it may mean working in fixed sized batches, etc.
The equivalent layer of a TCP/IP stack for storage is probably a filesystem, and the kernel filesystems and block layers are at least as inefficient as the network stack for similar reasons.
http://spdk.io - for block device form factors