Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

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 :)

share|improve this question
add comment

5 Answers

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.

share|improve this answer
    
Fantastic. Thanks very much for all that info, I'll probably go the tmpfs route. –  JustinP May 9 '11 at 0:54
add comment

Before you proceed please compose a message that you will be sending to users found by mail server log parsing informing them, that your server just lost their message due to power outage/reboot/crash/human tripping on a power cable.

Mail servers are very serious about data persistence guarantees. They go to great pains to make sure that when they take responsibility for user's mail, that message is secure on disk and is going to survive crash/reboot or any other event that wipes contents of the system's RAM. You are going to make sure, that their efforts will be wasted. Are you sure you want to do that?

You'd loose user's data through a plethora of scenarios here, including a clean reboot or shutdown of a machine. Please, search for some other idea on mail server performance tweaking.

share|improve this answer
    
The original poster has made it quite clear that he is aware of this and that performance is more important then persistancy. –  Wim Kerkhoff May 7 '11 at 18:45
    
Yep, the mail server is only used as an avenue for delivering messages. It serves a smartphone messaging application; messages enter the mail server bound for a particular user, and reside there for a maximum of 15-30 seconds before they're pulled into a database and the user is notified that they have a message. Thanks though :) –  JustinP May 9 '11 at 0:52
add comment

you can use tmpfs and mount a ramdisk, it's not complex.

there is this blog post that details creating the tmpfs and modifying the exim startup script to make it a little more robust.

share|improve this answer
add comment

I would just use /dev/shm which is already mounted by default on most modern Linux distributions.

vz1:~# df -h /dev/shm
Filesystem            Size  Used Avail Use% Mounted on
tmpfs                  12G     0   12G   0% /dev/shm

vz1:~# mount |grep shm
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)

vz1:/dev/shm# dd if=/dev/zero of=5gb.dat bs=1M count=5000 conv=fsync
5000+0 records in
5000+0 records out
5242880000 bytes (5.2 GB) copied, 7.36568 s, 712 MB/s


vz1:/dev/shm# time dd if=5gb.dat of=/dev/null bs=1M
5000+0 records in
5000+0 records out
5242880000 bytes (5.2 GB) copied, 2.70614 s, 1.9 GB/s

Just make sure you monitor it; filling it up could be bad.

And then just update the Exim init.d startup script to move the /var spool directories into /dev/shm/ somewhere.

share|improve this answer
add comment

As has already been stated, placing the spool directory in RAM of tempfs is risky as you can lose all emails in the queue if the server crashes. I have gotten very nice performance by placing the /var/spool/exim/input and /var/spool/exim/msglog directories on an SSD drive (over 60000 sent emails per hour on cheap desktop hardware).

The /var/spool/exim/db directory can preferably be placed on a ramdisk (symlink that directory to /dev/shm is the easiest way), as losing retry hints is not fatal.

It is also a fact that exim will trash rather badly if you have a few thousand emails or more in the queue as the queue runner processes will spend proportionally more time stumbling over each other and examining locks than actually getting emails delivered. Fast disks (SSD or ram-based) surely helps, but keeping the queue short is always better!

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.