Requirements
- only 1 thread holds the lock
- no dead lock
- can be blocked, and can be waken up from blocked status
- Note that it is almost impossible to achieve 1 and 2 at the same time (See the analysis below). Normally it becomes a tradeoff.
Redis
- set expiry time on lock. Other contenders will get the expiry time so to know when to retry
- the current holder will have a watchdog process to renew the lease.
- setnx and expire can be set in a same command as set
- record lock holder to prevent unlocking by mistake.
- compare and unlock is done in an atomtic action
- Timeshift,e.g., NTP may trick early release
- need record the number of acquires and incr/dec accordingly. When dec it to 0, you know it is safe to delete.
- Note that on production common just to use Redisson, although it does NOT handle correctness in the case of master fail-over
Problem:
- TTL is hard to set it right
- Master - slave replication may lose data
Zookeeper
- Zookeeper has official lock recipe. Also checkout Apache curator
* create a smallest ordered number in a lock dir
- listen for the smallest value in that lock dir if it exsits already for its deletion event
* On that listened val’s deletion, ask again if it is holding the lock
- On releasing the lock, delete ordered number created in the first setp
- heartbeat to prevent dead lock
- caller thread can be blocked, and will be waken up via Watch
- Problem: lost heartbeat from old caller will trick ZK server to release the lock too early - the caller process itself is still up
- To scale up,e.g., flash sale, common to use segmented locks on segmented contents, but this also means that the client code HAS to try different segments, if the current segment does not work