Hi all,

After much battling I've managed to increase the number of file handles available to rsyslog in Ubuntu 14.04. It was significantly harder than you might expect, even given that Ubuntu uses upstart, which does strange stuff with ulimits. So I thought it would be worth sharing the trick that works with the list. Perhaps someone could even explain to me *why* it works :-) Or, even better, tell me a better way to do it. Or both...

Scenario: I wanted to increase the number of available file handles for syslog, because I'm writing to a large number of files via a large number of queues.

Short version: you need to put "ulimit -n 16384" (or whatever) inside /etc/default/rsyslog. The normal way of setting the open file limit for an upstart job (ie. "limit nofile XXX") does not work, at least for me. Putting the ulimit call inside the upstart rsyslog.conf doesn't work either, which is weird (for reasons explained below).

Long version: the default Ubuntu upstart script for starting rsyslog looks like this:

   # rsyslog - system logging daemon
   #
   # rsyslog is an enhanced multi-threaded replacement for the traditional
   # syslog daemon, logging messages from applications

   description     "system logging daemon"

   start on filesystem
   stop on runlevel [06]

   expect fork
   respawn

   pre-start script
        /lib/init/apparmor-profile-load usr.sbin.rsyslogd
   end script

   script
        . /etc/default/rsyslog
        exec rsyslogd $RSYSLOGD_OPTIONS
   end script


Now, upstart does its own ulimit handling, and changes to limits.conf don't affect processes launched by it, so the normal way to increase the number of file handles is to add a line like this just after the "expect fork"/"respawn" bit:

   limit nofile 16384 16384


Indeed, David Lang suggested doing exactly that a couple of months ago in a different thread (archive <http://lists.adiscon.net/pipermail/rsyslog/2015-October/041404.html>).

But, weirdly, it doesn't work, at least for me. Inspecting /proc/<rsyslog-pid>/limits after adding that line and bouncing rsyslog showed that the file handle limit was still 1024 soft, 4096 hard. And I found that my system was not writing to a number of the files it was meant to; "ls /proc/<rsyslog-pid>/fd/ | wc -l" confirmed that it was capping out at 1024 files open.

My first guess was that it's something to do with the fact that Ubuntu's upstart script launches rsyslog via a "script" section. The normal way to start a process in upstart is simply something like

   exec <binary> <options>


...without a "script" block around it. The script block just allows you to add normal shell script to the upstart config so that you can do something more complicated. So, I thought, perhaps the "limit nofile" stuff only works if you're using a simple exec, and for scripts you have to do stuff manually. I added a

   ulimit -n 16384


...inside the script tag.  But that didn't work.

The next thing was investigate *why* the default upstart config uses the script tag. Best guess is that it's there so that the contents of /etc/default/rsyslog can be read, so that configuration options can be placed in that file. Looking inside /etc/default/rsyslog showed that the default file simply contained this:

   # Options for rsyslogd
   # -x disables DNS lookups for remote messages
   # See rsyslogd(8) for more details
   RSYSLOGD_OPTIONS=""


So, this was basically a no-op -- rsyslog was being run with no options by default. Because I hadn't needed to customise it, that meant that I could rewrite the upstart script so that the whole "script...end script" block was replaced by

   exec rsyslogd


If the problem was the script block not playing well with the "limit nofile" option, then you'd think that would work. But it didn't.

By this point (5 days in, working on this intermittently) I was clutching at straws, and as a last ditch attempt I tried reverting back to the original upstart script (so, no "limit nofile" bit, and the original "script...end script" stuff sourcing the file from /etc/default), and put a call to "ulimit -n 16384" inside /etc/default/rsyslog, and restarted rsyslog.

It worked.

This seems really weird to me. I can sort-of-kind-of see why the normal "limit nofile" upstart thing might not work, given that rsyslog forks and daemonises itself, though it seems odd that it does work for other processes (and there's a "expect fork" line in there to tell it to handle that kind of behaviour).

But the fact that the ulimit has to be in /etc/default/rsyslog completely baffles me. If it works when it's in a file that is sourced into the script block, then why does it not work inside the script block directly? I'm pretty sure that in normal shell commands, using "." is basically equivalent to running the commands in the file inside your current shell, one-by-one...

Anyway, I hope the solution is useful to someone out there, and that the (somewhat rambling) explanation is of interest to someone too. And if anyone does know the reason why it works in /etc/default/rsyslog but not in the script block, or knows a better solution to the problem, I'd love to hear!


All the best,

Giles

--
Giles Thomas <[email protected]>

PythonAnywhere: Develop and host Python from your browser
<https://www.pythonanywhere.com/>

A product from PythonAnywhere LLP
17a Clerkenwell Road, London EC1M 5RD, UK
VAT No.: GB 893 5643 79
Registered in England and Wales as company number OC378414.
Registered address: 28 Ely Place, 3rd Floor, London EC1N 6TD, UK

_______________________________________________
rsyslog mailing list
http://lists.adiscon.net/mailman/listinfo/rsyslog
http://www.rsyslog.com/professional-services/
What's up with rsyslog? Follow https://twitter.com/rgerhards
NOTE WELL: This is a PUBLIC mailing list, posts are ARCHIVED by a myriad of 
sites beyond our control. PLEASE UNSUBSCRIBE and DO NOT POST if you DON'T LIKE 
THAT.

Reply via email to