Performance strategy for site that is mostly static - ruby-on-rails

I am taking over development on a rails 3.2 application and am looking for the best way to improve page loading time. The site itself is more of a large dynamic website than an actual web application (the site is http://korduroy.tv/, a surf lifestyle community site), and while there is a couple of small pieces that differ from user to user, most of the site is the same experience for everyone.
Page loading time is fairly slow, and from looking at the server logs, it seems to be because each page is loading so much dynamic content (for example, most pages are loading resources from 10+ models). While I hope to go through and refactor what I can, I am looking for some basic performance wins. Knowing that most of the site is the same for every user, is their a way to aggressively cache the content on the server or even serve static content that has been generated through some kind of background job?
My initial thought was to create a job that uses a static site generator, maybe something like Jekyl, and basically creates a static copy of the site, which could then be served on a cdn. My gut is telling me this is probably not the way to do it, plus there are some pages (such as the user profile page), that need to be served dynamically.
Any recommendations would be great. Disclaimer, I come from front end land and have very little knowledge of best practices when it comes to server side optimizations. Thanks!

From what you write, I believe your biggest gain will be in implementing a fragment cache using a memcache store. See http://guides.rubyonrails.org/caching_with_rails.html as the definitive guide on rails caching.
You might be able to get away with a page cache or action caches for some of the content that doesn't depend on the user (like the homepage), but unless you're serving up millions of requests a day, I'm not sure this is necessary.
I notice that while the javascript and css seems to be compiled according to the rails asset pipeline, the images are missing the sha1 hashes that allow aggressive browser caching of the resources (since you don't have to worry about the contents changing, as they get new hashes when you change the images). The key here is enabling the asset pipeline, making sure you compile your assets as part of deployment (rake assets:precompile) and using the image_tag and asset_path helpers (or image-url sass helper). Also make sure that nginx is responding with code 304 (not modified) to your browser when you're refreshing a page. This won't affect the load on the rails server (unless you have both nginx and rails running on the same server), but will reduce the average page load time.
You can look into more advanced techniques like caching your sql queries, or optimizing these, but this can lead to increased complexity making it harder to maintain your codebase. Try the view caching first, and see if that gets the load time to an acceptable level.

Related

Is the MathJax gem really useful?

I would like to integrate math equations in a Rails project. I see that there exist a well-maintained MathJax gem (https://rubygems.org/gems/mathjax-rails/versions/2.5.1). On the webpage of this gem, there is a section called "Why bother with another gem?", which argues mainly that MathJax is huge and makes it difficult to manage the project when it is entirely installed in a subdirectory of a rails project. However, on the MathJax webpage (http://docs.mathjax.org/en/latest/start.html) I see that MathJax is available through a CDN, so I guess there is no need for downloading its source into the Rails project (maybe the gem was made at a time when it was necessary to download MathJax?).
So my question is: is there an advantage that I am missing, of using the gem rather than defining my own few helpers to get MathJax from the CDN and configure it for my need?
Assuming all things work, I think the CDN is the best and simplest way. They give instructions, it's free, it should reduce the performance and deployment cost of the library on your app, and if anything doesn't work it'll be easier to get help since you haven't done anything framework-specific.
However, using a CDN adds a partial failure mode to your app: what happens when your app server returns your HTML, but the CDN is down or unreachable for the MathJax assets? Your users will see the TeX code instead of the rendered equations.
This is pretty unusual, but can happen. Sometimes the CDN is broken, other times the user's ISP screws up their DNS to the CDN but not to your app.
Whether this is a risk worth defending against depends on your app, your users, etc.
You can avoid it by hosting mathjax yourself (app server or CDN) but it'll be more work to set up, and if you're using a CDN at all you can still get these partial failures.
If you really want the equations to render every time your app serves a page take a look at the server side rendering options (nodejs) added to MathJax and KaTeX recently. I'm not aware of a gem bundling this up yet for rails but it'd be cool to have. There's a mathjax node server/service you could send requests to from rails (cache the requests), but that'll complicate deployment if you're used to having a single app. There's also someone calling KaTeX through execjs.

Does rails cache static pages and assets automatically?

I have been reading about caching and all the resources available out there, but I am just not sure if I need to use 3rd party add-ons like Memcachier in my app. Other than the front pages (Static Pages like Homepage, About, Contact Us, Terms, Privacy) all other pages require authentication and are all dynamically created. It's a small social networking app so the show page, index page, edit page are all dynamically created. The index action is constantly going to be updated.
I want to know if Rails will automatically cache my static pages and assets such as css, javascript, images? What kind of caching should I be using?
If what you call static page are HTML files located in your public folder, they are directly served by your web server (ex: Apache), and the request don't even go through Rails
If they are files located in your app/views controller, the request goes through Rails, and it could be a good idea to implement page or fragment caching. Know that you can cache just parts of the pages, this is called fragment caching, and it's useful for dynamic pages that have static parts.
Also, you can link a cache to a record, so first time the view related to this record is displayed, the cache is generated and used for the next requests. Then when you modify this record the cache is invalidated and the process start over.
You don't need cache for your assets, they are compiles and not interpreted by Rails anymore in your production environment.
There is so many things about caching, and you can do a lot of good to your application with it (or a lot of bad is used incorrectly) and I cannot cover it all, let me give you some pointers that will teach you a lot:
http://railscasts.com/episodes/387-cache-digests
http://railscasts.com/episodes/169-dynamic-page-caching
http://railscasts.com/episodes/93-action-caching
http://railscasts.com/episodes/90-fragment-caching
http://railscasts.com/episodes/89-page-caching

How do I deploy sproutcore using a CDN into an existing site?

I'm just learning about SproutCore now, seems great. But I can't find a good answer on deployment options.
I'm starting small. Just implementing a single page of a complex site with SproutCore. Right now, that page is dynamically generated and served from my django based server. I serve all of my static files (.js, .css, images, etc) off of a CDN.
The page represents one customer.
So, on that dynamic page, it knows:
What customer we should be looking at, the ID, name, etc.
Where my media should be loaded from (absolute HTTP path)
How do I get a SproutCore based app to deploy and run in an environment like this?
I imagine I can upload the built sproutcore app to my CDN. Then in my html page, somehow reference it. But how does that SproutCore app know what server to request backend data from (I'd rather not hard code it)? It can't be installed in the root of the CDN, so how does it know how to load things relative to itself? I could tell it an absolute URL to load from at run time. With some pain, I could even tell it an absolute URL to load from at build time.
No answers on this one, here's what I did...
Ended up moving to Ember.js (aka SproutCore 2). That follows a completely normal "add .js to a page and serve it normally" model and doesn't have any interesting deployment worries, so it's a no-brainer.

Rails how to edit and save files in browser?

I want to make a CMS where I can edit the view and css files online in my browser.
How can it be done? Does everything have to be in a database?
Generally Stack Overflow is not for research, it's for problem solving. That said…
No, your editable assets do not have to be in a database for this to work.
But you want them to be anyways; allowing write access to the files in your application isn't the best approach.
The rendering chain of Rails 3 allows you to sub in your own view parser and add a path to the built in view-finding that you can trick into loading from a database relatively easily.
Having your end users write in something like Liquid templates will save you a lot of work and allow this to happen with relative ease. They won't have access to unsafe Ruby methods, and you won't have to go through all the work of sandboxing them in Ruby.
CSS has fewer security implications, so you can fairly easily store raw CSS in the database and allow your users to edit it to their liking and then serve it up with a request to a stylesheets/:user_id/style.css request (with some heavy caching, like with Varnish, to save your application from being murdered).
Hopefully that'll get you started out in the right direction. If you decide to hook into the rendering stack in Rails I strongly suggest you pickup a copy of Crafting Rails Applications — one of the handful of example applications it walks you through does just that at a fairly granular level.

Hybrid Rails Caching Options, am I reinventing something?

Well, not really reinventing, however, we have a large content-based website which handles load (after we fixed the SQL pooling issue) to a certain point, then we just run out of steam. A lot of this is due to bad code we are trying to fix up, but a lot is just due to the level of requests etc.
We were considering page caching, because well, it's damn quick (yep... :D) but that doesn't work because we have certain fragments within the page which are specific to the logged in user. But, not all hope is lost...
I was wondering if it would be ideal to do the following:
Page level caching, with sweepers to clean out the pages when content is updated.
Replace the user-specific fragments with placeholders (and perhaps generic content like... 'View your Account, or Sign Up Here')
When the users page loads fire off an async request (AJAX, or, some would call it AJAH), which requests the 'dynamic' fragment, then place the content placeholders with this fragment..
The main issue I can see with this is that users with JS turned off wouldn't see the content, but I honestly don't think we would be too affected by this, and IMHO people who disable javascript, for the most part, are idiots (yes, I said it!).
I'd also be interested to know if I'm (no doubt) reinventing something, and if anyone can point me to a site which is already doing something like this it would be appreciated.
Thanks awesome SO community!
Ryan Bates covered this technique in Railscast 169: Dynamic Page Caching. It's worth taking a look at.
Have you thought about server-side fragment caching? I've used it extensively, and it couldn't be more awesome. You could simply cache the content 'fragments' and render normally whatever depends on the logged in user.
There are many good resources for fragment caching, I'd start at the documentation:
http://api.rubyonrails.org/classes/ActionController/Caching/Fragments.html
Also very good from the Scaling Rails series:
http://railslab.newrelic.com/2009/02/09/episode-7-fragment-caching
When serving static content or cached content starts to slow down serving the real working processes put a reverse proxy as frontend to your application. It will free processes to do real work and reduce slowdowns due to file system caches becoming inefficient. And it will help you to make "client side caching" shareable to multiple visitors. Have a look at the fantastic screen cast series about caching and scaling by NewRelic: http://railslab.newrelic.com/scaling-rails

Resources