|
| 1 | +--- |
| 2 | +title: Using FIO |
| 3 | +weight: 4 |
| 4 | + |
| 5 | +### FIXED, DO NOT MODIFY |
| 6 | +layout: learningpathall |
| 7 | +--- |
| 8 | + |
| 9 | +## Setup and Install Fio |
| 10 | + |
| 11 | +I will be using the same `t4g.medium` instance from the previous section with 2 different types of SSD-based block storage devices as per the console screenshot below. Both block devices have the same, 8GiB capacity but the `io1` is geared towards throughput as opposed to the general purpose SSD `gp2`. In this section we want to observe what the real-world performance for our workload is so that it can inform our selection. |
| 12 | + |
| 13 | + |
| 14 | + |
| 15 | +Flexible I/O (fio) is a command-line tool to generate a synthetic workload with specific I/O characteristics. This serves as a simpler alternative to full record and replay testing. Fio is available through most Linux distribution packages, please refer to the [documentation](https://github.com/axboe/fio) for the binary package availability. |
| 16 | + |
| 17 | +```bash |
| 18 | +sudo apt update |
| 19 | +sudo apt install fio -y |
| 20 | +``` |
| 21 | + |
| 22 | +Confirm installation with the following commands. |
| 23 | + |
| 24 | +```bash |
| 25 | +fio --version |
| 26 | +``` |
| 27 | + |
| 28 | +```output |
| 29 | +fio-3.36 |
| 30 | +``` |
| 31 | + |
| 32 | +## Locate Device |
| 33 | + |
| 34 | +`Fio` allows us to microbenchmark either the block device or a mounted filesystem. The disk free, `df` command to confirm our EBS volumes are not mounted. Writing to drives that hold critical information may cause issues. Hence we are writing to blank, unmounted block storage device. |
| 35 | + |
| 36 | +Using the `lsblk` command to view the EBS volumes attached to the server (`nvme1n1` and `nvme2n1`). The immediate number appended to `nvme`, e.g., `nvme0`, shows it is a physically separate device. `nvme1n1` corresponds to the faster `io2` block device and `nvme2n1` corresponds to the slower `gp2` block device. |
| 37 | + |
| 38 | +```bash |
| 39 | +lsblk -e 7 |
| 40 | +``` |
| 41 | + |
| 42 | +```output |
| 43 | +NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS |
| 44 | +nvme1n1 259:0 0 8G 0 disk |
| 45 | +nvme0n1 259:1 0 8G 0 disk |
| 46 | +├─nvme0n1p1 259:3 0 7G 0 part / |
| 47 | +├─nvme0n1p15 259:4 0 99M 0 part /boot/efi |
| 48 | +└─nvme0n1p16 259:5 0 923M 0 part /boot |
| 49 | +nvme2n1 259:2 0 8G 0 disk |
| 50 | +``` |
| 51 | + |
| 52 | +{{% notice Please Note%}} |
| 53 | +If you have more than 1 block volumes attached to an instance, the `sudo nvme list` command from the `nvme-cli` package and be used to differentiate between volumes |
| 54 | +{{% /notice %}} |
| 55 | + |
| 56 | +## Generating a Synthetic Workload |
| 57 | + |
| 58 | +Let us say we want to simulate a fictional logging application with the following characteristics observed using the tools from the previous section. |
| 59 | + |
| 60 | +{{% notice Workload%}} |
| 61 | +The logging workload has light sequential read and write characteristics. The system write throughput per thread is 5 MB/s with 83% writes. There are infrequent bursts of reads for approximately 5 seconds, operating at up to 16MB/s per thread. The workload can scale the infrequent reads and writes to use up to 16 threads each. The block size for the writes and reads are 64KiB and 256KiB respectively (as opposed to the standard 4KiB Page size). |
| 62 | + |
| 63 | +Further, the application latency sensitive and given it holds critical information, needs to write directly to non-volatile storage through direct IO. |
| 64 | +{{% /notice %}} |
| 65 | + |
| 66 | +The fio tool uses simple configuration `jobfiles` to describe the characterisics of your synthetic workload. Parameters under the `[global]` option are shared among jobs. From the example below, we have created 2 jobs to represent the steady write and infrequent reads. Please refer to the official [documentation](https://fio.readthedocs.io/en/latest/fio_doc.html#job-file-format) for more details. |
| 67 | + |
| 68 | +Copy and paste the configuration file below into 2 files named `nvme<x>.fio`. Replace the `<x>` with the block devices we are comparing and just the `filename` parameter accordingly. |
| 69 | + |
| 70 | +```ini |
| 71 | + ; -- start job file including.fio -- |
| 72 | +[global] |
| 73 | +ioengine=libaio |
| 74 | +direct=1 ; write directly to the drive |
| 75 | +time_based |
| 76 | +runtime=30 |
| 77 | +group_reporting=1 |
| 78 | +log_avg_msec=1000 |
| 79 | +rate=16m,5m ; limit to 16 MB/s and 5MB/s for read and write per job |
| 80 | +numjobs=${NUM_JOBS} ; set at the command line |
| 81 | +iodepth=${IO_DEPTH} ; set at the command line |
| 82 | +filename=/dev/nvme1n1 ; or nvme2n1 |
| 83 | + |
| 84 | +[steady_write] |
| 85 | +name=steady_write |
| 86 | +rw=write ; sequential write |
| 87 | +bs=64k ; Block size of 64KiB (default block size of 4 KiB) |
| 88 | + |
| 89 | +[burst_read] |
| 90 | +name=burst_read |
| 91 | +rw=read |
| 92 | +bs=256k ; adjust the block size to 64KiB writes (default is 4KiB) |
| 93 | +startdelay=10 ; simulate infrequent reads (5 seconds out 30) |
| 94 | +runtime=5 |
| 95 | +; -- end job file including.fio -- |
| 96 | +``` |
| 97 | + |
| 98 | +Run the following commands to run each test back to back. |
| 99 | + |
| 100 | +```bash |
| 101 | +sudo NUM_JOBS=16 IO_DEPTH=64 fio nvme1.fio |
| 102 | +``` |
| 103 | + |
| 104 | +Then |
| 105 | + |
| 106 | +```bash |
| 107 | +sudo NUM_JOBS=16 IO_DEPTH=64 fio nvme2.fio |
| 108 | +``` |
| 109 | + |
| 110 | +### Interpreting Results |
| 111 | + |
| 112 | +The final terminal output from both runs are shown below. |
| 113 | + |
| 114 | +```output |
| 115 | +nvme1: |
| 116 | +
|
| 117 | +Run status group 0 (all jobs): |
| 118 | + READ: bw=118MiB/s (124MB/s), 118MiB/s-118MiB/s (124MB/s-124MB/s), io=629MiB (660MB), run=5324-5324msec |
| 119 | + WRITE: bw=80.0MiB/s (83.9MB/s), 80.0MiB/s-80.0MiB/s (83.9MB/s-83.9MB/s), io=2400MiB (2517MB), run=30006-30006msec |
| 120 | +
|
| 121 | +Disk stats (read/write): |
| 122 | + nvme1n1: ios=2663/38225, sectors=1294480/4892800, merge=0/0, ticks=148524/454840, in_queue=603364, util=62.19% |
| 123 | +
|
| 124 | +nvme2: |
| 125 | +
|
| 126 | +Run status group 0 (all jobs): |
| 127 | + READ: bw=85.6MiB/s (89.8MB/s), 85.6MiB/s-85.6MiB/s (89.8MB/s-89.8MB/s), io=456MiB (478MB), run=5322-5322msec |
| 128 | + WRITE: bw=60.3MiB/s (63.2MB/s), 60.3MiB/s-60.3MiB/s (63.2MB/s-63.2MB/s), io=1816MiB (1904MB), run=30119-30119msec |
| 129 | +
|
| 130 | +Disk stats (read/write): |
| 131 | + nvme2n1: ios=1872/28855, sectors=935472/3693440, merge=0/0, ticks=159753/1025104, in_queue=1184857, util=89.83% |
| 132 | +``` |
| 133 | + |
| 134 | +Here we can see that the faster `io2` block storage (`nvme1`) is able to meet the throughput requirement of 80MB/s for steady writes when all 16 write threads are running (5MB/s per thread). However `gp2` saturates at 60.3 MiB/s with over 89.8% SSD utilisation. |
| 135 | + |
| 136 | +We are told the fictional logging application is sensitive to operation latency. The output belows highlights that over ~35% operations have a latency above 1s on nvme2 compared to ~7% on nvme1. |
| 137 | + |
| 138 | + |
| 139 | +```output |
| 140 | +
|
| 141 | + nvme2: |
| 142 | +
|
| 143 | + lat (usec) : 10=0.01%, 500=1.53%, 750=5.13%, 1000=7.55% |
| 144 | + lat (msec) : 2=29.49%, 4=0.89%, 10=0.09%, 20=0.02%, 50=0.21% |
| 145 | + lat (msec) : 100=0.56%, 250=1.84%, 500=6.39%, 750=9.76%, 1000=10.17% |
| 146 | + lat (msec) : 2000=19.59%, >=2000=6.77% |
| 147 | +
|
| 148 | + nvme1: |
| 149 | +
|
| 150 | + lat (usec) : 750=0.44%, 1000=0.41% |
| 151 | + lat (msec) : 2=62.63%, 4=1.12%, 10=0.34%, 20=1.61%, 50=3.91% |
| 152 | + lat (msec) : 100=2.34%, 250=5.91%, 500=8.46%, 750=4.33%, 1000=2.50% |
| 153 | + lat (msec) : 2000=3.62%, >=2000=2.38% |
| 154 | +``` |
| 155 | + |
| 156 | +This insights above suggest the SSD designed for throughput, `io2` is more suitable than the general purpose `gp2` storage to meet the requirements of our logging application. |
| 157 | + |
| 158 | +{{% notice Tip%}} |
| 159 | +If the text output is hard to follow, you can use the `fio2gnuplot` package to plot the data graphically or use the visualisations available from the cloud service provider's dashboard. See image below for an example. |
| 160 | + |
| 161 | +  |
| 162 | +{{% /notice %}} |
| 163 | + |
| 164 | +The insights gathered by microbenchmarking with fio above can lead to more informed decisions about which block storage to connect to your Arm-based instance. |
| 165 | + |
| 166 | + |
0 commit comments