Looking in a way to use ruby to make some servers (like
http,pop3,smtp) I discovered that the TCPServer implementation doesn’t
allow set the queue_length size that is passed to “listen” and it uses
a fixed value of “5”.
That value is too low for a high trafic server every implementation I
looked in (GServer, wwwd, httpserver) uses the TCPServer call to
initialize the listen master socket and when we test it with
concurrent connections it simply blocks for a long time on my linux
machines.
Changing the interface to allow set the queue length make it works
under load.
diff from the ruby-1.6.7/ext/socket/socket.c
cut from here ------------------------------------------
787c787
< open_inet(class, h, serv, type)
···
open_inet2(class, h, serv, queue_length, type)
873c873
< listen(fd, 5);
listen(fd, FIX2INT(queue_length));
880a881,888
open_inet(class, h, serv, type)
VALUE class, h, serv;
int type;
{
return open_inet2(class,h,serv,5,type);
}static VALUE
1042c1050,1065
<
switch(argc){ case 1: return open_inet2(class, 0, argv[0], INT2FIX(5), INET_SERVER); break; case 2: return open_inet2(class, argv[0], argv[1], INT2FIX(5), INET_SERVER); break; case 3: return open_inet2(class, argv[0], argv[1], argv[2], INET_SERVER); break; default: rb_raise(rb_eArgError, "You must supply 1 to 3 parameters."); break; }
/*
1046a1070
*/
cut to here ------------------------------------------
After applying this patch the TCPServer accepts a third parameter for
the queue_length:
TCPServer.new(host,port,queue_length=5)
Old code should remain working since the default value is what was
used before hard coded.
If you whant to test the difference setting the queue length you can
use the apache utility called “ab” short for “apache bench”.
code example 1:
cut form here--------------------------------------------
require ‘socket’
port = (ARGV[0] || 9999).to_i
server = TCPServer.new(‘127.0.0.1’,port)
while (session = server.accept)
puts “Request: #{session.gets}”
session.print “HTTP/1.1 200/OK\r\nContent-type: text/html\r\n\r\n”
session.print “
#{Time.now}
\r\n”session.close
end
cut to here--------------------------------------------
using : “ab -c 1 -n 100 http://127.0.0.1:9999/”
requests per second = 622
time taken : 0.16 seconds
using : “ab -c 20 -n 100 http://127.0.0.1:9999/”
requests per second = 6
time taken : 16.22 seconds
code example 2:
cut form here--------------------------------------------
require ‘socket’
port = (ARGV[0] || 9999).to_i
server = TCPServer.new(‘127.0.0.1’,port,511)
while (session = server.accept)
puts “Request: #{session.gets}”
session.print “HTTP/1.1 200/OK\r\nContent-type: text/html\r\n\r\n”
session.print “
#{Time.now}
\r\n”session.close
end
cut to here--------------------------------------------
using : “ab -c 1 -n 100 http://127.0.0.1:9999/”
requests per second = 622
time taken : 0.16 seconds
using : “ab -c 20 -n 100 http://127.0.0.1:9999/”
requests per second = 622
time taken : 0.16 seconds
using : “ab -c 100 -n 1000 http://127.0.0.1:9999/”
requests per second = 600
time taken : 1.6 seconds
All tests was done in a celeron 700MHZ with linux 7.3