Performance and optimization in Ruby on Rails applications are crucial topics to ensure a fast and efficient experience for users. This involves several techniques, from caching to configuration and scalability adjustments.
Caching
Stores the HTML generated from pages in cache to serve quickly to subsequent users, avoiding the need to process the request again. Obviously this is super fast. Unfortunately, it cannot be applied to all situations (such as pages that need authentication) and since the web server is literally just serving a file from the file system, cache expiration is an issue that needs to be resolved.
To enable page caching, you need to use the "caches_page" method.
class ProductsController < ActionController
caches_page :index
def index
@products = Products.all
end
end
Fragment Caching
Caches specific parts of pages, such as chunks of HTML, to reduce rendering time. For example, if you want to show all orders placed on your website in real time and you don't want to cache that part of the page, but you want to cache the part of the page that lists all available products, you could use this snippet of code:
<% Order.find_recent.each do |o| %>
<%= o.buyer.name %> bought <%= o.product.name %>
<% end %>
<% cache do %>
All available products:
<% Product.all.each do |p| %>
<%= link_to p.name, product_url(p) %>
<% end %>
<% end %>
The cache block in our example will be linked to the action that called it and will be written to the same location as the Action Cache, which means that if you want to cache multiple fragments per action, you must provide an "action_suffix" for the call. cache:
% cache(:action => 'recent', :action_suffix => 'all_products') do %>
All available products:
and you can expire using the "expire_fragment" method, like this:
expire_fragment(:controller => 'products', :action => 'recent', :action_suffix => 'all_products')
If you don't want the cache block to be tied to the action that called it, you can also use global-key shards by calling the cache method with a key, like so:
<% cache('all_available_products') do %>
All available products:
<% end %>
This fragment is then available to all actions in the ProductsController using the key and can expire in the same way:
expire_fragment('all_available_products')
Scalability
SQL query optimization, using indexes and sharding to distribute data across multiple databases is a Rails feature that caches the result set returned by each query so that if Rails encounters the same query again for that request, it will use the cached result set instead of running the query against the database again. For example:
class ProductsController < ActionController
def index
# Run a find query
@products = Product.all
...
# Run the same query again
@products = Product.all
end
end
The second time the same query is executed against the database, it will not hit the database. The first time the query result is returned, it is stored in the query cache (in memory) and the second time it is extracted from memory.
Application Servers
Use of load balancers and horizontal scaling to handle increased traffic.
Example: Configuring application servers such as Puma or Unicorn for load balancing.
Distributed Cache
Using distributed caching to share data across multiple servers.
Example: Using Redis as a shared cache between application instances.
# Redis configuration for distributed cache in config/initializers/cache.rb
Rails.application.config.cache_store = :redis_store, {
host: "localhost",
port: 6379,
db: 0,
namespace: "app_cache"
}
Configuration Settings
Environment Settings: Specific adjustments for different environments (development, production, testing) to optimize performance at each phase of the application lifecycle.
Example: Configuring different databases for test and production environments.
Server Tuning
Web server and database configuration adjustments for better performance.
Example: Configuring the maximum number of simultaneous connections on the web server.
Conclusion
In summary, optimizing the performance of Ruby on Rails applications involves a combination of intelligent caching, efficient scalability, and fine-tuning configuration. These practices ensure that the application can handle large volumes of traffic quickly and responsively, providing a better experience for users.
These are just a few examples of how performance and optimization techniques can be applied in real-world scenarios in Ruby on Rails applications.
Top comments (0)