Last checked about 2 hours ago.
2 people have subscribed to this feed.
post frequency (last month)
PostRank™
From Webficient, 1 month ago,
0 comments
From Webficient, 1 month ago,
0 comments
From Webficient, 1 month ago,
0 comments
From Webficient, 2 months ago,
0 comments
From Webficient, 2 months ago,
0 comments
From Webficient, 2 months ago,
0 comments
From Webficient, 3 months ago,
0 comments
From Webficient, 3 months ago,
0 comments
From Webficient, 3 months ago,
0 comments
From Webficient, 3 months ago,
0 comments
From Webficient, 3 months ago,
0 comments
From Webficient, 3 months ago,
0 comments
From Webficient, 4 months ago,
0 comments
Rails 2.1 introduced the ability to specify which RubyGems are required by your application, making it much easier to replicate an environment across developer machines and servers. In environment.rb you can list dependencies as follows:
1 2 3 4 5 |
Rails::Initializer.run do |config| config.gem 'haml', :version => '>= 2.0.1' #any version >= to 2.0.1 config.gem 'pdf-writer', :lib => "pdf/writer" #latest version config.gem 'will_paginate', :version => '2.2.2' #identical version end |
However, if you have a plugin dependent on a gem which is not yet installed, you’ll more than likely see something like this when running the new rake gems command.
1 2 |
rake aborted! no such file to load -- some_missing_gem |
For example, during an upgrade of a Rails 1.x project which uses the Railspdf plugin, a reference to ‘pdf/writer’ led to the aborted rake task.
vendor/plugins/railspdf/lib/railspdf.rb:1 |
require 'pdf/writer'
|
Usually, running a rake task like rake gems initializes all Rails plugins. How do we know this? Adding “—trace” to the end of your rake task will show you the backtrace of everything that’s happening. You’ll notice that the framework calls rails/railties/lib/initializer.rb, responsible for loading plugins. So in this example, while Rails was trying to load the Railspdf plugin, it could not find the required pdf-writer gem.
A quick fix is to update the plugin to check for the presence of the gem:
vendor/plugins/railspdf/lib/railspdf.rb:1 |
require 'pdf/writer' if defined? PDF::Writer |
(Thanks to Dan Munk for this tip!)
The disclaimer here being that you should make rake gems a required part of your application deployment process. Otherwise, your plugin functionality will fail at runtime if the required gem is missing. Interestingly, Rails does a check for missing gems upon startup but does not prevent Mongrel from running.
So what if you do want Mongrel to abort if any dependencies are missing? If your application includes a frozen copy of the Rails framework, you can edit vendor/rails/railties/lib/initializer.rb by adding a call to ‘abort’ method (an alias for Process::abort) to the existing check_gem_dependencies method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
def check_gem_dependencies unloaded_gems = @configuration.gems.reject { |g| g.loaded? } if unloaded_gems.size > 0 @gems_dependencies_loaded = false # don't print if the gems rake tasks are being run unless $rails_gem_installer puts %{These gems that this application depends on are missing:} unloaded_gems.each do |gem| puts " - #{gem.name}" end puts %{Run "rake gems:install" to install them.} + abort end else @gems_dependencies_loaded = true end end |
If you’d like to take a less intrusive approach (or aren’t including a copy of Rails in the vendor directory), you can monkey patch check_gem_dependencies within your application.
Create a new file in app/config named check_gems.rb and add the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
unless defined?(Rake) module Rails class Initializer alias old_check_gem_dependencies check_gem_dependencies def check_gem_dependencies old_check_gem_dependencies unloaded_gems = @configuration.gems.reject { |g| g.loaded? } abort if unloaded_gems.size > 0 end end end end |
Then, add the following line to environment.rb:
1 |
require File.join(File.dirname(__FILE__), 'check_gems') |
The net result is that if any ‘unloaded’ gems are found, the current Ruby process will end.
For those of you wondering if the above could be added to a Rails initializer, the answer is no. The current version of the Rails Initializer class will not load any application-specific initializers if any gem dependencies are not met.
The PeepCode Rails 2.1 PDF has good coverage about Gem dependencies and freezing Rails.
Initializers are discussed in Stop Littering In Your Environment File.
Monkeypatching has an entry in the Wikipedia and is covered from a Rails perspective in The Virtues of Monkey Patching.
From Webficient, 4 months ago,
0 comments
In a previous article, we installed and tested a baseline configuration of Phusion Passenger, aka mod_rails. In this post, we’ll be comparing memory usage and performance by varying Apache configuration settings in httpd.conf.
Realize that these numbers aren’t absolutes and will vary on your server, depending on its architecture, CPU, and RAM. Our VPS slice has the following specs:
We used Apache Bench for testing:
1 |
# ab -n 10000 -c 100 http://server/app_path |
PassengerMaxPoolSize specifies the maximum number of Ruby on Rails application instances that may be simultaneously active. This setting has a lot of bearing on overall memory consumption and performance.
Memory Usage
1 2 3 4 5 6 |
PassengerMaxPoolSize total used free shared buffers cached
1 524460 417040 107420 0 21384 120216
2 524460 454740 69720 0 22560 127080
3 524460 489692 34768 0 23160 131860
4 524460 494548 29912 0 19860 110868
5 524460 516772 7688 0 19100 103628
|
Performance
1 2 3 4 5 6 |
PassengerMaxPoolSize Requests per second
1 89.09 [#/sec] (mean)
2 170.28 [#/sec] (mean)
3 224.88 [#/sec] (mean)
4 274.94 [#/sec] (mean)
5 272.45 [#/sec] (mean)
|
You’ll notice that our sweet spot is when PassengerMaxPoolSize = 4, since we did not gain any more performance when set to 5, and less memory is used.
According to the docs, PassengerMaxInstancesPerApp is the maximum number of application instances that may be simultaneously active for a single application. The recommendation is to have the value be less than PassengerMaxPoolSize. Trying different values, ranging from 1 to 3, we observed memory consumption to be a bit less, however the number of requests per second also suffered. We found that setting the value to 0, or no limit, produced the best results performance-wise. If you’re experiencing heavy swapping on a smaller slice, on the other hand, capping this value at something between 0 and PassengerMaxPoolSize will help.
If you’re curious about seeing the impact of the above settings on your own configuration, be aware of the following.
As physical memory is used up, your machine will start swapping virtual memory to disk. So be aware of any background processes already running. Disable any cron jobs, scheduled backups, etc.
A software firewall like Linux IP Tables tracks each connection and temporarily persists a handle in a built-in database. It’s entirely possible to overwhelm the system, which will affect your numbers. Your Linux kernel log will show this message: “ip_conntrack: table full, dropping packet.” For an explanation of this issue and how to solve it, see this article.
From Webficient, 4 months ago,
0 comments
In a previous article, we looked at the performance and memory usage of a Ruby on Rails application running on Passenger Phusion (mod_rails). In this post, we’ll compare the same app running on the Thin Web server behind an Nginx cluster.
Thin uses the Mongrel parser and Event Machine I/O library. In addition, it uses the Rack interface, allowing you to run other frameworks besides Ruby on Rails.
In a proxying scenario, where Nginx is the “front-end” for the Thin application server, you can leverage Unix domain sockets, which can boost performance and memory usage. Not all HTTP load balancers support it though.
To recap our testing configuration, we’re running a 512MB VPS slice (courtesy of Slicehost.com), and using Apache Bench to load test the login page of our Ruby on Rails blogging platform. This page is not cached but there isn’t a database call either, so our performance numbers don’t include any backend interaction. For other details, refer to the “Benchmark Overview” in our previous post.
Our first test used 4 Unix domain sockets, which are configured as follows, in nginx.conf:
1 2 3 4 5 6 |
upstream webficient {
server unix:/tmp/thin.0.sock;
server unix:/tmp/thin.1.sock;
server unix:/tmp/thin.2.sock;
server unix:/tmp/thin.3.sock;
}
|
Then, Thin was started up using
thin start -s4 --socket /tmp/thin.sock -e production |
Memory usage under load using Thin/Nginx appeared better than mod_rails (with Ruby Enterprise Edition).
1 2 |
total used free shared buffers cached Mem: 524460 458272 66188 0 7060 82792 |
Requests per second, on the other hand, were a bit slower than mod_rails (246 RPS vs. 292 RPS with mod_rails) but significantly faster than standard Mongrel.
Dynamic Content Load Test – Thin/Nginx
1 2 3 4 5 6 7 8 9 10 11 |
Concurrency Level: 100 Time taken for tests: 40.599507 seconds Complete requests: 10000 Failed requests: 0 Write errors: 0 Total transferred: 30210000 bytes HTML transferred: 25690000 bytes Requests per second: 246.31 [#/sec] (mean) Time per request: 405.995 [ms] (mean) Time per request: 4.060 [ms] (mean, across all concurrent requests) Transfer rate: 726.63 [Kbytes/sec] received |
Seeing that we had a surplus of available memory during load testing, we tweaked the number of Unix domain sockets to evaluate the effect on overall performance. However, going from 4 to 5 sockets did not improve performance significantly. Dropping down to 3 sockets decreased performance. Therefore, our recommendation for a 512MB VPS slice is 4 sockets. In another test, we doubled Nginx’s number of worker_processes from 3 to 6, however, this did not significantly improve Thin’s numbers either.
While slightly slower than mod_rails, Thin significantly outperforms a vanilla Mongrel Cluster/Nginx configuration. Thus, Thin is a viable solution to those who prefer Nginx to Apache. Recall that previous benchmarks show Nginx is the clear leader in serving up static content. So if your site uses caching extensively, you may want to consider this setup. Otherwise, Phusion Passenger will give you the best bang for the buck.
Another consideration is stability. Thin has been out for quite some time and has had 7 or so releases. Mod_rails is relatively new and not without issues, as seen in its Google group and blog posts. We’ll expect things to improve quickly in this area.