In a previous article, I wrote about using pgbench to tune PostgreSQL. While I covered a very common tunable shared_buffers, there are many other tuning options that can be used to gain performance from PostgreSQL.Today’s article is going to cover one of those additional options. However, this tunable does not belong to PostgreSQL. Rather this tunable belongs to the Linux Kernel.
In today’s article, we will be adjusting the Linux I/O scheduler and measuring the impact of those changes with pgbench. We will do this using the same PostgreSQL environment we used in the previous article. All of the tuning parameters from the previous article have already been applied to the environment we will be using today.
What Is an I/O Scheduler?
The I/O Scheduler is an interesting subject; it’s something that’s rarely thought about unless you are trying to get the best performance out of your Linux systems. Before going too deep into how to change the I/O scheduler, let’s take a moment to better familiarize ourselves with what I/O schedulers provide.
Disk access has always been considered the slowest method of accessing data. Even with the growing popularity of Flash and Solid State storage, accessing data from disk is considered slower when compared to accessing data from RAM. This is especially true when you have infrastructure that is using spinning disks.
The reason for this is because traditional spinning disks write data based on locations on a spinning platter. When reading data from a spinning disk it is necessary for the physical drive to spin the disk platters to a specific location to read the data. This process is known as “seeking” and in terms of computing, this process can take a long time.
I/O schedulers exist as a way to optimize disk access requests. They traditionally do this by merging I/O requests to similar locations on disk. By grouping requests located at similar sections of disk, the drive doesn’t need to “seek” as often, improving the overall response time for disk operations.
On modern Linux implementations, there are several I/O scheduler options available. Each of these have their own unique method of scheduling disk access requests. In the rest of this article, we will break down how each of these schedulers prioritize disk access and measure the performance changes from scheduler to scheduler.
Changing the I/O Scheduler
For today’s article, we will be using an Ubuntu Linux server for our tests. With Ubuntu, changing the I/O scheduler can be performed at both runtime and on bootup. The method for changing the scheduler at runtime is as simple as changing the value of a file located within /sys. Changing the value on bootup, which allows you to maintain the setting across reboots, will involve changing the Kernel parameters passed via the Grub boot loader.
Before we change the I/O scheduler however, let’s first identify our current I/O scheduler. We can do this by running:
$ cat /sys/block/sda/queue/scheduler
[noop] deadline cfq
In this example, we have three different I/O schedulers available on the system: noop, deadline, and cfq. The current scheduler is set to cfq (Completely Fair Queuing).
To change the scheduler at runtime, let’s switch it over to deadline:
$ echo ‘deadline’ > /sys/block/sda/queue/scheduler
$ cat /sys/block/sda/queue/scheduler
noop anticipatory [deadline] cfq
To change the scheduler on bootup, let’s add elevator=deadline to the end of the kernel line in /etc/grub.conf file:
title Red Hat Enterprise Linux Server (2.6.9-67.EL)
root (hd0,0)
kernel /vmlinuz-2.6.9-67.EL ro root=/dev/vg0/lv0 elevator=deadline
initrd /initrd-2.6.9-67.EL.img
In RHEL 4, the IO scheduler selection is not per-disk, but global only. In RHEL 7, the deadline IO scheduler is the default IO scheduler for all block devices except SATA disks. For SATA disk, the default IO scheduler is cfq.
Deadline Tunables:
$ grep -vH “zzz” /sys/block/sda/queue/iosched/*
/sys/block/sda/queue/iosched/fifo_batch:16 {number of contiguous io to treat as one}
/sys/block/sda/queue/iosched/front_merges:1 {1=enabled}
/sys/block/sda/queue/iosched/read_expire:500 {time in milliseconds}
/sys/block/sda/queue/iosched/write_expire:5000 {time in milliseconds}
/sys/block/sda/queue/iosched/writes_starved:2 {minimum number of reads to perform,
if available, before any writes}
See “Understanding the Deadline IO Scheduler” for additional and more in-depth information on the deadline scheduler, its tunables and how those tunables change IO selection and flow through the deadline scheduler.
In our next article, we will be exploring other I/O schedulers available to us and measuring their performance impact with pgbench. Based on the passage above, How can you switch between different I/O schedulers in Ubuntu Linux?