[syslog-ng] Setting UDP Receive Buffer size, then when increase performance problems

James hartsjc at unloyal.com
Fri Jul 28 20:44:43 CEST 2006


SUMMARY:

Due to the large number of UDP packets (aprox: 6,700 per second) coming 
into our syslog-ng (version 1.6.4) running on an HP-UX 11.11 server we 
have had a desire to increase the receive buffer for UDP.  I could NOT 
find a way to do this in syslog-ng, so we changed the default at the OS 
level (socket_udp_rcvbuf_default).  Has it been considered (or possibly 
already added) to allow this option to be specified in the config file?

Increasing this buffer size, seemed to cause  a performance problem 
because syslog-ng (again at least on HP-UX 11.11) has POLLIN set to 
POLLRDNORM|POLLRDBAND (default when _XOPEN_SOURCE_EXTENDED is set) which 
must mean the OS walks the entire buffer looking for priority message when 
poll() is called.  Since syslog-ng appears to do a poll(), then 1 read(), 
followed by another poll(), the OS is walking the entire buffer, and then 
only reading 1 entry.  During the time the OS spends walking this buffer, 
hundreds of packets have been added.  Thus, syslog-ng can reach a point of 
no return as long as data keeps coming in at this rate.  I did a quick 
change in io.c to override the POLLIN setting HP-UX sets for syslog-ng to 
the value it would use if _XOPEN_SOURCE_EXTENDED was NOT set (0x0001). 
This change seems to work for us, but more details and maybe another 
option is mentioned in my details below.







DETAILS:

We have an HP-UX system that is regularly receiving 6,700 log entries per 
second from several systems via UDP.  Originally we tried handling this 
workload with one daemon, but was CPU constrained due to it being single 
threaded.  We then split the work among 3 daemons each on their own 
virtual IP so we could utilize the other CPUs in the system.  We also 
increased socket_udp_rcvbuf_default (default receive buffer size for UDP) 
from 65K to 75mb - 150mb.  It would be nice if the syslog-ng config file 
allowed us to set this value instead of impacting ALL UDP listeners on the 
system.  I have edited our copy of io.c to include something like the 
following.  This example is crude, but seems to work for us setting 75Mb 
buffer (I hard coded the value, but obtaining from the config file would 
be a better solution):

    int Buffer = 78643199;
    socklen_t Len = sizeof(Buffer);

    if ( (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &Buffer, Len)) == 0 ) {
      Buffer=0;
      getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &Buffer, &Len);
      debug("io.c: SO_RCVBUF now set to: %i\n", Buffer);
    }
    else {
      werror("io.c: setsockopt() failed setting SO_RCVBUF (errno %i), %z\n", errno, strerror(errno));
    }


However, this can lead to another problem with syslog-ng (at least on on 
HP-UX).  Once the buffer starts to fill the OS starts spending a LOT of 
CPU in system time.  This appears to be because of the socket options 
specified due to _INCLUDE_XOPEN_SOURCE_EXTENDED being set during compile. 
On HP-UX 11.11 poll.h sets POLLIN to (POLLRDNORM|POLLRDBAND) when 
_INCLUDE_XOPEN_SOURCE_EXTENDED is defined.  It is my understanding that 
this means the OS will walk the entire buffer looking for a priority 
message when syslog-ng calls poll() to look for the next packet.  Once we 
increase the buffer past the 65K default in HP-UX this walking can take 
some time and lots of system CPU time (hate to see this if buffer was set 
the the 2GB maximum).  Overriding the POLLIN options to the setting poll.h 
would use if _INCLUDE_XOPEN_SOURCE_EXTENDED was NOT defined (0x0001) seems 
to resolve this problem, and actually allows syslog-ng to empty out this 
large UDP buffer space very quickly.

Another solution (which looks like may have been talked about in a post 
from John Morrissey) may be to change the way syslog-ng loops on the UDP 
socket. It appears to me that syslog-ng is currently doing:
   poll()
   read()
   Back to poll()

This delay maybe could only be encountered once if syslog-ng was to do 
something like:
   poll()
   read() with O_NONBLOCK set
   if return -1 with EAGAIN, Back to poll()
   else Back to read() with O_NONBLOCK set

I am not sure what impact this would have if syslog-ng was receiving data 
from more than one UDP socket (which is what we do) as it may spend too 
much time doing emptying the one buffer while the other data listeners 
wait.


Have concerns like this already been addressed in more current releases? 
Do these issues I have seen HP-UX concerns for other operating systems, or 
should I just continue to modify the standard syslog-ng code as there 
would be little to no benefit for others?

Thanks,
/James


More information about the syslog-ng mailing list