Rails 3 Passenger Lag - ruby-on-rails

I've setup my website with Rails 3 and Passenger (via nginx) and, although its only being used by one person, the web server has to essentially wake up the rails instance to render the page. This happens only when the website is not accessed for a while (hence its sleeping), but I'm a little paranoid that could it still lag like so when the website is operating on a production level (don't get mixed with the development/production mode, the sleeping website is running in production mode when I'm checking it out).
Any ideas? Or this just a sleep and wakeup thing when nobody's using the website.

There is an easy fix just edit your nginx.conf and set passenger_min_instances to a value larger then zero. This way passenger always keeps one instance alive; this will prevent the "lag" as you describe it. Read more about it in the Passenger Nginx documentation.

Take a look at passenger_pool_idle_time. It states the maximum number of seconds that an application instance may be idle. That is, if an application instance hasn’t received any traffic after the given number of seconds, then it will be shutdown in order to conserve memory.

Related

Apache/Passenger/RoR Slow - But Why

I am running Ubuntu (64Bit) with Apache 2.2.17, Passenger 3.0.11, Ruby 1.9.3 and Rails 3.2.6
When accessing the web page (index.html) on my webpage the request takes ages to complete, somewhere around 30 second in extreme cases.
The server has plenty of memory available (top shows more than 4GB free), the Apache processes (there are 10 of them) each show 0% CPU in top and the load is also almost 0 and there are hardly any DB accesses as I cache most of the things with memcached.
The log files of Apache as well as Rails do not show any errors, on the contrary the render times shown in the RubyOnRails log file show excellent values (<100 ms).
So where to go from here?
Is the first request slow or all requests slow? Passengers shutdown after a given time interval. So intermittenly requests (requests with sufficient time span in between) will allow passengers to shutdown (only to be restarted at next request.
Passenger does the autoshutdown BY DESIGN. This is so because on a shared environment, there might be other user's apps. If your app is idle for a while, then the resources can be transferred to other people's app.
If you are on a tight budget and you have multiple apps hosted on the same server, then passenger is a great solution.
If you have only ONE app in your server which you control, then please reconfigure Passengers to NOT shutdown (if that indeed is your problem).
You can do "passenger-status" to see how many passengers are currently running and available for taking requests.
The configuration to ensure that Passengers stay up is PassengerMinInstances and PassengerPoolIdleTime.
Are you accessing it through a 'fake domain name' (added to your /etc/hosts file)?
If so, do
service avahi-daemon stop
At least that's what worked for me on ubuntu 10.10 :)
For some reason a DNS lookup is made on each and every request you do to the server, and when the domain doesn't exists, it times out ...
The performance issue has been keeping me busy for all these days. I believe I have nailed it down to Apache configuration: KeepAliveTimeout, it was set to a very high value (90), can't think why it was set that high, must have been a typo.
My understanding of KeepAliveTimeout is that the Apache process gets locked to the client for 90 seconds, even if the client isn't issuing any further requests, hence when traffic picks up (which it did on that day when performance was significantly reduced, page visits more than tripled) all Apache processes are busy waiting for the KeepAliveTimeout, while blocking all new requests coming in. This would also explain why the system was not showing much load at all, it was just sitting there waiting. I reduced the value down to 10, if traffic picks up I'll probably drop it to 5.

How should I build a VPS that will host multiple small Rails applications?

Up until now, I've always built my VPS dedicated to running just a single application in multiple instances, mostly with Unicorn. That way I could set up the whole environment to fit perfectly for that one specific application and be happy with it.
But now I need to build a VPS, that will host multiple small Ruby applications. Some of them will be Rails and some Sinatra. They will have basically zero traffic (under 100 visits per day), which means I don't even need multiple instances of a single app.
I don't really have experience with other servers than unicorn + nginx, but what I think I need would look something like this.
request to app1, gets loaded into memory and serves the request
request to app2, gets loaded into memory and serves the request
request to app3, there is not enough free memory
app1 gets killed before the app3 is booted to serve the request
I know this isn't an exactly perfect scenario, but imagine having a 10 or 20 small apps on a single server, where each app gets 5 hits a day. They don't exactly need to be up and running at all times.
As far as I know, Heroku does this with their free tier, where Dynos get killed after some idle time, and then they get loaded back up when a request comes in. That's basically what I need to do on my own server.
I would recommend using Apache + Passenger. Passenger by default loads the application only when you need it, e.g. the first request will take a bit longer (actually as long as it takes to load your framework).
If the application is idle for some predefined time, it will be removed from memory.
Setup is very easy and adding new applications is just adding one line in your apache configuration.

Change the Passenger application pool size at runtime

Is it possible to change the Passenger application pool size at runtime? Ie, without restarting apache, and without disrupting active visitors?
The same time every day we have a background job run. It is very memory intensive. Since during that time, traffic on the site tends to be relatively low, I would like to automatically scale down the number of application servers running just before the jobs runs, and then scale up again when it is finished.
Passenger should automatically shut down instances when they are not in use. Since your traffic is low then you should not have any unnecessary passenger instances running.
One variable you can tweak is PassengerPoolIdleTime. This tells passenger how long to wait before shutting down idle instances.
There is no PoolSize variable. There is however a MaxPoolSize but this limit should not be hit unless you are receiving heavy traffic.
You can find all the variables along with what they do here: http://www.modrails.com/documentation/Users%20guide.html
If you really want to change the settings dynamically, you can try calling sudo /etc/init.d/apache2 reload. This will tell apache to reload its settings, including the passenger configuration.
Good luck!

My passenger powered Rails app sometimes needs a long time to load

I use Apache + Passenger to host some Rails applications. Something seems to go in a sleep mode when there is no request for a longer time. It then takes 10-20 seconds for the site to load. Feels like there is something that has to wake up when there have been no requests for a longer time.
How can I fix that? I have enough RAM so it should be no problem if whatever goes to sleep just stays awake. ;)
Take a look at the PassengerPoolIdleTime parameter for Passenger.
It states the maximum number of seconds an application instance can be idle before it shuts down to conserve memory.
The default is 300, but you could try to set a higher number and see if that helps.
Also, if you're on a shared host and can't change that setting, you could always write a cron script to hit your site once every x seconds (where x is slightly less than PassengerPoolIdleTime), and update your analytics package to ignore requests from the IP address of the box that's doing the polling.
The passenger documentation recommends setting the PassengerPoolIdleTime to 0 on non-shared hosts that are running only a few Rails apps. That should prevent it from getting unloaded unless it's absolutely necessary.
#x0ne, you can set PoolIdleTime (pool_idle_time in nginx) in the global server configuration. In my installation of Nginx that's /opt/nginx/conf/nginx.conf.
Here's the part of passenger's documentation that covers PoolIdleTime: http://www.modrails.com/documentation/Users%20guide.html#PassengerPoolIdleTime

Slow initial server startup when using Phusion Passenger and Rails

To jump on the band-wagon of Phusion Passenger we've setup a staging server for a small rails app to test things out.
So far it has been very nice to use, it makes installing/configuring and deploying apps a breeze. The problem is the site we're using doesn't get hit very often and it seems to shut down the servers in the background. Meaning when someone goes to the site they have a really long wait until it starts up a new server to handle the request. We've read through the documentation, tried quite a few different set-ups (smart/smart-lv2 modes, passengeridletime etc) and still haven't found a real solution.
After ploughing through Google results we can't really find useful information. Currently we have a cron job that makes a request every-so-often in an attempt to keep the servers running.
Is anyone else experiencing this problem and do you have any advice for a fix?
What's happening is that your Application and/or ApplicationSpawners are shutting down due to time-out. To process your new request, Passenger has to startup a new copy of your application, which can take several seconds, even on a fast machine. To fix the issue, there are a few Apache configuration options you can use to keep your Application alive.
Here's specifically what I've done on my servers. The PassengerSpawnMethod and PassengerMaxPreloaderIdleTime are the configuration options most important in your situation.
# Speeds up spawn time tremendously -- if your app is compatible.
# RMagick seems to be incompatible with smart spawning
# Older versions of Passenger called this RailsSpawnMethod
PassengerSpawnMethod smart
# Keep the application instances alive longer. Default is 300 (seconds)
PassengerPoolIdleTime 1000
# Keep the spawners alive, which speeds up spawning a new Application
# listener after a period of inactivity at the expense of memory.
# Older versions of Passenger called this RailsAppSpawnerIdleTime
PassengerMaxPreloaderIdleTime 0
# Just in case you're leaking memory, restart a listener
# after processing 5000 requests
PassengerMaxRequests 5000
By using "smart" spawning mode and turning off PassengerMaxPreloaderIdleTime, Passenger will keep 1 copy of your application in memory at all times (after the first request after starting Apache). Individual Application listeners will be forked from this copy, which is a super-cheap operation. It happens so quickly you can't tell whether or not your application has had to spawn a listener.
If your app is incompatible with smart spawning, I'd recommend keeping a large PassengerPoolIdleTime and hitting your site periodically using curl and a cronjob or monit or something to ensure the listener stays alive.
The Passenger User Guide is an awesome reference for these and more configuration options.
edit:
If your app is incompatible with smart spawning, there are some new options that are very nice
# Automatically hit your site when apache starts, so that you don't have to wait
# for the first request for passenger to "spin up" your application. This even
# helps when you have smart spawning enabled.
PassengerPreStart http://myexample.com/
PassengerPreStart http://myexample2.com:3500/
# the minimum number of application instances that must be kept around whenever
# the application is first accessed or after passenger cleans up idle instances
# With this option, 3 application instances will ALWAYS be available after the
# first request, even after passenger cleans up idle ones
PassengerMinInstances 3
So, if you combine PassengerPreStart and PassengerMinInstances, Passenger will spin up 3 instances immediately after apache loads, and will always keep at least 3 instances up, so your users will rarely (if ever) see a delay.
Or, if you're using smart spawning (recommended) with PassengerMaxPreloaderIdleTime 0 already, you can add PassengerPreStart to get the additional benefit of immediate startup.
Many thanks to the heroes at phusion.nl!
Just incase there are any nginx server users stumbling upon this question, both the 'PassengerMaxRequests' and 'PassengerStatThrottleRate' directives don't translate to nginx. However the others do:
rails_spawn_method smart;
rails_app_spawner_idle_time 0;
rails_framework_spawner_idle_time 0;
passenger_pool_idle_time 1000;
HTH!
EDIT rails_spawn_method is deprecated in passenger 3
instead use
passenger_spawn_method smart;
everything else is just good till date.
You can also use PassengerMinInstances:
http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerMinInstances
This can be combined with PassengerPreStart
RE:
# Additionally keep a copy of the Rails framework in memory. If you're
# using multiple apps on the same version of Rails, this will speed up
# the creation of new RailsAppSpawners. This isn't necessary if you're
# only running one or 2 applications, or if your applications use
# different versions of Rails.
RailsFrameworkSpawnerIdleTime 0
Just something to add and might be useful.
The default spawn method in the current release
is "smart-lv2", which skips the framework spawner, so setting
the framework spawner timeout wouldn't have effect anyway unless you
explicitly set the spawn method to "smart".
Source:
http://groups.google.com/group/phusion-passenger/browse_thread/thread/c21b8d17cdb073fd?pli=1
If your host is a shared server, like mine, you can't change the settings and are stuck with a cron job.
I had also this problem but I was not able to change the passenger settings because I had no write permission to this file. I found a tool ( http://www.wekkars.com ) that keeps my app responding fast. Maybe this can also be a solution for you.
check the version of passenger. it was RailsSpawnMethod <string> for old versions.
If so (if I remember correctly), replace Passenger with Rails in all the configuration directives or look for old passenger docs for more details

Resources