Because there are so many factors that can affect storage performance, before running any kind of storage performance test, real-world or synthetic, it’s always a good idea to try to ascertain what the maximum data throughput capabilities are for your test environment as it is currently configured. These are known as plumbing tests.
What are Plumbing Tests?
Plumbing tests can help you more easily discover problems or misconfigurations in your testing environment that should be addressed before conducting a storage performance test.
There are many ways to do this, but one way is to:
- create a number of thin-provisioned volumes on the storage array
- leave the volumes empty, thus leaving all of the logical blocks in the volumes unmapped to physical blocks
- this will help the array to serve reads as fast as possible.
- leave the volumes empty, thus leaving all of the logical blocks in the volumes unmapped to physical blocks
- map the storage volumes to raw luns on a number of host initiators
- use a load-generation tool to run a series of 100% read tests to discover the maximum unidirectional data throughput capabilities of your test environment
- then run a series of 100% write tests to see if the maximum data throughput capabilities of your test environment are different for writes
- create highly reducible datastreams to increase the front-end write capabilities of your data-reduction storage array
- follow this up with a series of read/write tests to discover the maximum bi-directional capabilities of your test environment
Related reading IO Plumbing Tests with fio
Below is a fio job file that can serve as a template to construct your own plumbing sequential read ramp test:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
[global] time_based size=1p runtime=50 filename=/dev/sdb:/dev/sdc:/dev/sdd:/dev/sde ioengine=libaio randrepeat=0 direct=1 invalidate=1 verify=0 verify_fatal=0 ramp_time=10 blocksize=32k zero_buffers rw=read numjobs=4 bwavgtime=1000 iopsavgtime=1000 log_avg_msec=1000 group_reporting [job00] stonewall iodepth=1 [job01] stonewall iodepth=2 [job02] stonewall iodepth=3 . . . [job29] stonewall iodepth=30 [job30] stonewall iodepth=31 [job31] stonewall iodepth=32 |
The fio sequential write ramp plumbing test is exactly the same as the sequential read ramp test above, except that we use the “rw=write” parameter.
For a bi-directional read/write plumbing test, you can do something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
[global] time_based size=1p runtime=50 filename=/dev/sdb:/dev/sdc:/dev/sdd:/dev/sde ioengine=libaio randrepeat=0 direct=1 invalidate=1 verify=0 verify_fatal=0 ramp_time=10 blocksize=32k zero_buffers numjobs=4 bwavgtime=1000 iopsavgtime=1000 log_avg_msec=1000 group_reporting [job00–read] stonewall rw=read iodepth=1 [job00–write] rw=write iodepth=1 [job01–read] stonewall rw=read iodepth=2 [job01–write] rw=write iodepth=2 . . . [job30–read] stonewall rw=read iodepth=31 [job30–write] rw=write iodepth=31 [job31–read] stonewall rw=read iodepth=32 [job31–write] rw=write iodepth=32 |
A much more in-depth explanation of these tests, and the fio job files, can be found HERE. Please keep in mind that using 100% unmapped, or partially unmapped luns, is a trick that some take to artificially inflate their results. While this is fine for a “plumbing” test, it is completely useless for a proper storage performance test.
Running a True Performance Test
If anyone tries to convince you that it is OK to run a performance test with datasets and datastreams that are not a defensible approximation of your real-world environment, they either don’t understand proper storage performance testing principles, especially for a data-reduction storage array, or they are trying to sneak something past you.
It is just as useless to use 100% non-reducible data in your datasets and datastreams as it is to use unmapped luns, NUL writes, single-character writes, or even writes consisting of a small repeating set of characters for a storage performance test on a data-reduction storage array.
Insist upon datasets that are filled and aged in such a way that they defensibly approximate the various datasets and datastreams in your environment.
Anything short of this is a flawed synthetic storage performance test.