Re: problems with fastcgi performance & ruby

"Zev Blut" <[email protected]>
Newsgroups gmane.comp.web.fastcgi.devel
Message-ID <[email protected]>
Hello,

On Tue, 2 Nov 2004 14:11:05 +1100, Andrew Stuart  
<[email protected]> wrote:

> It is all working a running but the performance is not what I had  
> expected
> and certainly not what is needed to run a production web application.

What are you expecting?  Are you trying to optimize for throughput or
latency?  From you tests below I am guessing throughput.  What are
your metrics for a "production web application"?  Which costs more
developer time or hardware?  If developer time is more valuable you
can always buy more hardware and load balance   it for increased
throughput.


Here are a few points with regards to your tests:

1) The scripts you are trying to compare against are not all the
same. For example your env Ruby scripts are still more complex than
your PHP script.  If you want meaningful data you should try to test
with programs that are generating the same result (or as much as
possible when it comes to echoing the environment). You should probably
just start with benchmarking echo.

Note:
Your echo scripts are not the same either.  The example c echo script
does not sort the environment.  So you should not sort the environment
in your Ruby script either.  I have provided two Ruby scripts below
that are a little bit closer to matching the C example.

2) Below is your Apache configuration of mod_fastcgi:

> LoadModule fastcgi_module modules/mod_fastcgi.so
>
>  <IfModule mod_fastcgi.c>
>
>     # URIs that begin with /fcgi-bin/, are found in /var/www/fcgi-bin/
>     Alias /fcgi-bin/ /var/www/fcgi-bin/
>
>     FastCgiIpcDir /var/fcgi/
>     #FastCgiConfig -autoUpdate
>
>     # Anything in here is handled as a "dynamic" server if not defined as
> "static" or "external"
>     <Directory /var/www/fcgi-bin/>
>         Order allow,deny
>         Allow from all
>         SetHandler fastcgi-script
>         Options +ExecCGI
>         #Require user andrewstuart
>     </Directory>
>
>     # Anything with one of these extensions is handled as a "dynamic"  
> server
> if not defined as
>     # "static" or "external". Note: "dynamic" servers require ExecCGI to  
> be
> on in their directory.
>     AddHandler fastcgi-script .fcgi .fpl
>
>     # Start a "static" server at httpd initialization inside the scope of
> the SetHandler
>     FastCgiServer /var/www/fcgi-bin/examples/echo -processes 5
>
>     # Start a "static" server at httpd initialization inside the scope of
> the AddHandler
>     #FastCgiServer /var/www/fcgi-bin/examples/echo
>
>     # Start a "static" server at httpd initialization outside the scope  
> of
> the Set/AddHandler
>     #FastCgiServer /var/www/htdocs/some/path/coolapp
>     <Directory /var/www/html/ruby>
>         SetHandler fastcgi-script
>     </Directory>
>
> </IfModule>

Notice that FCGI c echo example is is set to start with 5 processes
 from the beginning.  Try making all of your test scripts match that
statement.


For example:
FastCgiServer /var/www/htdocs/some/path/coolapp/ruby_echo.rb -processes 5

As you are attempting to do 100 parallel requests, you may want to
play with increasing the processes number to see if that helps improve
throughput.

3) Below are sample runs from my development machine:
Dual Processor Pentium III 750 MHz
Redhat 9
Apache 2
FCGI 2.4.0
mod_fcgi 2.4.0
Ruby 1.8.2 (2004-05-24) [i686-linux]

############################################################
# with both apps set to 5 processes
############################################################
# Ruby echo
# Note: I did not include the standard input check, as I am not
# exactly  sure how I would simulate this.
# Plus the Initial environment is the same output either.
# But it is closer to what the c version does.
------------------------------------------------------------
#!/usr/local/bin/ruby
require 'cgi'
require 'fcgi'

def print_env(title,env)
   str = "#{title}:<br>\n<pre>\n"
   env.each do |k,v|
     str<<"#{k}=#{v}\n"
   end
   str<< "</pre><p>\n"
end

count = 0
FCGI.each_cgi do |cgi|
   count += 1
   content = "<title>FastCGI echo</title><h1>FastCGI echo</h1>\n"
   content<< sprintf("Request number %d,  Process ID: %d<p>\n", count,  
Process.pid)

   content<< print_env("Request environment", cgi.env_table)
   content<< print_env("Initial environment", ENV) # not sure if that is  
what is intended for the c impl.

   cgi.out{content}
end
------------------------------------------------------------
#############################################################
***** Ruby Version *****
$ ./http_load -parallel 100 -seconds 20 ruby_url.txt 2> /dev/null
9031 fetches, 100 max parallel, 8.05197e+06 bytes, in 20.0063 seconds
891.592 mean bytes/connection
451.408 fetches/sec, 402472 bytes/sec
msecs/connect: 3.05451 mean, 164.012 max, 0.104 min
msecs/first-response: 125.278 mean, 743.138 max, 6.421 min
5345 bad byte counts
HTTP response codes:
   code 200 -- 9031

***** C Version *****
./http_load -parallel 100 -seconds 20 c_url.txt 2> /dev/null
16177 fetches, 100 max parallel, 1.6673e+07 bytes, in 20.0104 seconds
1030.66 mean bytes/connection
808.431 fetches/sec, 833216 bytes/sec
msecs/connect: 2.21553 mean, 75.915 max, 0.095 min
msecs/first-response: 55.6049 mean, 488.322 max, 4.388 min
16134 bad byte counts
HTTP response codes:
   code 200 -- 16177

############################################################
# without setting the processes
############################################################
***** Ruby Version *****
$ ./http_load -parallel 100 -seconds 20 ruby_url.txt 2> /dev/null
6706 fetches, 100 max parallel, 5.98064e+06 bytes, in 20.0051 seconds
891.835 mean bytes/connection
335.214 fetches/sec, 298956 bytes/sec
msecs/connect: 0.970607 mean, 73.495 max, 0.115 min
msecs/first-response: 294.584 mean, 524.954 max, 80.764 min
6697 bad byte counts
HTTP response codes:
   code 200 -- 6706

***** C Version *****
$ ./http_load -parallel 100 -seconds 20 c_url.txt 2> /dev/null
12016 fetches, 100 max parallel, 1.23894e+07 bytes, in 20.0001 seconds
1031.08 mean bytes/connection
600.798 fetches/sec, 619468 bytes/sec
msecs/connect: 1.25415 mean, 151.896 max, 0.113 min
msecs/first-response: 159.242 mean, 550.63 max, 10.673 min
12007 bad byte counts
HTTP response codes:
   code 200 -- 12016

############################################################
# Ruby with 20 processes
############################################################
$ ./http_load -parallel 100 -seconds 20 ruby_url.txt 2> /dev/null
8649 fetches, 100 max parallel, 7.70597e+06 bytes, in 20.0581 seconds
890.967 mean bytes/connection
431.198 fetches/sec, 384183 bytes/sec
msecs/connect: 3.0964 mean, 126.724 max, 0.108 min
msecs/first-response: 133.628 mean, 1024.41 max, 4.549 min
8470 bad byte counts
HTTP response codes:
   code 200 -- 8649

############################################################
# Below is another implementation of echo in Ruby, this time
# without creating a cgi instance.
# This shows that if performance is a critical issue you will need to
# watch what you  create.
------------------------------------------------------------
#!/usr/local/bin/ruby
require "fcgi"


def print_env(title,env)
   str = "#{title}:<br>\n<pre>\n"
   env.each do |k,v|
     str<<"#{k}=#{v}\n"
   end
   str<< "</pre><p>\n"
end

count = 0
FCGI.each do |request|
   count +=1

   out = request.out

   content = "<title>FastCGI echo</title><h1>FastCGI echo</h1>\n"
   content<< sprintf("Request number %d,  Process ID: %d<p>\n", count,  
Process.pid)

   content<< print_env("Request environment", request.env)
   # not sure if that is what is intended for the c impl.  In this example  
ENV is empty.
   content<< print_env("Initial environment", ENV)

   out.print "Content-Type: text/html\r\n"
   out.print "Content-Length: #{content.size}\r\n"
   out.print "\r\n"
   out.print content
   request.finish
end
------------------------------------------------------------
############################################################
$ ./http_load -parallel 100 -seconds 20 n_ruby_url.txt 2> /dev/null
12172 fetches, 100 max parallel, 1.12779e+07 bytes, in 20.0209 seconds
926.546 mean bytes/connection
607.966 fetches/sec, 563308 bytes/sec
msecs/connect: 2.46843 mean, 135.91 max, 0.097 min
msecs/first-response: 98.272 mean, 443.003 max, 2.215 min
12130 bad byte counts
HTTP response codes:
   code 200 -- 12172
############################################################

Quick Summary:
5 Processes Ruby
451.408 fetches/sec

No CGI Object Ruby 5 Processes
607.966 fetches/sec

5 Processes C
808.431 fetches/sec

No Processes C
600.798 fetches/sec,

No Processes Ruby
335.214 fetches/sec,

20 Processes Ruby
431.198 fetches/sec,


I hope this helps.
Best,
Zev

___________________________________
fastcgi-developers mailing list
http://fastcgi.com/fastcgi-developers/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.