================================HOLY Crap, My Rails Site is Slow ================================ Ever say this? Ever feel this? Ever wonder how to fix this? I''ll give you some solid ideas on how to fix this. Let''s start with a few things to make sure we''re all on the same page here. Your general site makeup will have: A backend server component (Apache for instance) A frontend server component (passenger, nginx etc.) Your application (Rails) Apache: A lot of initial troubles really start at the apache end. If you edit your apache2.conf file, I use apache2, for instance, and look over a few simple things, scroll down the prefork section that contains: <IfModule mpm_prefork_module> StartServers 5 MinSpareServers 5 MaxSpareServers 10 MaxClients 150 MaxRequestsPerChild 0 </IfModule> One of the biggest issues I see that people make is with one line here and that is MaxClients. What is MaxClients? Straight from apache docs: The MaxClients directive sets the limit on the number of simultaneous requests that will be served. Any connection attempts over the MaxClients limit will normally be queued, up to a number based on the ListenBacklog directive. Once a child process is freed at the end of a different request, the connection will then be serviced. I remember, when visiting IRC for #httpd one day, some fella telling another, just increase that setting to 256 and you''ll be okay. The guy he was telling this to was on a virtual server utilizing 256m of RAM. Do you know what will happen here? Good guess maybe? Well, before I answer that let''s look at how to properly calculate MaxClients for any apache setup. First, you go to your server and type Top and hit enter. Top allows you to view your system resources, cpu, mem, etc. Press Shift+M to sort by memory. Now then, you should be able to see some process IDs running under different users. If you look at the command column, you will see apache2 for instance, and in my case, www-data is the user. The mem column tells me what percentage of memory is being used for a single instance, per user connection attempt. So, on a 256m slice, this might be around 2.4%. If you take 90% and divide that by 2.4% you get.. 37.5 or let''s round down to 37. Why 90% and not 100%? You still have to account for resources that your server needs to have available to it. So, now looking back at the guy who told the other fella to set this to 256, if we take 256 and multiply it by 2.4 we get 614% of memory usage. 100% memory usage versus 614% memory usage.. I think you get the picture. The point here is to make sure you properly configure apache. Make sure you''ve calculated and optimized everything here. If you don''t, you will create a lot of issues for yourself. Other Apache notables: Expires Headers, Gzip should be used for caching and compression of content. Passenger/Nginx: There are a lot of articles about optimizing these areas. I have to admit that my knowledge with either is still very slim but I''m working with passenger and finding that it''s pretty easy to work with. passenger-memory-stats passenger-status Both of these commands are really good to use with passenger so make use of them. I''m not going to go into optimizing passenger at all here because my knowledge is just not strong enough to provide any details here. If someone wants to add to this discussion with some optimization links or techniques for both passenger and nginx, please do so! Thanks. Rails: Caching If you haven''t tried caching, you should look into it. Page caching, action caching, and fragment caching. All three are very useful but the differences in speed are noticeable. Page caching is faster than action caching is faster than fragment caching. That''s the way it runs. Depending on your app, you can use all three if necessary. For instance, on pages that are very dynamic, or include authentication, fragment caching might be necessary for specific areas. On static pages with content that pretty much never changes, page caching is what you would use. Look over all 3 and learn them. If you want to get advanced, go with memcached. Memcached is really great if you have a multi-tiered setup (multiple content servers) as you can have all those content servers working in the same cache pool. Reverse Proxy Caching is also great to implement. It puts less of a load on your server and sets up a proxy layer where you can expire content. Database Optimize your database. If you have fields that end with _id and they are foreign keys, setup indexes on them. Make sure you use includes and joins so that you aren''t sending multiple queries to your db. Normalize your database properly but dont'' over-normalize your database to the point your rails app no longer functions. If you have some heavy work to do with your database, calculations and such, you might want to look into setting up stored procedures in your database. It can be a little difficult getting used to using them with rails but it will make a world of difference when you get used to understanding them. Newrelic RPM http://www.newrelic.com/features.html This is a really useful utility to use for measuring and optimizing your rails app and site. Look into it. Firefox Plugins Firebug and YSlow: Most people know about Firebug but Yslow is really solid on grading your site. YSlow grades out your site like such: * F Use a Content Delivery Network (CDN) * F Add Expires headers * C Compress components with gzip * A Put CSS at top * A Put JavaScript at bottom * A Avoid CSS expressions * N/A Make JavaScript and CSS external * A Reduce DNS lookups * A Minify JavaScript and CSS * A Avoid URL redirects * A Remove duplicate JavaScript and CSS * F Configure entity tags (ETags) * A Make AJAX cacheable * A Use GET for AJAX requests * A Reduce the number of DOM elements * A Avoid HTTP 404 (Not Found) error * A Reduce cookie size * A Use cookie-free domains * A Avoid AlphaImageLoader filter * A Do not scale images in HTML * A Make favicon small and cacheable Summary: Keep in mind, I''m only touching on about 70% of the things you can do to improve the slowness of your site. The idea is to become very familiar with all of the different pieces of the puzzle and implement things properly. Don''t be afraid or lazy. Optimize your site! Take care. -- Posted via http://www.ruby-forum.com/.
Hi Joel, On Fri, 2009-08-14 at 18:13 +0200, Alpha Blue wrote:> Let''s start with a few things to make sure we''re all on the same page > here. > > Your general site makeup will have: > > A backend server component (Apache for instance) > A frontend server component (passenger, nginx etc.) > Your application (Rails)Not sure we''re using the ''back'' / ''front'' words the same, but in my lingo you''ve got these reversed. Apache lives ''in front of'' passenger / mongrel / etc. serving static content itself and directing requests for dynamic content to them. HTH, Bill> Apache: > > A lot of initial troubles really start at the apache end. If you edit > your apache2.conf file, I use apache2, for instance, and look over a few > simple things, scroll down the prefork section that contains: > > <IfModule mpm_prefork_module> > StartServers 5 > MinSpareServers 5 > MaxSpareServers 10 > MaxClients 150 > MaxRequestsPerChild 0 > </IfModule> > > One of the biggest issues I see that people make is with one line here > and that is MaxClients. What is MaxClients? Straight from apache docs: > > The MaxClients directive sets the limit on the number of simultaneous > requests that will be served. Any connection attempts over the > MaxClients limit will normally be queued, up to a number based on the > ListenBacklog directive. Once a child process is freed at the end of a > different request, the connection will then be serviced. > > I remember, when visiting IRC for #httpd one day, some fella telling > another, just increase that setting to 256 and you''ll be okay. The guy > he was telling this to was on a virtual server utilizing 256m of RAM. > Do you know what will happen here? Good guess maybe? > > Well, before I answer that let''s look at how to properly calculate > MaxClients for any apache setup. > > First, you go to your server and type Top and hit enter. Top allows you > to view your system resources, cpu, mem, etc. Press Shift+M to sort by > memory. Now then, you should be able to see some process IDs running > under different users. If you look at the command column, you will see > apache2 for instance, and in my case, www-data is the user. The mem > column tells me what percentage of memory is being used for a single > instance, per user connection attempt. So, on a 256m slice, this might > be around 2.4%. If you take 90% and divide that by 2.4% you get.. 37.5 > or let''s round down to 37. > > Why 90% and not 100%? You still have to account for resources that your > server needs to have available to it. So, now looking back at the guy > who told the other fella to set this to 256, if we take 256 and multiply > it by 2.4 we get 614% of memory usage. 100% memory usage versus 614% > memory usage.. I think you get the picture. > > The point here is to make sure you properly configure apache. Make sure > you''ve calculated and optimized everything here. If you don''t, you will > create a lot of issues for yourself. > > Other Apache notables: > > Expires Headers, Gzip should be used for caching and compression of > content. > > Passenger/Nginx: > > There are a lot of articles about optimizing these areas. I have to > admit that my knowledge with either is still very slim but I''m working > with passenger and finding that it''s pretty easy to work with. > > passenger-memory-stats > passenger-status > > Both of these commands are really good to use with passenger so make use > of them. > > I''m not going to go into optimizing passenger at all here because my > knowledge is just not strong enough to provide any details here. If > someone wants to add to this discussion with some optimization links or > techniques for both passenger and nginx, please do so! > > Thanks. > > Rails: > > Caching > > If you haven''t tried caching, you should look into it. Page caching, > action caching, and fragment caching. All three are very useful but the > differences in speed are noticeable. Page caching is faster than action > caching is faster than fragment caching. That''s the way it runs. > Depending on your app, you can use all three if necessary. For > instance, on pages that are very dynamic, or include authentication, > fragment caching might be necessary for specific areas. On static pages > with content that pretty much never changes, page caching is what you > would use. Look over all 3 and learn them. > > If you want to get advanced, go with memcached. Memcached is really > great if you have a multi-tiered setup (multiple content servers) as you > can have all those content servers working in the same cache pool. > > Reverse Proxy Caching is also great to implement. It puts less of a > load on your server and sets up a proxy layer where you can expire > content. > > Database > > Optimize your database. If you have fields that end with _id and they > are foreign keys, setup indexes on them. Make sure you use includes and > joins so that you aren''t sending multiple queries to your db. > > Normalize your database properly but dont'' over-normalize your database > to the point your rails app no longer functions. > > If you have some heavy work to do with your database, calculations and > such, you might want to look into setting up stored procedures in your > database. It can be a little difficult getting used to using them with > rails but it will make a world of difference when you get used to > understanding them. > > Newrelic RPM > > http://www.newrelic.com/features.html > > This is a really useful utility to use for measuring and optimizing your > rails app and site. Look into it. > > Firefox Plugins > > Firebug and YSlow: Most people know about Firebug but Yslow is really > solid on grading your site. > > YSlow grades out your site like such: > > * > F Use a Content Delivery Network (CDN) > * > F Add Expires headers > * > C Compress components with gzip > * > A Put CSS at top > * > A Put JavaScript at bottom > * > A Avoid CSS expressions > * > N/A Make JavaScript and CSS external > * > A Reduce DNS lookups > * > A Minify JavaScript and CSS > * > A Avoid URL redirects > * > A Remove duplicate JavaScript and CSS > * > F Configure entity tags (ETags) > * > A Make AJAX cacheable > * > A Use GET for AJAX requests > * > A Reduce the number of DOM elements > * > A Avoid HTTP 404 (Not Found) error > * > A Reduce cookie size > * > A Use cookie-free domains > * > A Avoid AlphaImageLoader filter > * > A Do not scale images in HTML > * > A Make favicon small and cacheable > > Summary: > > Keep in mind, I''m only touching on about 70% of the things you can do to > improve the slowness of your site. The idea is to become very familiar > with all of the different pieces of the puzzle and implement things > properly. Don''t be afraid or lazy. Optimize your site! > > Take care.
> Not sure we''re using the ''back'' / ''front'' words the same, but in my > lingo you''ve got these reversed. Apache lives ''in front of'' passenger / > mongrel / etc. serving static content itself and directing requests for > dynamic content to them. > > HTH, > BillHi Bill, you are correct. My use of backend/frontend was not correct, but yep you knew what I was trying to get at. :) Reverse Proxy lives in front of Apache lives in front of Passenger lives in front of Rails. -- Posted via http://www.ruby-forum.com/.
Alpha Blue wrote: [...]> Reverse Proxy lives in front of Apache lives in front of Passenger lives > in front of Rails.Interesting essay; I''ll try to find time to comment in depth. But why are you using a reverse proxy with Passenger? Or was that hypothetical? Best, -- Marnen Laibow-Koser http://www.marnen.org marnen-sbuyVjPbboAdnm+yROfE0A@public.gmane.org -- Posted via http://www.ruby-forum.com/.
Marnen Laibow-Koser wrote:> Alpha Blue wrote: > [...] >> Reverse Proxy lives in front of Apache lives in front of Passenger lives >> in front of Rails. > > Interesting essay; I''ll try to find time to comment in depth. But why > are you using a reverse proxy with Passenger? Or was that hypothetical? > > Best, > -- > Marnen Laibow-Koser > http://www.marnen.org > marnen-sbuyVjPbboAdnm+yROfE0A@public.gmane.orghypothetical. -- Posted via http://www.ruby-forum.com/.
On Aug 14, 2:26 pm, Alpha Blue <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> Marnen Laibow-Koser wrote: > > Alpha Blue wrote: > > [...] > >> Reverse Proxy lives in front of Apache lives in front of Passenger lives > >> in front of Rails. > > > Interesting essay; I''ll try to find time to comment in depth. But why > > are you using a reverse proxy with Passenger? Or was that hypothetical? > > > Best, > > -- > > Marnen Laibow-Koser > >http://www.marnen.org > > mar...-sbuyVjPbboAdnm+yROfE0A@public.gmane.org > > hypothetical. > > -- > Posted viahttp://www.ruby-forum.com/.I guess a load balancer is a specific type of reverse proxy.
On Aug 14, 12:13 pm, Alpha Blue <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> ================================> HOLY Crap, My Rails Site is Slow > ================================> > Ever say this? Ever feel this? Ever wonder how to fix this? I''ll give > you some solid ideas on how to fix this. > > Let''s start with a few things to make sure we''re all on the same page > here. > > Your general site makeup will have: > > A backend server component (Apache for instance) > A frontend server component (passenger, nginx etc.) > Your application (Rails) > > Apache: > > A lot of initial troubles really start at the apache end. If you edit > your apache2.conf file, I use apache2, for instance, and look over a few > simple things, scroll down the prefork section that contains: > > <IfModule mpm_prefork_module> > StartServers 5 > MinSpareServers 5 > MaxSpareServers 10 > MaxClients 150 > MaxRequestsPerChild 0 > </IfModule> > > One of the biggest issues I see that people make is with one line here > and that is MaxClients. What is MaxClients? Straight from apache docs: > > The MaxClients directive sets the limit on the number of simultaneous > requests that will be served. Any connection attempts over the > MaxClients limit will normally be queued, up to a number based on the > ListenBacklog directive. Once a child process is freed at the end of a > different request, the connection will then be serviced. > > I remember, when visiting IRC for #httpd one day, some fella telling > another, just increase that setting to 256 and you''ll be okay. The guy > he was telling this to was on a virtual server utilizing 256m of RAM. > Do you know what will happen here? Good guess maybe? > > Well, before I answer that let''s look at how to properly calculate > MaxClients for any apache setup. > > First, you go to your server and type Top and hit enter. Top allows you > to view your system resources, cpu, mem, etc. Press Shift+M to sort by > memory. Now then, you should be able to see some process IDs running > under different users. If you look at the command column, you will see > apache2 for instance, and in my case, www-data is the user. The mem > column tells me what percentage of memory is being used for a single > instance, per user connection attempt. So, on a 256m slice, this might > be around 2.4%. If you take 90% and divide that by 2.4% you get.. 37.5 > or let''s round down to 37. > > Why 90% and not 100%? You still have to account for resources that your > server needs to have available to it. So, now looking back at the guy > who told the other fella to set this to 256, if we take 256 and multiply > it by 2.4 we get 614% of memory usage. 100% memory usage versus 614% > memory usage.. I think you get the picture. > > The point here is to make sure you properly configure apache. Make sure > you''ve calculated and optimized everything here. If you don''t, you will > create a lot of issues for yourself.Eh... not really how it works. First, the amount of client requests only maps to the amount of Apache processes running when using the prefork MPM. However, with the exception of fairly nasty virtualization environments (like Virtuozzo), threaded MPMs give you much more efficient resource usage. And even *then*, MPM selection and configuration is a topic worthy of volumes of discussion on its own. Also, linux is *fantastic* at being deceptive about process memory usage. The %MEM column in top is fairly worthless when judging how much memory Apache is really using... as is pretty much every "default" tool. passenger-memory-stats is pretty good at this though! And even *then* configuring memory limits is **highly** dependent on your production environment''s configuration. If you only have one machine, than probably no one component (webserver, DB, mail, etc) should be allowed to use over half your available memory. Things do get when when you add multiple servers to the mix though And even **then** all this server configuration milarky is the last (chronological, not emphatically) thing you as the Rails developer should be be worrying about. The first step to *any* optimization is finding where the major bottlenecks in your app are. Newrelic is indeed a great tool for that. Once you''ve found the major general areas to work on, you''ll need to break out the actual profiler (ruby- prof is pretty good, unless you''re using Ruby 1.9 :( ) and actually get dirty. This is where it is *vital* to have thorough test coverage, else who knows what you''ll mysteriously break when optimizing your code. (and assuming your code is well structured and understandable to begin with, don''t be afraid of making it ugly to speed things up at this point... thats why you write tests and "elegant" code in the beginning). Gah sooo much more to talk about here though, I guess someone else will contribute more to this thread. At this point I guess I''ll just plug Enterprise Rails. Seemingly rushed execution aside, it is THE absolute best Rails-geared book that currently exists in regards to application structure and performance.
Good follow-up Pharrington. My goal with the topic is to make people aware that oftentimes the reason why a site is slow is not due to any one particular reason but mainly due to the fact that the site, in its entirety, has not been properly optimized. I really do like newrelic RPM - it''s very useful. One thing I definitely like is this: http://railslab.newrelic.com/scaling-rails This is probably one of the best put-together series of screencasts on scaling rails and optimizing rails. It''s a must watch for everyone. -- Posted via http://www.ruby-forum.com/.
Good stuff. I have been following the scaling rails series and must say, very very important for Rails developers. The part about calculating the MaxClients for Apache --> It would be great if inexperienced people like me could learn from someone who would be gracious enough to explain how it can be done. When I went through that part in the configuration file, it was rather obvious there was some optimization to be done there but had no idea how to arrive at the golden numbers. Anyone who could provide a good thorough run down on how to optimize Apache? Thanks again for starting this thread. On Aug 15, 2:25 am, Alpha Blue <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> Good follow-up Pharrington. > > My goal with the topic is to make people aware that oftentimes the > reason why a site is slow is not due to any one particular reason but > mainly due to the fact that the site, in its entirety, has not been > properly optimized. > > I really do like newrelic RPM - it''s very useful. > > One thing I definitely like is this: > > http://railslab.newrelic.com/scaling-rails > > This is probably one of the best put-together series of screencasts on > scaling rails and optimizing rails. It''s a must watch for everyone. > -- > Posted viahttp://www.ruby-forum.com/.