Why is my sinatra website so slow? - performance

After asking this question, I started using Sinatra as a way to serve web pages.
This evening, a friend of mine and I started to test the speed of the server.
The file to log in looks like:
require 'rubygems'
require 'sinatra'
require 'haml'
enable :sessions #for cookies!
get '/' do
haml :index
end
And the index.haml looks like:
%title
First Page
%header
%h2 First Page
He's sitting on a recent laptop, as am I, with an Apple 802.11n router between the two of us. We're both running Windows 7. I've also tried these same files on a laptop running Ubuntu 9.10 x64 with Sinatra and all relevant files installed from apt-get.
Sinatra is taking 7 seconds to serve up a single page request, no matter the server OS, Windows or Linux. I see that here the author managed to get over 400 requests/second processed. What gives? (or should this be on SuperUser or the like?)

I'll set aside any opinions on when you should optimize your web application.
Set up different configurations in your Sinatra app for development and production because some of these suggestions, you won't always want to use. In fact, you should probably go ahead and setup and environment similar to how you would deploy in production. You would not deploy by simply running ruby app.rb. You'd want to put apache or nginx in front of your Mongrel. Mongrel will serve up your static files, but that's really only advisable for development mode. In deployment, a web server is going to do a lot better job for that. In short, your deployed environment will be faster than your standalone development environment.
At this point, I wouldn't worry about Mongrel vs. Thin. If Thin is twice as fast - it isn't - then your 7 seconds becomes 3.5. Will that be good enough?
Some things to try ...
I know I just told you to set up a deployment environment, but maybe it's not the server side. Have you tried running YSlow or PageSpeed on your pages? I/O is going to take up more of those 7 seconds (Disclaimer: I'm assuming that there's nothing wrong with your network set up) than the server. YSlow - Firebug actually - will tell you how long each part of your page takes to get to the browser.
One of the things that YSlow told me to do was to put a far forward Expires header on my static assets, which I knew but I was leaving optimization until the end. That's when I realized that there were at least 3 different places that I could specify that header. I'm convincing myself that doing it in nginx is the right place to put it.
If you're happy with those results, then you can look at the server. Off the top of my head, so not exhaustive
Turn on gzip responses.
Combine your stylesheets so there's only one per page request. There may be some Rack Middleware for this, if you don't do it manually.
Cache. I'm trying Rack::Cache.
Use sprites to decrease the number of image downloads you use.
Minify your Javascript. Again, maybe via Rack Middleware.
Rack Middleware is neat, but it uses CPU. So, manually minifying your Javascript adds a new step to your workflow, but on the server, it's faster than Middleware. It's a tradeoff.
Sorry if this was rambly.

I had this problem when running Sinatra with shotgun but not when running my app directly (i.e., ruby -rubygems app.rb). This is because shotgun forks and reloads the application for each request.
I found a thread in Sinatra's mailing list which discussed this issue and people there advised using rerun instead of shotgun. I'm happy to say it solved this issue for me.

Try using Thin as the server. I noticed an increase in performance compared with WEBrick and Mongrel.
gem install thin
When you run your app using ruby TestServer.rb you'll see the following:
Sinatra/0.10.1 has taken the stage on 4567 for development with backup from Thin

I'm running Sinatra inside VMWare Fusion with Vagrant. My app was running slowly (about ten seconds to service a request). Then I found this gem:
Webrick is very slow to respond. How to speed it up?
It seems that WEBrick was (by default) configured to reverse dns lookup on every request, and that was slowing it down.

Related

How do you move a sinatra app to github pages?

I created a sinatra app and I'm trying to put it on github pages. I can run my app on localhost, but I don't know how to push it to the actual web.
I have tried googling and searching stackoverflow and I keep seeing people use heroku. Is this required? Is there anyway to push directly from sinatra to the web? I can get a simple index.html file to run on github pages, but I don't know how to get my sinatra app to run. Any help would be great.
As Sirajus says, Github pages only serve static HTML pages. Sinatra is a framework for producing code that produces web pages. It's really there for sites that require some server side processing (i.e. dynamic), but can serve static pages too (a wise decision).
It doesn't serve the pages itself, it runs on a Rack compliant application server (like Thin, Puma, Unicorn or Webrick) and when asked, it builds the page, gives it to the server and the server gives it to you.
Entirely static sites like Github pages or those served via Amazon's S3 are just a collection of HTML files sitting behind HTTP file servers (those of the Apache and Nginx variety). They're static because they're not generated on the fly… dynamically. They don't change, there's no extra processing needed to serve them. They're just sat there wait to be served. You could use things like Sinatra and Thin to do this, but the added complexity adds maintenance work, security issues, costs extra money, time… and crucially, slows the serving speed down. If your site is essentially all static, by which I mean there's no need for the server to process anything, then you may be better off using something that generates static pages from the off. There are many libraries to help with this, Middleman (based on Padrino and hence Sinatra) and Jekyll come to mind, as does Nanoc.
You can emulate what these libraries do by saving the output of each route and uploading that, if it's appropriate. There are libraries that help with this, like Sinatra Static and its fork, Sinatra Export. You could use cURL to save the pages with a command like curl http://localhost:9292/ > index.html for every single path if you wanted. I did something like this for my own blog the other day.
If it's not appropriate to do this or you can't be bothered, set up some server hosting. A lot of these services are free to start with so it won't hurt to give them all a try, you'll learn a lot from doing each.
To run your sinatra app you need to host it with a server. Github pages only run html page not a ruby web application.
To host your sinatra app you can use heroku/ digital ocean.

How to deploy a Ruby app - not ROR?

I am very new to ruby and I wonder, Is it possible to have my ruby script deployed on a server?
Or I should have to use Rails?
As I can understood that Rails is not part of the core Ruby lang, and Ruby have server functionality even without Rails. (as in Java, PHP, etc..)
EDIT:
I have a Ruby script - acts as a cmd-line passed program - and I want to deploy it to an external (or even internal) server the way CGI scripts/programs used to do.
Yes, you can deploy any Ruby application, not just Rails apps obviously. Take a look at Capistrano.
Deployment and serving are two different things however. If you're looking for Ruby HTTP servers look at Unicorn, Thin, WEBrick, Puma.
If you want a fully-fledged solution try Heroku which handles both the deployment and web serving parts.
There are many tools to deploy Ruby projects, but you can do it pretty much manually.
I also found it very hard to find an easy-to-go solution and I think this is a very annoying gap in RoR framework.
I've been working in a solution to deploy a project to a server using Git, like the Heroku toolbelt (google it, is a really nice tool). The main concept is: you use Git to push your project and the server does everything else! Here you can see my project: https://github.com/sentient06/RDH/.
But please, don't focus on that. Instead, read the way I came to all information in the wiki: https://github.com/sentient06/RDH/wiki.
It is a bit outdated, but I can summarize here to you:
First, setup your server. This is the most boring part, you must setup all configuration, security measures, remote access, etc, etc.
If you don't have a server, you can hire one specially for RoR applications. There are a few good out there and each has a different deployment workflow. But supposing you decide o setup yourself:
I suggest you have any Linux or Unix system, server version. Then install Ruby Version Manager, then Ruby and then Rails. Then install a server application. I suggest Thin, but lots of people use Unicorn or Apache or other servers. Dig a little bit on the internet, find an easy to use solution. If you do not use Apache, though, you will need a "reverse proxy" too, so you can redirect all requests on ports 80, 8080, etc, to your applications. I suggest Nginx (I don't like Apache, I think is too overkill).
Now, everything done, the deploy process can be done more or less like this:
1 - Commit everything in a way your files are updated in the server;
2 - In the server, cd to the directory of your application and execute these commands:
$ bundle package
$ bundle install --deployment
$ RAILS_ENV=production rake db:migrate
$ rake assets:precompile
3 - Restart the server and, if necessary, the reverse proxy.
Dig on the internet to understand each command. These will pretty much force your application into production mode, reduce the space used by your javascript and CSS, migrate your production database and install the bundles. Production RoR is not so different from development RoR, it is just more compact and faster.
I do hope these informations are useful.
Good luck!
Update:
I forgot to mention, check ruby-toolbox, it has some really useful statistics and information on how often Rails technologies are being updated. They have many categories, this one is on deployment automation, give it a look: https://www.ruby-toolbox.com/categories/deployment_automation.
Cheers!

Is there a standard way to serve pre-gzipped assets in Rails 3.2 on Heroku Cedar?

I have a Rails 3.2 app that I'm deploying on the Heroku Cedar stack. This means that the app itself is responsible for serving its static assets. I'd like these assets to be gzipped, so I've inserted Rack::Deflater in my middleware stack in production.rb:
middleware.insert_after('Rack::Cache', Rack::Deflater)
...and curl tells me that this works as advertised.
However, since Heroku is going to all the effort of running rake assets:precompile, producing a bunch of pre-gzipped assets, I'd quite like to use those (rather than letting Rack::Deflater do all the work again). I've seen recipes for serving these up with nginx (no use on Heroku), and with CDNs (not wanting to use a CDN just yet), but I haven't seen anything that can just run standalone. I've hacked together a rack middleware to do this, but I was wondering if this is the best way to go about it?
Since deflater is after rack cache, then deflator will only have to do the work once, and after that the compressed assets will be served from rack cache (assuming the cache is big enough so that they don't get bumped out occasionally).
That said, your middleware looks pretty cool, and you should make make it a gem and blog about it, maybe it will be what people start to use :-)

How does Pow/Phusion Passenger/Webrick work?

I come from a PHP and .NET world where I understand the environment fairly well. However I can't find a newbie explanation of how the Ruby / Ruby on Rails stack actually work with these web server.
Are they more close to the PHP model, where all classes of an application are loader for each request and there is no default shared memory, or is it like an application server where an active app sits in the memory and handles requests?
How is it with reloading when a file changes? Does the app in an application server has to be restarted? How does it know? Does it monitor file system?
I have seen that both the Ruby Version Manager (rvm) and the newer rbenv from 37signals shomewhat shuffles with the ruby command on OS X / Linux. This seems like a total magic to me. Does a webserver just runs ruby command and does not care where the interpreter is resolved in the $PATH?
Webrick is the default server of Rails and is usually used for developing and testing.
Rails is session based like PHP is. If you want to run in production you will generally use Phusion Passenger on Apache or Nginx, dont worry about that for now.
If you run in Development or Test environment you can edit your application files(views, controllers and models) and they will be reloaded on each request (even if they are not edited).
Have a look at generating a project and scafolds with Rails to get you started.
http://guides.rubyonrails.org/getting_started.html

Ruby (off the Rails) Hosting

Many people have asked about Rails hosting on this site, but I'm not familiar enough with the back end of things to know if there's a difference.
I want to host some Ruby CGI 'webservices', basically just ruby methods that take parameters from a POST request, access a MySQL db and return data.
I've looked at RoR and it seems like overkill for this, from what I can tell it's for speeding up the development of data baesd CRUD sites, which is not at all what I'm doing.
So my question is, does this affect the hosting provider I choose? Does anyone recommend a good Ruby host for CGI operations? I'm not familiar with FastCGI, mod_ruby, Passenger, Mongrel etc. and what they mean for performance, scalability etc. I just want to host my ruby scripts with reasonably good performance, and all the info out there(and here) seems to be focused on rails.
First, if you want lightweight, Sinatra is usually my first pick. Pair it up with rack and Passenger for best results. It's not CGI, but realistically speaking, CGI is rarely a good match-up with Ruby.
Here's the "Hello World!" Sinatra app from the main page:
require 'rubygems'
require 'sinatra'
get '/hi' do
"Hello World!"
end
Hard to get more lightweight than that.
As for providers, anybody that supports Passenger (mod_rack) should be able to handle Sinatra. I'm a big fan of Slicehost personally, but they're a VPS host, which means you need to be able to install and manage the entire stack yourself. If you don't mind paying a tiny bit extra for the infrastructure, Heroku makes installation and deployment dead simple, so long as your needs don't exceed what they provide (sounds like they won't). In the unlikely event that you're only using 5MB or if you're using an external storage mechanism like Amazon RDS, Heroku may actually be free for you.
Update:
Passenger is an Apache module that allows Rack applications to be run inside of Apache.
Rack is a middleware layer that separates the web server and the web framework from each other. This allows web frameworks to run on any web server for which there is an adapter.
Sinatra is a lightweight web framework that runs on top of Rack.
Once Passenger and Rack are installed (gem install rack, gem install passenger) you just need to edit the Apache vhost to point at the config.ru file for your Sinatra app and create the required directories as per the Passenger docs and you'll be good to go.
I think you might want to look into Rack. It allows you to do the kinds of things you're talking about and shrugs off the weight of frameworks like Rails or Merb. Rack applications can be hosted at a place like Heroku.

Resources