Nick Sieger: Tag railsconftag:blog.nicksieger.com,2005:TypoTypo2010-11-22T18:07:00+00:00Nick Siegerurn:uuid:be1363d9-dfe0-443e-8248-93aa316228202007-09-14T05:33:00+00:002010-11-22T18:07:00+00:00Gig: Speaking at RailsConf Europe 2007<p>Speaking of keeping busy, <a href="http://www.railsconfeurope.com/cs/railseurope2007/view/e_sess/14961">I’ll be speaking</a> alongside my colleague <a href="http://blogs.sun.com/craigmcc/" title="Craig McClanahan's Weblog">Craig McClanahan</a> at <a href="http://www.railsconfeurope.com/" title="RailsConf Europe 2007 • September 17, 2007 - September 19, 2007 • Berlin, Germany">RailsConf Europe </a> in Berlin next week.</p>
<p>Sun is a Diamond Sponsor at RailsConf again, just like in Portland last May. Part of that sponsorship money pays for a brief keynote spot (filled by Craig) as well as a session or two. So no, I didn’t get my spot through an accepted proposal submission, but that doesn’t mean that the session is going to be a big <a href="http://headius.blogspot.com/2007/09/infoworld-bossies-close-to-my-heart.html">marketing shill</a>.</p>
<p>No, actually Craig and I are part of a small group at Sun that’s embracing Rails in a big way, and we’re going to be launching a site built mostly on Rails later this fall. We’re taking what we think are some novel approaches to building a Rails-based application and we thought we’d share some of those thoughts with you rather than drone on for the session about how great Sun is and what snazzy tools we make. (Although expect to see a subtle plug or two for Sun hardware and tools. Call it product placement rather than overt selling.)</p>
<p>I titled the session “Rails Hydra” because the central idea of the structure of our application is not one Rails app, but many. The UI and views don’t even talk to a database; instead they make use of ActiveResource and RESTful web services, talking to the models living in other Rails applications in the backend. One key point is we’re deploying .war files to JRuby running on Glassfish, thus avoiding headaches of morbidly multiplying Mongrel math. We’ll elaborate on this arrangement and talk about some of the other tools and tricks we’re using.</p>
<p>Also, Charlie, Tom and Ola will be there, so we’ll certainly have a JRuby summit at some point. Stop by and say hello!</p>Nick Siegerurn:uuid:b09ae6ba-f3b3-4624-a962-227b9646560e2008-06-01T22:07:33+00:002010-11-22T18:11:35+00:00JRuby Q & A at RailsConf<p>These are the notes I took during our “panelish” Q & A session on Sunday afternoon at RailsConf.</p>
<ul>
<li><p>Exceptions (behavior between ruby and java)</p>
<ul>
<li>Embedding: JSR-223 preferred, BSF fallback</li>
</ul></li>
<li><p>Java integration, mocking, proxying, extension</p></li>
<li><p>Multiple VM support</p>
<ul>
<li>multiple JRuby instances can be run in the same VM</li>
<li>JavaSand (google it) -- Ola’s port of _why’s (freaky freaky)
sandbox</li>
</ul></li>
<li><p>Startup time performance gain recently</p>
<ul>
<li>-Xbootclasspath: VM does not verify classes in the “boot” classpath</li>
<li>-Xverify:none is not recommended because of runtime-generated code</li>
<li>Nailgun to keep VM running and “send commands” to it</li>
</ul></li>
<li><p>Compiling Ruby code to JVM bytecode</p>
<ul>
<li>Keep # of class files low</li>
<li>Walk AST and dump out high-level, abstracted operations
(local variable access, dynamic invocation) and low-level bytecode
is built for each of those</li>
<li>4096 -- maximum # of methods to be compiled</li>
<li>Compiled methods are shared between runtimes</li>
<li>Future:</li>
<li>raise/eliminate overhead of compiled methods</li>
<li>share AST, reduce memory load</li>
</ul></li>
<li><p>Community tasks/actions</p>
<ul>
<li>Projects needing help (e.g., ActiveHibernate)</li>
<li>Adoption, acceptance, blogging</li>
<li>Documentation (http://wiki.jruby.org/ and others), screencasts</li>
<li>Who’s using it?</li>
</ul></li>
<li><p>Sun’s commitment</p>
<ul>
<li>Ruby vs. Groovy vs. Python vs. Scala vs. other langs</li>
<li>Rails vs. Grails vs. Lift vs. JSF vs. Struts 2 vs. ???</li>
<li>all of the above</li>
<li>improve the JVM’s support for all dynamic languages</li>
<li>JRuby is a full open source project, not owned or controlled by Sun,
with history that extends years before main devs hired by Sun</li>
</ul></li>
<li><p>Ruby programming language, JRuby is an implementation</p>
<ul>
<li>community evangelism of Ruby the language vs. implementations</li>
<li>despite MVM, FFI and emerging areas that are not standard yet</li>
</ul></li>
<li><p>How do you pitch JRuby/Rails in a legacy environment?</p>
<ul>
<li>Consider demonstrating running application without discussing
technology specifics</li>
<li>IBM and JDK 1.5 issues have been reported</li>
<li>Free support as long as these issues are new and help improve
JRuby and the community!</li>
</ul></li>
<li><p>Testing</p>
<ul>
<li>JRuby enables more agile testing</li>
<li>Without production risks</li>
<li>Ceremony vs. Essence discussion</li>
</ul></li>
<li><p>Terracotta/DSO</p>
<ul>
<li><a href="http://jonasboner.com/2007/02/05/clustering-jruby-with-open-terracotta/" title="Jonas Bonér » Blog Archive » Clustering JRuby with Open Terracotta">Jonas Boner blogged about it over a year ago</a> </li>
</ul></li>
<li><p>Windows/Mongrel/ImageMagick issues</p>
<ul>
<li><a href="http://blog.nicksieger.com/articles/2008/03/27/imagevoodoo-0-1-released" title="ImageVoodoo 0.1 Released">ImageVoodoo</a> is an imaging library using Java2D, comes with Java</li>
<li>MiniMagick also reportedly works</li>
</ul></li>
<li><p>Rails benchmarks</p>
<ul>
<li>Micro-benchmarks are problematic and usually don’t lead to
measurable application speedups</li>
<li>Community needs a real-world, full application</li>
<li>Antonio Cangiano working on new application-level benchmarks?</li>
<li>“Richards” -- Smalltalk-originated application benchmark</li>
</ul></li>
<li><p>JSR-292 (“invokedynamic”)</p>
<ul>
<li>Actually extension of “invokeinterface” bytecode</li>
<li>Call site structure/method handles</li>
<li>Expose the dynamic nature of the JVM
(get the Java-specific stuff out of the way)</li>
<li>Language-specific calling semantics, method invocation</li>
<li>“Punching a hole” through the JVM</li>
<li>Comments on <a href="http://blogs.sun.com/jrose/entry/dynamic_invocation_in_the_vm" title="dynamic invocation in the VM : John Rose @ Sun">JSR-292 Early Draft Review</a> currently ongoing</li>
</ul></li>
</ul>Nick Siegerurn:uuid:032b3183-e579-4896-a439-2f62ee8279e62006-06-23T20:40:00+00:002010-11-22T18:15:29+00:00RailsConf: Stefan Kaes - Rails Performance<p>Stefan starts by citing a factor of 4-5 improvement in performance in
Rails over the last year.</p>
<h2>Performance, broken down</h2>
<ul>
<li>Latency -- how fast</li>
<li>Throughput -- how many</li>
<li>Utilization -- how idle is the cpu</li>
<li>Cost efficiency -- performance per unit cost</li>
</ul>
<p>For completeness calculate the min, max, mean and standard deviation
of these metrics and use the deviation as your guide for how reliable
the data is.</p>
<h2>Tools</h2>
<ul>
<li>Log files (level > <code>Logger::DEBUG</code>)</li>
<li><a href="http://rails-analyzer.rubyforge.org/">Rails Analyzer Tools</a> (Eric Hodel)</li>
<li>Benchmarker (<code>script/benchmarker</code>)</li>
<li>DB vendor tools</li>
<li>Apache bench (<code>ab</code> or <code>ab2</code>)</li>
<li>httperf</li>
<li><a href="http://rubyforge.org/projects/railsbench">railsbench</a> (Stefan Kaes)</li>
</ul>
<h2>Railsbench</h2>
<p>Railsbench measuress raw performance of rails request processing.
It’s configured using <code>config/benchmarks.yml</code> and
<code>config/benchmarks.rb</code>. These files let you control which requests
get benchmarked, whether to create a new session when benchmarking
them, etc.</p>
<h2>Profiling Tools</h2>
<ul>
<li>Ruby Profiler</li>
<li>Zen Profiler</li>
<li>rubyprof</li>
<li>Rails profiler script</li>
<li><a href="http://www.softwareverify.com/rubyPerformanceValidator/index.html">Ruby Performance Validator</a></li>
</ul>
<p>At this point Stefan gave an overview of RPV, which appears to be a
nifty tool that lets you get typical hotspot tree views of where time
is spent in code. It currently only runs on Windows.</p>
<h2>Top Rails Performance Problems</h2>
<ul>
<li>slow helper methods</li>
<li>complicated routes</li>
<li>associations -- navigating and eager loading vs. proxy loading</li>
<li>retrieving too much data from the DB</li>
<li>slow session storage (e.g., ActiveRecord store)</li>
</ul>
<p>Stefan says that in his experience, DB performance is generally not a
big factor or bottleneck. Instantiating ActiveRecord objects is
expensive, though.</p>
<h2>Session containers</h2>
<ul>
<li>In memory -- if you server crashes...oops. Also doesn’t scale.</li>
<li>File system -- easy to set up, scales with NFS, but slower than...</li>
<li>ActiveRecordStore -- easy to set up since it comes with Rails, but
much slower than...</li>
<li>SQLSessionStore -- which uses the same table structure as
ActiveRecordStore, but was written by Stefan to overcome performance
issues with ActiveRecordStore. Setup is more involved.</li>
<li>memcached -- slightly faster than SQLSessionStore, scales best, but
setup is also more involved.</li>
<li>DrbStore -- distributed ruby store</li>
</ul>
<h2>Caching</h2>
<ul>
<li>Full pages -- fastest, complete pages are served on the
filesystem. Web server bypasses appserver for rendering. If you
have private pages, you can’t use it.</li>
<li>Actions -- pages are cached after an action is rendered. The
user ID can be used as part of the storage key.</li>
<li>Fragments -- fragments can be cached in memory, on the file system,
in a DrbStore, or in memcached. Memcached scales the best but
doesn’t support expiring fragments by regular expression.</li>
</ul>
<h2>ActionController</h2>
<ul>
<li>Stefan recommends avoiding components, and replacing them with
helpers or partials. He has not found a use for them.</li>
</ul>
<h2>ActionView</h2>
<ul>
<li>Don’t create unnecessary instance variables in the controller;
creating them in the view with <code>instance_variable_set</code> and accessing
with <code>instance_variable_get</code> is slow.</li>
</ul>
<h2>Helpers</h2>
<ul>
<li>pluralize -- don’t use the inflector if you don’t need to, it’s expensive.</li>
<li>link<em>to and url</em>for are among the slowest helpers, since they need
to use routes. Instead, if you have page with lots of links, you
might consider hard-coding the links. This reduces the amount of GC
by up to 50% and the GC time down by a few percentage points (11.3%
to 8.7% of total processing time).</li>
</ul>
<h2>ActiveRecord</h2>
<ul>
<li>use the <code>:include</code> option to prefetch associations, it avoids extra
onesy-twosy SQL statements.</li>
<li>use piggy-backing plugin for <code>has_one</code> or <code>belongs_to</code> relationships
-- allows you to retrieve extra attributes from additional tables in
the same fetch query.</li>
<li>Field values are retrieved from the DB mostly as strings, so type
conversion happens on each access, which can be slow.</li>
</ul>
<h2>Language-level and miscellaneous issues</h2>
<ul>
<li>Method calls are the slowest -- don’t needlessly create method
abstractions</li>
<li>Short-circuit intermediate results to improve performance</li>
<li>Cache results in instance variables or class variables</li>
<li>Don’t call <code>ObjectSpace.each_object</code> on each request</li>
</ul>
<h2>Ruby Memory Management</h2>
<ul>
<li>designed for batch scripts, not long-running servers.</li>
<li>no generational garbage collection.</li>
<li>this is suboptimal for Rails because ASTs are stored on the heap
(biggest portion of non-garbage for Rails apps), and get
processed/traversed more often than they need to be</li>
<li><a href="http://rubyforge.org/projects/railsbench">Railsbench</a> includes a patch to allow one to recompile Ruby
and tweak the garbage collector.</li>
</ul>
<h2>Rails Template Optimizer</h2>
<ul>
<li>Stefan has started a project to “compile” templates.</li>
<li>The idea is to cache results of some ERb scriptlets and essentially
“compile” or replace the template with one that has more expressions
expanded or inlined.</li>
<li>Code forthcoming; I assume you can stay tuned to <a href="http://railsexpress.de/blog/">Rails
Express</a> for news.</li>
</ul>
<h2>Questions</h2>
<ul>
<li>There was a question on JRuby -- Stefan replied that it would
certainly solve GC issues, but he doesn’t know if it’s in a state to
be able to benchmark Rails requests.</li>
<li>What are your recommendations for a web server. <em>I don’t have
any.</em></li>
<li>Is horizontal or vertical scaling better? <em>I don’t know, I’ve
been focused on making single requests go fast, so I don’t have
enough experience.</em></li>
</ul>Nick Siegerurn:uuid:13f5e270-43ae-4f56-b7c4-27fb1c6884192008-04-18T17:25:16+00:002010-11-22T18:16:48+00:00Spring and Summer Gigs<p>Just a quick note on some upcoming gigs. I’ll be speaking next month at both <a href="https://www28.cplan.com/cc191/session_details.jsp?isid=296490&ilocation_id=191-1&ilanguage=english">JavaOne</a> and <a href="http://en.oreilly.com/rails2008/" title="RailsConf 2008 - O'Reilly Conferences, May 29 - June 01, 2008,Portland, Oregon">RailsConf</a>, giving an update on the JRuby deployment situation, which by the way is rapidly improving! Despite my proposal for a hands-on tutorial on JRuby deployment not getting accepted for RailsConf, I’ve been asked to fill one of the Sun-sponsored talk slots again. So, much like <a href="/articles/2007/10/06/railsconf-europe-hydra">RailsConf EU last fall</a>, if you come listen I promise you will not get a heavy sales pitch from me! Do stop by, I may even have a couple goodies in store for you.</p>
<p>I also feel privileged to be speaking at <a href="http://rubyfringe.com/speakers#nick_sieger">RubyFringe</a> this summer, where I haven’t yet determined exactly what I’ll be talking about (although it will probably have some connection to JRuby).</p>
<p>Hope to see you at one of these upcoming events!</p>
<p><em>Update:</em> We just re-jiggered the schedule of 3 JRuby-related talks at JavaOne, including mine, so that they flow better from beginning to end of the week. My talk is now on Thursday morning instead of Wednesday morning. In addition, <a href="https://www28.cplan.com/cc191/session_details.jsp?isid=295416&ilocation_id=191-1&ilanguage=english">Charlie and Tom’s</a> is on Tuesday, and <a href="https://www28.cplan.com/cc191/session_details.jsp?isid=294806&ilocation_id=191-1&ilanguage=english">Ola’s</a> is on Wednesday. If you’re attending JavaOne and are interested in JRuby-related talks, please make sure you log into Schedule Builder and re-check your schedule.</p>Nick Siegerurn:uuid:35f07fbf-9a1b-4848-9e0a-848ba70296972007-05-18T17:10:39+00:002010-11-22T18:17:31+00:00RailsConf 2007 Opening Keynote: David Heinemeier Hansson<h1>Rails 2.0</h1>
<h2>Where we’ve been</h2>
<p>David is surprised and proud of the community that we already have, and wants us to be comfortable with where we are, and not always looking toward the future. We have:</p>
<ul>
<li>Million gem downloads</li>
<li>Hundreds of plugins</li>
<li>10k users on the rubyonrails-talk mailing list</li>
<li>Ruby job descriptions (asking for 3 years RoR experience, longer than David)</li>
<li><a href="http://www.amazon.com/s/002-0555878-2213644?ie=UTF8&tag=mozilla-20&index=blended&link%5Fcode=qs&field-keywords=ruby%20on%20rails&sourceid=Mozilla-search">Books, books, books</a> (and not just English books, but non-English titles as well), surpassing VBA, Perl, and Python in book sales</li>
<li>IDEs from NetBeans, Borland, Aptana, etc.</li>
</ul>
<p>Rails 2.0 is not going to be the “Unicorn”. It’s not going to be a total rewrite, it actually has a release schedule, it will not break backwards-compatibility. Instead, it will build upon what we already have, and continue the philosophy of building on what is useful and needed. In fact, 95% of what’s in 2.0 already works today, in the edge. Example, a simple controller that handles three formats of input/output, with a person resource for accessing the data from a remote server.</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="keyword">class </span><span class="class">PeopleController</span> <span class="punct"><</span> <span class="constant">ApplicationController</span>
<span class="punct">...</span>
<span class="keyword">def </span><span class="method">create</span>
<span class="attribute">@person</span> <span class="punct">=</span> <span class="constant">Person</span><span class="punct">.</span><span class="ident">create</span><span class="punct">(...)</span>
<span class="ident">respond_to</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">format</span><span class="punct">|</span>
<span class="ident">format</span><span class="punct">.</span><span class="ident">html</span> <span class="punct">{</span> <span class="ident">redirect_to</span> <span class="ident">person_url</span><span class="punct">(</span><span class="attribute">@person</span><span class="punct">)</span> <span class="punct">}</span>
<span class="ident">format</span><span class="punct">.</span><span class="ident">xml</span> <span class="punct">{</span> <span class="ident">render</span> <span class="symbol">:status</span> <span class="punct">=></span> <span class="symbol">:created</span><span class="punct">,</span> <span class="symbol">:location</span> <span class="punct">=></span> <span class="ident">person_url</span><span class="punct">(</span><span class="attribute">@person</span><span class="punct">),</span> <span class="punct">...</span> <span class="punct">}</span>
<span class="ident">format</span><span class="punct">.</span><span class="ident">js</span> <span class="punct">{</span>
<span class="ident">render</span> <span class="symbol">:update</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">js</span><span class="punct">|</span>
<span class="punct">...</span>
<span class="keyword">end</span>
<span class="punct">}</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">class </span><span class="class">Person</span> <span class="punct"><</span> <span class="constant">ActiveResource</span><span class="punct">::</span><span class="constant">Base</span>
<span class="constant">self</span><span class="punct">.</span><span class="ident">site</span> <span class="punct">=</span> <span class="punct">"</span><span class="string">http://example.com/</span><span class="punct">"</span>
<span class="keyword">end</span></code></pre></div>
<p>David then goes into a live demo of the new scaffold resource, which by appearance is identical to the old scaffolding, except it comes pre-baked with a REST-ful XML interface. He then adds support for a text format with a couple of lines of code, jumps into IRB, defines an active resource, and proceeds to change the data remotely.</p>
<p>If you want to add search to your controller, you can do it in a DRY way, and all the format/view work you’ve done will benefit:</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="keyword">class </span><span class="class">PeopleController</span> <span class="punct"><</span> <span class="constant">ApplicationController</span>
<span class="keyword">def </span><span class="method">index</span>
<span class="keyword">if</span> <span class="ident">params</span><span class="punct">[</span><span class="symbol">:name</span><span class="punct">]</span>
<span class="attribute">@people</span> <span class="punct">=</span> <span class="constant">Person</span><span class="punct">.</span><span class="ident">find</span> <span class="symbol">:all</span><span class="punct">,</span> <span class="symbol">:conditions</span> <span class="punct">=></span> <span class="punct">["</span><span class="string">name like ?</span><span class="punct">",</span> <span class="punct">"</span><span class="string"><span class="expr">#{params[:name]}</span>%</span><span class="punct">"]</span>
<span class="keyword">else</span>
<span class="attribute">@people</span> <span class="punct">=</span> <span class="constant">Person</span><span class="punct">.</span><span class="ident">find</span> <span class="symbol">:all</span>
<span class="keyword">end</span>
<span class="punct">...</span>
<span class="keyword">end</span>
<span class="keyword">end</span></code></pre></div>
<p>David points out that 37signals, Shopify, Fluxiom, et. al. are real sites, with non-trivial domains that are still well executed in Rails, so it’s not just about simple scaffolding demos.</p>
<p>In Rails 2.0, ActiveResource will be bundled with Rails, and ActionWebService will not.</p>
<h2>Friends of Rails</h2>
<ul>
<li>AJAX!</li>
<li>REST!</li>
<li>Atom? -- Atom should be more native to Rails</li>
<li>Openid? -- Openid is not necessarily something that needs to be used by all, but still a strong ally.</li>
</ul>
<h2>9 other things I like about Rails 2</h2>
<ul>
<li>Breakpoints are back -- no longer depends on <code>Binding.of_caller</code>; instead Rails depends and builds upon <a href="http://rubyforge.org/projects/ruby-debug/"><code>ruby-debug</code></a> by Kent Sibilev.</li>
<li>HTTP Performance -- streamlining .js and .css, even though it feels better to break up Javascript and CSS into many little pieces, and gzip them</li>
</ul>
<div class="typocode"><pre><code class="typocode_ruby "><span class="punct"><%=</span><span class="string"> javascript_include_tag :all, :cache </span><span class="punct">=></span> <span class="constant">true</span> <span class="punct">%></span><span class="string">
<%= stylesheet_link_tag :all, :cache =</span><span class="punct">></span> <span class="constant">true</span> <span class="punct">%></span><span class="string"></span></code></pre></div>
<p>We can also fake out the browser and configure multiple asset hosts (4) you can maximize browser connections</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="ident">config</span><span class="punct">.</span><span class="ident">action_controller</span><span class="punct">.</span><span class="ident">asset_host</span> <span class="punct">=</span> <span class="punct">'</span><span class="string">assets%d.highrisehq.com</span><span class="punct">'</span></code></pre></div>
<ul>
<li>Query cache</li>
</ul>
<div class="typocode"><pre><code class="typocode_ruby "><span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span><span class="punct">.</span><span class="ident">cache</span> <span class="keyword">do</span>
<span class="comment"># actions here are cached</span>
<span class="keyword">end</span></code></pre></div>
<ul>
<li>Rendering and MIME types -- bake the MIME convention into the template, and separate from the rendering mechanism
people/index.html.erb
people/index.xml.builder
people/index.rss.erb
people/index.atom.builder</li>
<li>config/initializers replacing config/environment. Initializers are .rb files in the config/initializers directory of your app that are automatically loaded during initialization time.</li>
<li>Sexy migrations</li>
</ul>
<div class="typocode"><pre><code class="typocode_ruby "><span class="ident">create_table</span> <span class="symbol">:people</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">t</span><span class="punct">|</span>
<span class="ident">t</span><span class="punct">.</span><span class="ident">integer</span> <span class="symbol">:account_id</span>
<span class="ident">t</span><span class="punct">.</span><span class="ident">string</span> <span class="symbol">:first_name</span><span class="punct">,</span> <span class="symbol">:last_name</span><span class="punct">,</span> <span class="symbol">:null</span> <span class="punct">=></span> <span class="constant">false</span>
<span class="ident">t</span><span class="punct">.</span><span class="ident">text</span> <span class="symbol">:description</span>
<span class="ident">t</span><span class="punct">.</span><span class="ident">timestamps</span>
<span class="keyword">end</span></code></pre></div>
<ul>
<li>HTTP authentication (<code>authenticate_or_request_with_http_basic</code>, <code>authenticate_with_http_basic</code>)</li>
<li>The MIT assumption -- the licensing question -- make it easier to understand</li>
<li>Spring cleaning -- getting rid of the cruft -- stay tuned!</li>
</ul>Nick Siegerurn:uuid:d9edbea6-8e0e-43b6-af40-7d8bb3d69f522007-10-06T12:04:00+00:002010-11-22T18:19:05+00:00RailsConf Europe: Hydra<p><img src="/files/hydra.png" alt="Hydra" title="Hydra"/></p>
<p>On September 19, Craig and I presented our <a href="http://blog.nicksieger.com/articles/2007/09/14/gig-speaking-at-railsconf-europe-2007">talk at RailsConf</a>, which appears to have been <a href="http://loudthinking.com/posts/11-sun-surprises-at-railsconf-europe-2007">well received</a>. It went off mostly without a hitch, if it wasn’t for a couple of hiccups in the demos. I apparently didn’t practice them enough, because a couple of critical steps were either missed or I did them out of order and confused myself. But that’s ok, because I’m releasing the demo steps, source and slides here so you can try them out for yourself.</p>
<p>So, <a href="http://blog.nicksieger.com/files/RailsConfEurope-Hydra.zip">download the zip</a> and follow along. The contents look like this:</p>
<pre><code>1-active-resource-basics.txt
2-make-resourceful.txt
3-atom-roller.txt
4-service-chatter.txt
RailsConfEurope-Hydra.pdf
demo/
demo-baked/
</code></pre>
<p>The demo steps are in the text files; I’d recommend going in the order specified. It turns out the third isn’t really a demo but more of a code review, because it also requires you to have Roller set up and I’m not going into those details for now. If you want to just run the demos, skip to <code>demo-baked</code>, the finished product.</p>
<p>For those of you who didn’t see the talk, here’s the basic message.</p>
<p>Look at your basic MVC Rails app.</p>
<p><img src="/files/single.png" alt="Single app" title="Single app"/></p>
<p>Why not consider spliting it into two? ActiveResource allows you to access a RESTful resource in your Rails application like it was just another model.</p>
<p><img src="/files/double.png" alt="Double app" title="Double app"/></p>
<p>This might seem like overkill for a simple application, but what if you had an e-commerce application domain like this?</p>
<p><img src="/files/ecomm.png" alt="E-Commerce app" title="E-Commerce app"/></p>
<p>Splitting up your code into separate Rails applications encourages encapsulation, reduces potential coupling, and gives you more flexible deployment options. Basing interactions upon REST and HTTP means that you can more easily mash up data or create caching strategies, given proper usage of ETags/Last-Modified and/or cache-control headers. The great thing is that existing HTTP reverse proxies can be used without having to mix the caching code in with your application code.</p>
<p>In the application we’re building, we have a number components that are not Rails-based. To expose them to our environment, we’ve taken the strategy of exposing a simple REST web service for the component, and then it can be consumed by the other applications using ActiveResource. The REST web service can either be implemented in the component’s native language/technology, or in some cases we’ve written a wrapper service in Rails since Rails makes it so easy to build REST interfaces. In that case, Rails is pure integration -- RESTful glue.</p>
<p>The idiom that makes this all possible is the uniform interface. In HTTP, this means addressability (each resource gets a unique URI) coupled with the HTTP method verbs HEAD, GET, POST, PUT, and DELETE. Inside your Rails applications, it’s the ActiveRecord interface. If you <a href="http://www.therailsway.com/2007/6/1/railsconf-recap-skinny-controllers">keep your controllers skinny</a>, you can boil the interface down to the following set of methods (in this case, for the prototypical blog post model):</p>
<pre><code>Post.new/Post.create
Post.find
@post.save
@post.update_attributes
@post.errors
@post.destroy
</code></pre>
<p>And in fact, this is precisely what ActiveResource provides, and it’s enabled by <a href="http://en.wikipedia.org/wiki/Duck_typing">duck-typing</a>. Walking through the demos illustrates this pretty well, as you’ll basically swap ActiveRecord for ActiveResource with no noticeable difference, all the way down to validation errors in the scaffolded forms (which I was unable to demo in the talk due to the hiccups).</p>
<p>We’ve found that when you’re making RESTful web services, the controllers largely become boilerplate because of the uniform interface. <a href="http://svn.hamptoncatlin.com/make_resourceful/trunk/"><code>make_resourceful</code></a> has been a boon in that regard, as the demos also show. There are several plugins that help you DRY up your controllers (other approaches include <a href="http://plugins.ardes.com/doc/resources_controller/"><code>resources_controller</code></a>), so you have some choices there.</p>
<p>We mentioned some drawbacks in our experience with ActiveResource, which have largely been addressed for the upcoming Rails 2.0 release.</p>
<p>Finally, we noted that deployment could be a pain with so many Rails applications to keep running. To that end, we are leveraging JRuby and Glassfish to make this a non-issue, as we simply WAR up our Rails applications with <a href="http://blog.nicksieger.com/articles/2007/09/04/warbler-a-little-birdie-to-introduce-your-rails-app-to-java">warbler</a> and let Glassfish take care of the rest. Performance is still an open question, but we plan to roll up our sleeves and make sure this combination really hums.</p>
<p>Enjoy the demos! Feel free to drop me an email if you have any questions or troubles with them.</p>Nick Siegerurn:uuid:40171862-80d2-460f-9ad6-ead9fe29fd912007-05-19T20:34:00+00:002010-11-22T18:23:55+00:00RailsConf 2007: Chris Wanstrath: Kickin' Ass with Cache-fu<p>Chris is here to talk about games, since he used to work for Gamespot. He coded PHP, which is like training wheels without the bike. He had to sit in a glass cube and help keep the site running during E3 last year. There were 100 gajillion teenage boys during their lunch break hitting refresh, and it all blew up. Couldn’t even gzip the responses, because the servers heated up to much. They served 50M pages in a day, without downtime. They did it with Memcache.</p>
<p>Memcache is a distributed hash -- multiple daemons running on different servers. Developed by Livejournal for their infrastructure, you just put up the servers, and they just work.</p>
<p>Should you use Memcache? No. <a href="http://c2.com/xp/YouArentGonnaNeedIt.html">YAGNI</a>, UYRDNI (unless you really do need it).</p>
<h2>Rails and Memcache</h2>
<p>Fragments, Actions, Sessions, Objects, cache it all. You can use:</p>
<ul>
<li><code>memcache-client</code> (by Robot-coop guys/Eric Hodel). Marshal.unload is 40 times faster than Object.new/loading from the database.</li>
<li>CachedModel -- integration with ActiveRecord</li>
<li>Fragment Cache Store</li>
<li>Memcache session store</li>
</ul>
<p>...or...</p>
<h2><code>cache_fu</code></h2>
<p>Or, <code>acts_as_cached</code>. It knows about all the aforementioned objects, with a single YAML config file (<code>config/memcached.yml</code>). Word to the wise: don’t use names in your server config file. Use IPs, avoid BIND and connections to the servers with every connection. Don’t let DNS outages bring down your servers.</p>
<ul>
<li><code>get_cache</code></li>
<li><code>expire_cache</code></li>
</ul>
<p>This is all you need -- if you’re using <code>set_cache</code>, you probably don’t understand how the plugin works. Expire cache on the “after save” hook, which allows you to cache ID misses as well.</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="keyword">class </span><span class="class">Presentation</span> <span class="punct"><</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
<span class="ident">acts_as_cached</span>
<span class="ident">after_save</span> <span class="symbol">:expire_cache</span>
<span class="keyword">end</span></code></pre></div>
<p>Example: only cache published items</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="keyword">class </span><span class="class">Presentation</span> <span class="punct"><</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
<span class="ident">acts_as_cached</span> <span class="symbol">:conditions</span> <span class="punct">=></span> <span class="punct">'</span><span class="string">published = 1</span><span class="punct">'</span>
<span class="keyword">end</span></code></pre></div>
<p>Cached-scoped-finders (if somebody thinks of a good name, let Chris know). The idea is to move custom finder logic to a method on your model, and then wrap a cache-scoping thingy around it. <code>cache_fu</code> ties this up nicely by giving you a <code>cached</code> method on AR::Base.</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="keyword">class </span><span class="class">Topic</span> <span class="punct"><</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
<span class="keyword">def </span><span class="method">self.weekly_popular</span>
<span class="constant">Topic</span><span class="punct">.</span><span class="ident">find</span> <span class="symbol">:all</span><span class="punct">,</span> <span class="punct">...</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="constant">Topic</span><span class="punct">.</span><span class="ident">cached</span><span class="punct">(</span><span class="symbol">:weekly_popular</span><span class="punct">)</span></code></pre></div>
<p>Adding date to cache key with <code>alias_method_chain</code>:</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="keyword">def </span><span class="method">self.cache_key_with_date</span><span class="punct">(</span><span class="ident">id</span><span class="punct">)</span>
<span class="punct">...</span>
<span class="keyword">end</span>
<span class="keyword">class </span><span class="punct"><<</span> <span class="constant">self</span>
<span class="ident">alias_method_chain</span> <span class="symbol">:cache_key</span><span class="punct">,</span> <span class="symbol">:date</span>
<span class="keyword">end</span></code></pre></div>
<p>Cached loads by ID: <code>Topic.find(1, 2, 3)</code> moves to <code>Topic.get_cache(1, 2, 3)</code>, which can parallelize calls to memcached and bring them back as they’re ready.</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="ident">user_ids</span> <span class="punct">=</span> <span class="attribute">@topic</span><span class="punct">.</span><span class="ident">posts</span><span class="punct">.</span><span class="ident">map</span><span class="punct">(&</span><span class="symbol">:user_id</span><span class="punct">).</span><span class="ident">uniq</span>
<span class="attribute">@users</span> <span class="punct">=</span> <span class="constant">User</span><span class="punct">.</span><span class="ident">get_cache</span><span class="punct">(</span><span class="ident">user_ids</span><span class="punct">)</span></code></pre></div>
<p>You can also cache associations, so that you’re navigating associations via Memcache.</p>
<p>Cache overrides</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="keyword">class </span><span class="class">ApplicationController</span> <span class="punct"><</span> <span class="constant">ActionController</span><span class="punct">::</span><span class="constant">Base</span>
<span class="ident">before_filter</span> <span class="symbol">:set_cache_override</span>
<span class="keyword">def </span><span class="method">set_cache_override</span>
<span class="constant">ActsAsCached</span><span class="punct">.</span><span class="ident">skip_cache_gets</span> <span class="punct">=</span> <span class="punct">!!</span><span class="ident">params</span><span class="punct">[</span><span class="symbol">:skip_cache</span><span class="punct">]</span>
<span class="keyword">end</span>
<span class="keyword">end</span></code></pre></div>
<p><code>reset_cache</code>: Slow, uncached operations can sometimes queue up and wedge a site. Instead, issue cache resets on completion of a request, rather than expiring beforehand. That way, requests that continue to pile up will still use the cached copy until the rebuild is complete.</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="keyword">class </span><span class="class">Presentation</span> <span class="punct"><</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
<span class="ident">after_save</span> <span class="symbol">:reset_cache</span>
<span class="keyword">end</span></code></pre></div>
<p>Versioning: a way to expire cache on new code releases</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="keyword">class </span><span class="class">Presentation</span> <span class="punct"><</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span>
<span class="ident">acts_as_cached</span> <span class="symbol">:version</span> <span class="punct">=></span> <span class="number">1</span>
<span class="keyword">end</span></code></pre></div>
<p>Deployment: Chris recommends using Monit to ensure your Memcache servers are up.</p>
<p><code>libketama</code>: consistent hashing that gives you the ability to redeploy Memcache servers without invalidating all the keys.</p>
<p>Q: Page caching? A: Nginx with native Memcache page caching, but outside of Rails domains.</p>
<p>Lots of other questions, but dude, Chris talks too fast!</p>Nick Siegerurn:uuid:f0f0e50c-df6a-47dc-81fe-0845c594512c2007-05-19T19:30:06+00:002010-11-22T18:23:55+00:00RailsConf 2007: Bradley Taylor: Virtual Clusters<p>How does Rails figure into virtualization? Bradley will cover this topic with examples and case studies. Along the way, hardware items may be mentioned, but are not critical. Really, it’s about the design of the clusters, not the bits of plumbing you use to connect them up.</p>
<p>Virtualization is partitioning of physical servers that allow you to run multiple servers on it. Xen, Virtuozzo, VMWare, Solaris containers, KVM, etc. Bradley uses Xen. The virtual servers share the same processor (hopefully multi-core), memory, storage, network cards (but with indepenent IP addresses), etc., but run independently of each other. VPS, slice, container, accelerator, VM, it’s all the same. Memory, storage, and CPU can be guaranteed with the virtualization layer.</p>
<p>Why would you do this? <em>Consolidate</em> servers for less hardware and cost; <em>Isolate</em> applications -- bad apps don’t drag the server down, contain intrusions, use different software stacks; <em>Replicate</em> -- easily create new servers and deploy in a standardized and automated way; <em>Utilize</em> -- take advantage of all CPU, memory, storage, resources; <em>Allocate</em> resources, give a server exactly what it requires, grow/shrink up and down, and balance them. Bradley says, “Once you go to virtualization you won’t want to go back. Do the simplest thing that could possibly work.”</p>
<p>Virtual clusters, then, are a bunch of servers cooperating toward a common goal -- if you have many versions or copies of one thing. More than one customer, more than one version of software, etc.</p>
<p>For Rails, this means a lot of things: you can have many development environments and stages, take advantage of memory isolation, protect against PHP/Java, and make multiple-server scaling accessible.</p>
<h2>Examples</h2>
<ul>
<li>Two servers for production and staging</li>
<li>Three for web/db/staging</li>
<li>Mixed languages -- instead of 1x1GB server use 3x300MB servers</li>
<li>High availability applications with fewer servers</li>
<li>Multiple applications -- one server per application</li>
<li>Standardized roles/appliances -- mail, ftp, dns, web, db</li>
</ul>
<h2><a href="http://www.eastmedia.com/">EastMedia</a></h2>
<ul>
<li>They can incubate customers in separate images</li>
<li>Dev/staging/production servers</li>
<li>Shared SVN/trac</li>
<li>2 physical servers => 8 virtual servers</li>
</ul>
<h2>Boom Design</h2>
<ul>
<li>Again, multiple stages</li>
<li>Customer staging, with lower uptime requirements</li>
<li>Low-traffic apps on a single server, but everything else gets its own dedicated server</li>
<li>2GB memory spread across 9 virtual servers</li>
</ul>Nick Siegerurn:uuid:c67fa477-41f0-4798-9fa2-2c27ae65e5372007-05-19T17:22:42+00:002010-11-22T18:23:56+00:00RailsConf 2007: Saturday Morning Keynotes<p><strong>Cyndi Mitchell -- ThoughtWorks Studios</strong></p>
<p>Enterprise (the “e” word)</p>
<p>Before IT got involved, “enterprise” was a bold new venture. Toyota manufacturing, Skype disruption of telephony.</p>
<p>Enterprise in terms of IT has come to mean bloatware, incompetence, corruption, waste of time, no value.</p>
<p>So this is the battle: The enterprise (to boldly go where no man has gone before) we need to reclaim vs. the bloatware/competence/corruption/fear-based selling etc.</p>
<p>RubyWorks -- package stack with haproxy, mongrel, monit through an RPM repository</p>
<p>For JRuby support, call <a href="http://ola-bini.blogspot.com/">Ola</a>.</p>
<p><strong>Tim Bray -- Web Guy from Sun Microsystems</strong></p>
<p>Change the world that are better than just using a cool web framework: http://pragmaticstudio.com/donate/</p>
<p>Sun loves Ruby. Ruby <em>and</em> Rails, that is. The impact of the Ruby language is going to be at least as big as Rails is for web development.</p>
<p>Sun provided servers for Ruby 2.0 development, and can provide servers for your potentially cool, worthy, open source project, just drop Tim an email.</p>
<p>A few more obligatory plugs for NetBeans and Sun sponsoring the conference. “Pre-alpha,” he says. Hmm, I wonder what <a href="http://blogs.sun.com/tor/">Tor</a> would say about that!</p>
<p>JRuby: when would you use JRuby vs. Ruby? If you have no pain, keep using C Ruby. But if you have management concerns, deployment concerns, etc. then by all means do try it!</p>
<p>Obligatory handshake/sandal connection with ThoughtWorks and Cyndi -- running <a href="http://studios.thoughtworks.com/2007/5/7/mingle-to-run-on-jruby">Mingle</a> (and cruisecontrol.rb) with JRuby.</p>
<p>Sun: “Hi, the answer is Java, what was the question?” So why would Sun want to support Ruby? Well, you guys are programmers. Programmers who deliver quality software fast. And those programmers need computers, and OSes, and web servers, and support and services, etc. Plug, plug, plug.</p>
<p>How do you make money on free products? Sun has open-sourcing Java, Solaris, even Sparc. Joyent is open-sourcing their stuff. Where does the money come from? 1. Adoption 2. Deployment 3. Monetization at the point of value</p>
<p>What if we win? Are our problems over? No, we’ll have to deal with Java. And .NET. And PHP. <em>From the audience: And COBOL.</em> The Network Is The Computer. The Network Is Heterogeneous. <strong>Deal with it.</strong> So how do we interoperate?</p>
<ul>
<li>Just Run Java (and JRuby, of course!, and JavaScript, and PHP, etc.)</li>
<li>Use Atom/REST. Everything should have a publish button. <em>Don’t use WS-DeathStar or WCF or WSIT.</em></li>
</ul>
<p>Developer issues: Scaling, Static vs. Dynamic, Maintainability, Concurrency, Tooling, Integration, Time to Market. Which two of these matter the most?</p>
<p>Tim’s final assertion: Maintainability and Time to Market, and that’s why we’re all at RailsConf.</p>Nick Siegerurn:uuid:f408e374-3a8c-4436-b31f-cf1d3fe7e4be2007-05-18T19:33:31+00:002010-11-22T18:23:56+00:00RailsConf 2007: Evan Weaver: Going Off Grid<p>Evan is talking about leaving Rails as a full-stack framework and remixing bits and pieces for integration projects. He’s doing it in the context of a case study on Bio: a project at the University of Delaware working with DNA data in large SQL databases. Evan states that all of bioinformatics is an integration problem. (Me: That’s probably true of any research project where data is coming from multiple, varied sources. So where does Rails fit in this?)</p>
<p>So how do you cope with this? Use the Rails console as an admin interface, mapping AR onto the legacy schema.</p>
<p>Shadow (<code>gem install shadow</code>) is a REST-ful record server -- a small Mongrel handler that allows you to manipulate the database remotely. It uses dynamic ActiveRecord classes that are created and trashed for each request.</p>
<p>Parallelization -- uses the Sun 1 grid engine that distributes shell scripts across 128 nodes. Used for job and backend processing.</p>
<p>bioruby/bioperl/biopython -- bioinformatics libraries in other languages -- bioruby is not complete, but we still want to use Ruby, so he looked at ways of integrating Ruby with other languages. No RubyInline for Perl or Python, no up-to-date direct/C bindings. He ended up building a socket-level interface into python.</p>
<p>Admin tools to consider -- streamlined, active_scaffold, autoadmin, Django (<code>manage.py inspectdb; manage.py syncdb; manage.py runserver</code>). (Wow, come to RailsConf, get a Django demo. Unexpected surprise!)</p>
<p>Extending Rails -- <code>has_many_polymorphs</code> for easy creation directed graphs</p>
<p>Frustrating AR tidbits: <code>has_many_through</code> has a huge case statement, with sql strings everywhere, and tightly intertwined classes. Ugh.</p>
<p>Scaling big webapps: AR/SQL is not the way. Instead, go to a hyper-denormalized model, where the DB is just a big hash. This leads to things like berkeleydb, memcached, madeleine, etc. and MySQL just becomes a persistence store for memcache. One key is moving joins at write-time, so that reads don’t need to re-join associations. You’re essentially duplicating/caching the data out to each association, but this makes sharding/splitting of data easier. Example: Flickr user photos vs. photos placed in a group.</p>
<p>Evan doesn’t believe that SQL is a viable data store for webapps -- I think he means large-scale webapps. Not everyone who’s trying to build a web application will run into these kinds of issues, so your mileage may vary. Still, it’s refreshing to see more people rebel against the incumbent 30-year gorilla of SQL.</p>