Improving Exim performance: mounting message queue on RAMdisk

eximperformancequeueramdisktmpfs

I have an email server that's part of a messaging application, and it's going to see a lot of throughput. I want to mount Exim's message queue on a RAMdisk to maximize performance; throughput speed is most important, as opposed to solidarity in case of a crash or system reboot. I've found lots of information saying that mounting the message queue on a RAMdisk will help quite a bit, but no real information on how to do this.

I'm pretty certain the message queue is in /var/spool/exim by default, and that I can use tmpfs to mount a RAMdisk. How exactly would I go about mounting a RAMdisk upon bootup, and having Exim's message queue use it?

I.e. what would the command be to mount this RAMdisk, and where would I put that command so that it executes when the machine boots (but before Exim starts up)?

Thanks 🙂

Best Answer

Ramdisk: Implications

  • Using a ramdisk is only useful when your application is IO bound, specifically to your hard disk. Unless you are sending thousands of messages over a fast fiber link, chances are that your primary limiter is the speed of your internet connection, and not the speed of your hard drive.
  • Exim is already very good at handling large queues on 'slow' mediums such as hard disks; simply set the split_spool_directory in the config file and Exim will handle large queues more efficiently by splitting messages into subdirectories instead of a single spool directory.
  • Spooling messages to a ramdisk poses the risk of loosing the entire queue in the event of a reboot or power outage, with no way to recover the queue.
  • The spool directory can become quite massive, and you risk running out of space on the ramdisk partition very quickly. A few emails with large attachments could quite easily fill up even a sizable ramdisk. Similarly, messages which cannot be delivered immediately sit in the queue until they are successfully delivered, removed manually or expired by Exim, though this is a configurable setting in the Exim config file.


Ramdisk: Configuring a ramdisk

Many linux distros already have some preconfigured but unused ramdisks. Run the following command to list your current ramdisks:

ls /dev/ram*

To see the size allocation, use fdisk in the standard fashion: (where X is your ramdisk number)

fdisk -l /dev/ramX

You will probably want to increase the default space allocation. Since ramdisk size is controlled by the kernel, you will need to set a kernel option to increase the allocated space. If your bootloader is GRUB, you can edit the grub.conf file and add the ramdisk_size kernel option. Your GRUB config file should then look something like this: (in this example we're setting the ramdisk size to 256MB)

default 0
timeout 5
hiddenmenu
splashimage=(hd0,1)/boot/grub/splash.xpm.gz

title=Gentoo Gateway Server
root (hd0,1)
kernel /boot/vmlinuz root=/dev/sda2 ramdisk_size=256000

After a reboot your new ramdisks should reflect the updated space allocation. Since there is no point in formatting a ramdisk with a journalled filesystem, we'll just use ext2:

mke2fs -m 0 /dev/ram0

The -m 0 option keeps mke2fs from reserving any space on the file system for the root user. You can now create a mount point for the ramdisk, mount it, and begin using it.

mkdir /mnt/ramdisk
mount /dev/ram0 /mnt/ramdisk
df -h /dev/ram0

Additionally, make sure that you have the correct permissions set on the mountpoint (replace username and groupname with the correct group and user for your system):

chown -R username:groupname /mnt/ramdisk

You can now use this partition as though it were a standard hard disk partition. Note that if you unmount the partition, your data will not be lost, and the RAM will not be freed, since the kernel permanently allocates the required space until rebooted.

To automate this procedure, add the following into your /etc/rc.local script:

/sbin/mke2fs -q -m 0 /dev/ram0
/bin/mount /dev/ram0 /mnt/ramdisk
/bin/chown username:groupname /mnt/ramdisk
/bin/chmod 0750 /mnt/ramdisk


Ramdisk: Exim configuration

You can do a bind mount so that Exim will continue to write to its standard spool directory. To do so, add the following line to your /etc/fstab file:

/mnt/ramdisk        /var/spool/exim        none        bind        0 0

Alternatively, you can just point Exim to the ramdisk mountpoint. To do so, you'll need to set the following in the exim.conf file:

spool_directory = /mnt/ramdisk

Obviously you would only do either one of the aforementioned, not both.


A Better Solution: tmpfs

Instead of using a ramdisk, rather use tmpfs, supported by Linux kernel 2.4 and up. The benefit of using tmpfs is that memory is dynamically assignable, making it a far more flexible solution than ramdisks. Additionally, if your tmpfs partition runs out of space, the kernel will automatically begin paging data to your hard disk, whereas the ramdisk solution would simply cause Exim to stop processing messages and crash.

Using tmpfs, you won't need to do any of the of the steps required for the above ramdisk solution. The following steps are required for a successful tmpfs configuration:

Create a mountpoint and set correct permissions:

mkdir /mnt/tmpfs
chown -R username:groupname /mnt/tmpfs

Next, open your /etc/fstab file and set the tmpfs partition to be created and mounted at boot:

#<fs>        <mountpoint>        <type>       <opts>                             <dump/pass>
tmpfs        /mnt/tmpfs          tmpfs        size=1G,nr_inodes=10k,mode=0700    0 0

This will create a 1GB tmpfs partition with 10'000 inodes. The exim configuration is the same as when creating a ramdisk - either tell Exim that the location of the new spool directory is located at /mnt/tmpfs or bind the existing spool directory to the /mnt/tmpfs mountpoint. Alternatively, you could just mount the tmpfs partition onto Exim's existing spool directory right from the start - so instead of the above changes to the /etc/fstab file, use this line instead:

#<fs>        <mountpoint>        <type>       <opts>                             <dump/pass>
tmpfs        /var/spool/exim     tmpfs        size=1G,nr_inodes=10k,mode=0700    0 0


This site has a good article explaining tmpfs and ramdisks, and the differences between them.

Related Topic