I've been looking for a solution for implementing Mongrel cluster synchronization. My application writes and updates XML files on disk. The possibility of having 2 (or more) users update the same file at the same time is very real. I'm using a Mongrel cluster for scalability.
I can't believe I haven't found an answer for this on the Internet. I thought this is a common problem for people in production. I did come across this problem before. I solved it by creating a separate bottle-neck process which performed the region which had to be sync-ed. The code was wrapped in a Mutex.synchronize block. All Mongrel instances called the bottle-neck process' only function through DRb.
I don't want to use this solution again. It is difficult to maintain, especially in production environments. So, without finding anything else on the Internet, the only other thing I could think of was using database locking. I will use the locking features of MySQL to create a synchronized region in a Mongrel cluster setup.
Rails provides optimistic and pessimistic locking through MySQL (see http://api.rubyonrails.com/classes/ActiveRecord/Locking/Pessimistic.html and http://api.rubyonrails.com/classes/ActiveRecord/Locking/Optimistic.html). In my case I didn't even consider optimistic locking because it requires conflict resolution. For my specific case conflict resolution was too difficult to do, so I looked into pessimistic locking. Here is a step-by-step breakdown of implementing it:
1. Create a model (no fields are necessary; mine is called lockers)
2. Migrate it (and insert one record in it - in the migrations script, e.g. 0)
3. Implement the synchronization region in your controller. Here's my code:
class DoerController < ApplicationController
def do
Locker.transaction do
r = Locker.find(1, :lock => true)
sleep 10
r.save!
end
redirect_to :action => :index
end
end
Now, the code inside the Locker.transaction block is synchronized. You can test it by opening X Firefox/Explorer tabs to X instances of Mongrel and click the "do" link at the same time. The first Mongrel will takes 10 seconds to finish, the second Mongrel 20 seconds, etc.
One word of advice: make sure you don't create the lockers table manually. The default "CREATE TABLE" statement in MySQL creates a tables with the myisam engine type, which does not support locking!!! Migrations in Rails crate tables with the innodb engine type which supports locking!!! I created the sync table manually and it took me half day to understand why the hell it wasn't sync-ing.
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment