Monit + ‘check program’ + Zombies
from Dave Goddard
Monit recently introduced a new type of service to check ; “check program” which will run a script each cycle (or specified number) and will end up being good or bad depending on the exit code. After we started using this, we noticed that the script was often marked as a zombie on the machine ; at first we blamed the script, but eventually discovered that this is expected behaviour by monit, and that monit is planning to fix it RSN (real soon now)
Polymorphic Associations and Active Record Subclasses
from Adam Milligan
If you have a polymorphic association, Rails will use the base class of the parent of the association (as defined by ActiveRecord) as the class name of the associated parent.
class Foo < AR::Base
belongs_to :wibble, polymorphic: true
class Bar < AR::Base
has_many :foo, as: :wibble
class Baz < SomeSubclassOfActiveRecordBase
has_many :foo, as: :wibble
The class of the wibble association when instantiated for Bar will be Bar.
The class of the wibble association when instantiated for Baz will be SomeSubclassOfActiveRecordBase, not Baz, unless SSOARB.abstract_class returns true.
- Ruby 1.9.3
- RVM 1.10.0
- Mac OSX 10.7.2
- XCode 4.2
Our team ran into an issue installing Ruby 1.9.3 on Lion today. When running…
$ rvm install ruby-1.9.3
… the installer fails with an error message including “checking whether the C compiler works… no” even though we had XCode and gcc installed.
After some reading on StackOverflow and Github I found this solution …
$ rvm install 1.9.3-p0 --with-gcc=clang
… which points an explanation on RVM’s issue tracker .
See our full command line history and error messages below:
$ rvm install ruby-1.9.3-p0
Installing Ruby from source to: /Users/foobar/.rvm/rubies/ruby-1.9.3-p0, this may take a while depending on your cpu(s)...
ruby-1.9.3-p0 - #fetching
ruby-1.9.3-p0 - #extracted to /Users/foobar/.rvm/src/ruby-1.9.3-p0 (already extracted)
Fetching yaml-0.1.4.tar.gz to /Users/foobar/.rvm/archives
Extracting yaml-0.1.4.tar.gz to /Users/foobar/.rvm/src
Configuring yaml in /Users/foobar/.rvm/src/yaml-0.1.4.
Compiling yaml in /Users/foobar/.rvm/src/yaml-0.1.4.
Installing yaml to /Users/foobar/.rvm/usr
ruby-1.9.3-p0 - #configuring
ERROR: Error running ' ./configure -- prefix=/Users/foobar/.rvm/rubies/ruby-1.9.3-p0 --enable- shared --disable-install-doc --with-libyaml- dir=/Users/foobar/.rvm/usr ', please read /Users/foobar/.rvm/log/ruby-1.9.3-p0/configure.log
ERROR: There has been an error while running configure. Halting the installation.
$ cat /Users/foobar/.rvm/log/ruby-1.9.3-p0/configure.log
[2012-01-13 10:31:49] ./configure -- prefix=/Users/foobar/.rvm/rubies/ruby-1.9.3-p0 --enable-shared --disable-install-doc --with-libyaml- dir=/Users/foobar/.rvm/usr
configure: WARNING: unrecognized options: --with-libyaml-dir
checking build system type... x86_64-apple-darwin11.2.0
checking host system type... x86_64-apple-darwin11.2.0
checking target system type... x86_64-apple-darwin11.2.0
checking whether the C compiler works... no
configure: error: in `/Users/foobar/.rvm/src/ruby-1.9.3-p0':
configure: error: C compiler cannot create executables
See `config.log' for more details
Advice for Rails Performance Optimization
Recently, our team releasing to a large set of users and needed to ensure that our application could meet the performance needs of the new users. Launch day was a month away. Months of steady Agile feature development needed to meet a healthy amount performance engineering.
We started with a few goals in mind. We wanted:
- data-driven improvements
- to prefer simple performant code to complex caching strategies
- to use available tools to provide visualization for badly performing requests
Plan a Solution
We brainstormed for ideas on what would reliably lead us in the right direction. Requests per second (and seconds per request) were useful data points that we were able to get from Apache Benchmark (ab). Using AB we could make a change, run the benchmark, and be sure that the change made a positive performance impact. One obvious way to get requests per second to increase is to use caching. Our team was hesitant to use caching for several reasons:
- there are many user-specific features
- caching increases the complexity of your codebase when dealing with cache population and invalidation strategies
- we felt that we could meet our performance needs without caching by employing a few other tools
To track down specific bottlenecks we used Ruby Benchmark. We could perform an Outside-in performance analysis of specific actions, benchmarking deeper and deeper, until specific methods or database calls stood out as obvious problems.
The Big Wins
A few things stood out as Big Wins for us:
- Missing database indexes often came up as a cause for slowness. Often there were non-foreign key columns that had not been indexed but were being used in a WHERE or a JOIN. The MySQL slow query log led us to several major culprits.
- We could see from our New Relic graphs that while iterating and rendering the same exact view with a different user, we would see a large spike of time spent rendering. This smelled to us of garbage collection. We turned on Rack::Bug and quickly noticed that we were performing 6 garbage collections during one request. We had read a blog article from Sam Coward about using Ruby Enterprise Edition Garbage Collection statistics gathering to track down object allocation and garbage collection problems. (http://pivotallabs.com/users/scoward/blog/articles/1411-identify-memory-abusing-partials-with-gc-stats) We installed his patch to Rack::Bug which displays memory usage information for each ActionView template that is rendered. From there we were able to use our outside-in benchmarking to find our offensive memory hogs and make them more friendly. We found out later that New Relic has released an RPM that also graphs time spent in garbage collection.
- This led us to our final optimization. We had removed most of our GC time, but still had not taken advantage of the Ruby Enterprise GC variables. Our servers are hosted with Blue Box Group (http://www.blueboxgrp.com/) and their service staff helped us eek out the last bit of memory performance. They worked with us to tweak our Ruby Enterprise Edition garbage collection variables to the most optimum settings.
What We Learned
In the end, we learned a few things about optimization.
- There are many things you can do easily to improve performance without resorting to complex solutions.
- A data driven approach can lead you quickly to a good solution.
- Use tools that can give you visibility into your performance bottlenecks.
- Set a realistic performance goal to meet. Your site can always perform better. The real question is, how much performance do you need?
These are the obvious, well-covered topics of performance enhancement. There’s a reason. They can take your application a long way.
Thanks to Evan Farrar for much of the wisdom that went into our performance optimization thought process.