I have an application that listens for SNMP traps using Net::SNMPTrapd. It examines the trap, discards most, and does some work (taking about 5ms) with a few of them. The rate of traps coming in is considerable (>100/s). The current version can handle that rate, but I'd like to make it more scalable. To that end, I've rewritten it with a master process controlling multiple worker threads.
The master process creates a lockfile that the worker threads then use to control access to port 162. The worker threads sit in a loop blocking on flock(). When they succeed in getting the lock, they get a trap from port 162 using Net::SNMPTrapd and give up the lock. Here are the basics of what each worker thread does:
my $snmptrapd = Net::SNMPTrapd->new(ReusePort => 1); while (1) { flock($lockfile,LOCK_EX); my $trap = $snmptrapd->get_trap(); flock($lockfile,LOCK_UN); # filter traps based on IP, etc. here $trap->process_trap(); # do some work here, usually taking 3-5ms }
All this works. However, I find that regardless of the number of worker threads I create, one of them does most - about 70% - of the work. That is OK for now - one thread can handle it at the current volume of traps - but that seems to defeat my object of scalability.
I have tried several methods to encourage the hardest-working thread to sit back and allow the others a turn. The one that I thought made sense was having each thread keep track of how many traps it's received and do a sub-second sleep when its trap count crosses a threshold. That just resulted in dropped traps.
Is there some technique I'm missing here? Running on Perl 5.16 on CentOS 7. Thank you!
In reply to worker threads - one does all the work by jvuman
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |