Disclaimer: I already asked this question, but without the
deployment requirement. I got an
answer that got 3 upvotes, and when I
edited the question to include the deployment requirement the answer then
became irrelevant. The reason I'm
resubmitting is because SO considers
the original question 'answered', even
though I got no meaningful upvoted
answer. I opened a uservoice
submission about this problem.
The reason I reposted is so StackOverflow consider the original question answered, so it doesn't show up on the 'unanswered questions' tab.
Which distributed lock service would you use?
Requirements are:
- A mutual exclusion (lock) that can be seen from different processes/machines
- lock...release semantics
- Automatic lock release after a certain timeout - if lock holder dies, it will automatically be freed after X seconds
- Java implementation
- Easy deployment - must not require complicated deployment beyond either Netapp, MySql or GigaSpaces. Must play well with those products (especially GigaSpaces - this is why TerraCotta was ruled out).
- Nice to have: .Net implementation
- If it's free: Deadlock detection / mitigation
I'm not interested in answers like "it can be done over a database", or "it can be done over JavaSpaces" - I know. Relevant answers should only contain a ready, out-of-the-box, proven implementation.
Here's the outline of a GigaSpaces based answer that meets your criteria, depending on exactly what you mean in criteria 3. I work with GigaSpaces from .Net, not Java:
Create a locking class with a SpaceID+SpaceRouting property IDing what is locked and a DataMember bool property Unlocked:
sealed public class IdLockTrans
{
[SpaceID]
[SpaceRouting]
public string ID
{
get;
set;
}
[DataMember]
public bool Unlocked
{
get;
set;
}
public IdLockTrans(Id id)
{
ID = id.ID;
}
public IdLockTrans()
{
}
}
You will use GigaSpaces' lease time for lock release after a certain
timeout. This will cause GigaSpaces to remove IdLockTrans objects
from the space automatically after they have been idle for the timeout
period. The lack of an IdLockTrans for an ID means the ID is unlocked.
Your locker class will define and initialize these class members
private readonly ISpaceProxy _proxy;
private readonly long _leaseTime;
public override bool Lock(Id id, long timeout)
{
bool locked;
IdLockTrans lockTransTemplate = new IdLockTrans(id);
// Assume that this is a new id.
try
{
_proxy.Write(lockTransTemplate, null, _leaseTime, 0, UpdateModifiers.WriteOnly);
locked = true;
}
catch (EntryAlreadyInSpaceException)
{
using (ITransaction tx = _proxy.CreateLocalTransaction())
{
try
{
lockTransTemplate.Unlocked = true;
IdLockTrans lockTrans = _proxy.Take(lockTransTemplate, tx, timeout);
locked = (lockTrans != null);
if (lockTrans != null)
{
lockTrans.Unlocked = false;
_proxy.Write(lockTrans, tx, _leaseTime, 0, UpdateModifiers.WriteOnly);
}
tx.Commit();
}
catch
{
tx.Abort();
throw;
}
}
}
return locked;
}
public override void Unlock(Id lockedId)
{
IdLockTrans lockTrans = new IdLockTrans(lockedId);
lockTrans.Unlocked = true;
try
{
_proxy.Update(lockTrans, null, _leaseTime, 0, UpdateModifiers.UpdateOnly);
}
catch (EntryNotInSpaceException)
{
throw new Exception("IdLockTrans for " + lockTrans.ID
+ " not found on Unlock. Lock time exceeded lease time.");
}
}
Your .Net implementation is very close the existing out of the box lock/unlock API provided with the Java API. See:
http://www.gigaspaces.com/docs/JavaDoc8.0/org/openspaces/core/DefaultGigaMap.html
You may found the source code for this Java class as part of the gs-openspaces-src.zip file provided with the product. Having the same with Gigaspaces .Net API should be straightfwd.
In case you are still looking, take a look at Apache Zookeeper:
ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services. All of these kinds of services are used in some form or another by distributed applications.
The Zookeeper documentation provides examples of how to build a Lock service on top of Zookeeper.
Use mysql to lock a unique key is very simple.
Assumption 1:
You use transaction and your isolation level is read committed.
Assumption 2:
You lock you processing thread by a unique key, and release it when your transaction committed.
Then you can use this sql as a distribute lock:
Insert into distributed_lock(key)
values(#{key}) ON DUPLICATE KEY UPDATE key=key;