In Rails Session Management Howto, Part III of this series, I described memory based session storage approaches. The mem_cache_store approach provides fast access to the session data and unparalleled scaling, but doesn’t provide rock solid reliability (because it is ultimately a cache). It also maybe overkill for a lot of applications. In this post, I will discuss the final approach which is database based sessions.
There are a couple of options. The first is to use DRb storage. With the drb_store, the session data is marshaled to a DRb server. The DRb server is accessible from multiple servers so you can scale out to many servers for your application. And it is also reliable. DRb stands for distributed Ruby and more information about DRb and DRb server is available in Intro to DRb. Performance is reported to be very solid with DRb based session storage.
The second option is to utilize the built in Active Record capability of rails. I like the active_record_store because it is easy to configure and immediately provides scalability and reliability to session data storage. Performance is largely dependent on the database server infrastructure, which is a well know field and has many different optimization possibilities. Rails provides a simple way to configure the sessions by running rake db:sessions:create. Then you can just run the migration to create the table via rake db:migrate.
As pointed out by the authors of Agile Web Development with Rails, the proper choice of session storage is uniquely application and environment driven. There is an older study, by Scott Barron comparing the performance of some of these approaches. Although the results might have changed slightly, the considerations and insights are still probably very valid.
I personally use the active_record_store as my default approach. It requires no special outside expertise to implement and for most applications it is scalable and reliable. What do you use?
In Rails Session Management Howto, Part II, I discussed using the PStore approach for session data storage. The p_store based sessions utilize the local OS file system. In this post, I will present memory based storage approaches for session management in Rails.
The first approach is to use memory_store based sessions. With MemoryStore the session objects are kept in the applications memory with no serialization necessary. While this approach will make it extremely fast for an application to move objects in and out of a session store, it is not a reliable method because the memory where the session data is stored is only available to a single server. Thus it also does not scale well since it requires sticky sessions.
The second approach utilizes memcached, a high-performance, distributed memory object caching system. Memcached is used by some of the largest websites in the world and is certainly a very solid approach for session storage. The mem_cache_store based sessions meet the criteria of scalability (just add more servers) but this approach is still not reliable. Because it is a cache you still need to use some form of reliable storage for your session data, such as a database store. But if you need super fast reads of the session data across multiple servers, then memcached is really the best performing approach. You can find some discussion of that approach discussed in Sessions. Several memcached Ruby clients are available including RMemCache.
For more discussion of these memory based sessions and their configuration, I recommend you pickup a copy of the excellent reference Agile Web Development with Rails.
Are you using a memory based session approach? How do you scale and protect against server crashes (or maintenance)?
In Rails Session Management Howto Part I, I introduced the concepts of managing http sessions with Rails and explored the first approach, cookie based sessions. A couple of the limits were the size of the data that can be stored in the session and the lack of encryption as the data is transferred from browser to server. The next approach is to store session data in a flat file on the server in what is known as the PStore format. This format stores the serialized (marshaled) form of the session data on the file system. The location and name (actually just the prefix for the name) of the file can be configured in the environment.rb file. Refer to Agile Web Development with Rails by Dave Thomas for details on the syntax and configuration.
The benefits of using the p_store based sessions are that the data is securely kept on the server and never crosses the network between the browser and server. This provides security and also reduces bandwidth usage. The size limit of the session data is also greatly increased (limited by your system IO).
What happens when scaling the number of servers? Clearly each server can not have an individual PStore unless one is using “sticky” sessions and are willing to have users lose their session data when a server fails. This is not an optimal situation for scalable, reliable, load-balanced systems. When there is more than one server, then it is necessary to have the PStore file available to all servers because subsequent http requests may be directed to a different server each time. One way to do this is to place the PStore file on a network mounted storage system.
Thus with a p_store based session there is increased data security and reduced bandwidth usage vs a cookie based session. However, there is also now some challenging server configuration choices and network file storage. Thus it is a IO limited solution which requires a lot of optimization and monitoring. For some applications this might not be a problem and should be tested. In an application with many simultaneous sessions the number of PStore files can grow very large.
I’ll also briefly mention that there is a file_store option for sessions in Rails which also uses flat files, but it is rarely used because the session data must be strings.
Is anyone using p_store based sessions in their applications? Is it scalable? Is it reliable when servers failover?
In the next part of this series I will examine some memory based sessions.
Today I am going to start a series of posts describing various approaches to managing http sessions with a Ruby on Rails application. Http sessions are valuable for managing state when using a stateless protocol like http. The emphasis here will be on moving toward the most resilient and scalable solutions. For more detail on sessions and Rails I strongly recommend you purchase Agile Web Development with Rails by Dave Thomas.
Sessions can contain any objects which can be marshaled (think serialization if you are used to other languages). Rails provides numerous ways to persist the session objects. The default in Rails 2.0 is to send it via a cookie to the client. Because the session is hash-like, multiple objects may be stored in the session. The size limit of cookie based session objects is 4K total.
Because the data in the session is passed with every http request from the client to the server, this can cause an increase in bandwidth usage compared to alternative approaches (discussed in the next posts). Also, even though the cookie contents are signed, they are unencrypted by default. So no secure data should be stored in the session when using the cookie_store.
If your session data is very small and the data is not sensitive, then using the cookie_store can be very effective. However, for many web applications this is not the case and fortunately Rails provides some effective solutions.
You can change the session defaults in your controllers by overriding them with the session declaration in a controller.
I have been trying to determine strategies for implementing sessions via Ruby on Rails. I am particularly concerned about scalability and session replication across multiple servers in large scale sites. What is the proper choice? Here are some options for session management with Rails:
- No session
Using PStore writes to a local file system, which doesn’t scale across multiple servers unless it is a shared directory visible to them all. This isn’t very practical across multiple data-centers. ActiveRecordStore uses a DB which means each access of the session objects may use DB resources. Again this isn’t scalable.
Thus, MemCacheStore looks like the way to go for most web applications. There is a great discussion of it by Stefan Kaes.
Anybody else using another solution?