Distributed lock technology selection

First, based on the implementation of distributed database lock

  1. Pessimistic locking

Use select ... where ... for update exclusive lock

Note: Other additional features consistent with a realization, to note here is "where name = lock", name index field must go, otherwise it will lock the table. In some cases, such as small tables, mysql optimizer will not go the index, resulting in lock-table problem.

  1. Optimistic locking

The so-called optimistic locking front and the biggest difference is that the CAS-based thinking, which does not have mutually exclusive, no lock wait while consumption of resources during the operation does not believe there is a concurrency violation only after the update version failed to perceive. Our buying, spike is to use this implementation to prevent oversold.
Optimistic locking achieved by increasing the incremented version number field

Second, based on the cache (Redis, etc.) to achieve distributed lock

  1. Use Commands:
    (1) SETNX
    SETNX key val: if and only if the key does not exist, a SET key is a string of val, returns 1; if the key is present, then do nothing, 0 is returned.
    (2) The expire
    The expire Key timeout: Set a timeout for the key, the unit is second, more than this time will automatically release the lock, to avoid deadlock.
    (3) the Delete
    the Delete key: Delete key

When using Redis implementation of distributed locks, will be used primarily to these three commands.

  1. Thought achieved:
    (1) when acquiring the lock, lock setnx use, and use the command to add a timeout expire time of the lock, the time beyond which automatically releases the lock, the lock is a value of the UUID randomly generated, by this release lock time to judge.
    (2) to obtain a lock when it set a timeout acquired over this time if you give up to acquire the lock.
    (3) when the lock is released, it is not determined by the UUID of the lock, if the lock, the lock is released for the delete.

  2. Distributed Lock simple implementation code:

Copy Code
1 / *
2 * distributed lock simple implementation code. 4 /
. 5 DistributedLock {public class
. 6
. 7 Private Final JedisPool jedisPool;
. 8
. 9 public DistributedLock (JedisPool jedisPool) {
10 = this.jedisPool jedisPool;
. 11}
12 is
13 is /
*
14 * lock
15 * @param lockName lock Key
16 * @param acquireTimeout acquisition timeout
17 * @param timeout lock timeout
18 * @return lock identifier
. 19 /
20 is lockWithTimeout public String (String LockName, acquireTimeout Long, Long timeout) {
21 is Jedis Conn = null;
22 is retIdentifier String = null;
23 is the try {
24 // Get connected
JedisPool.getResource Conn = 25 ();
26 is a randomly generated // value
27 = UUID.randomUUID identifier String () toString ();.
28 // lock name, i.e. key value
29 String lockKey = "lock:" + lockName;
30 // timeout period, after which time the lock is automatically released over lock
31 is lockExpire int = (int) (timeout / 1000);
32
33 is acquired // lock timeout, over this time to abstain from acquiring the lock
34 long end = System.currentTimeMillis () + acquireTimeout;
35 the while (System.currentTimeMillis () <End) {
36 IF (conn.setnx (lockKey, identifier) ==. 1) {
37 [conn.expire (lockKey, lockExpire);
38 is returned // value value for releasing the lock time confirmation
39 identifier = retIdentifier;
40 return retIdentifier;
41 is}
42 is -1 // not set the representative key timeout, a timeout time set key
43 is IF (conn.ttl (lockKey) == -1) {
44 conn.expire(lockKey, lockExpire);
45 }
46
47 try {
48 Thread.sleep(10);
49 } catch (InterruptedException e) {
50 Thread.currentThread().interrupt();
51 }
52 }
53 } catch (JedisException e) {
54 e.printStackTrace();
55 } finally {
56 if (conn != null) {
57 conn.close();
58 }
59 }
60 return retIdentifier;
61 }
62
63 /
*
64 * 释放锁
65 * @param lockName 锁的key
66 * @param identifier 释放锁的标识
67 * @return
68 */
69 public boolean releaseLock(String lockName, String identifier) {
Jedis Conn = null 70;
71 is lockKey String = "Lock:" + LockName;
72 = to false Boolean retFlag;
73 is the try {
74 jedisPool.getResource Conn = ();
75 the while (to true) {
76 // monitor lock, ready to begin a transaction
conn.watch 77 (lockKey);
78 // value determination by the value returned is not in front of the lock, if the lock is removed, releasing the lock
79 IF (identifier.equals (conn.get (lockKey))) {
80 the Transaction conn.multi = Transaction ();
81 transaction.del (lockKey);
82 = transaction.exec Results List ();
83 IF (Results == null) {
84 Continue;
85}
86 = retFlag to true;
87}
88 Conn. unwatch ();
89 BREAK;
90}
91 is the catch} (JedisException E) {
92 e.printStackTrace ();
The finally {} 93
94 IF (Conn = null!) {
95 conn.Close ();
96}
97}
98 return retFlag;
99}
100}
copy the code

  1. Test just realized Distributed Lock

Example using a spike 50 threads analog product, used - operator to achieve a reduction in product, from the results of ordering can be seen whether the locked state.

Simulation spike service, where you can configure the jedis thread pool, distributed lock passed during initialization, for its use.

Copy the code
public class Service {

private static JedisPool pool = null;

private DistributedLock lock = new DistributedLock(pool);

int n = 500;

static {
    JedisPoolConfig config = new JedisPoolConfig();
    // 设置最大连接数
    config.setMaxTotal(200);
    // 设置最大空闲数
    config.setMaxIdle(8);
    // 设置最大等待时间
    config.setMaxWaitMillis(1000 * 100);
    // 在borrow一个jedis实例时,是否需要验证,若为true,则所有jedis实例均是可用的
    config.setTestOnBorrow(true);
    pool = new JedisPool(config, "127.0.0.1", 6379, 3000);
}

public void seckill() {
    // 返回锁的value值,供释放锁时候进行判断
    String identifier = lock.lockWithTimeout("resource", 5000, 1000);
    System.out.println(Thread.currentThread().getName() + "获得了锁");
    System.out.println(--n);
    lock.releaseLock("resource", identifier);
}

}
Copy the code

Analog threads spike services;

Copy the code
public in ThreadA the extends the Thread class {
Private-Service-Service;

public ThreadA(Service service) {
    this.service = service;
}

@Override
public void run() {
    service.seckill();
}

}

the Test class {public
public static void main (String [] args) {
-Service-Service-Service new new = ();
for (int I = 0; I <50; I ++) {
in ThreadA ThreadA in ThreadA new new = (-Service);
threadA.start ( );
}
}
}
copy the code
results below, the result is ordered:

Write pictures described here

If the comment out part of a lock:

Copy the code
public void seckill () {
// return the lock value value for determining when to release a lock
// String Indentifier = lock.lockWithTimeout ( "Resource", 5000, 1000);
System.out.println (Thread.currentThread ( ) .getName () + "obtained lock");
System.out.println (-n);
//lock.releaseLock("resource ", Indentifier);
}
copy the code
can be seen from the results, there are some asynchronous of:

Write pictures described here

Third, based on the realization Zookeeper distributed lock

ZooKeeper is provide a consistent service for distributed applications open source components within it is a hierarchical file system directory tree structure, the provisions of the same directory can only have a unique file name. ZooKeeper step is based on the implementation of distributed locking:

(1) Create a directory mylock;
(2) A thread want to get a lock on creating a temporary order of nodes in the mylock directory;
(3) Gets all the child nodes under mylock directory, and then get smaller than their siblings, if there is no , then the current minimum thread sequence number, to acquire the lock;
(4) thread B acquires all nodes, it is determined that they are not the lowest node, provided listening times smaller than its own node;
(5) the thread a processed, delete its own node, the thread B listens to change events, determine whether it is the smallest node, if it is then get the lock.

It is recommended that an Apache open source library Curator, it is a ZooKeeper client, InterProcessMutex Curator offer is to achieve a distributed lock, acquire the method used to obtain the lock, release method for releasing the lock.

Advantages: high availability is provided, reentrant, blocking locks characteristics, failure solve the deadlock problem.

Cons: Because of the frequent need to create and delete nodes, as Redis way on performance.

Fourth, contrast

Distributed database lock to achieve
disadvantages:

1.db operating performance is poor, and there is the risk of lock table
2. After a non-blocking operation fails, the need to poll, occupancy cpu resources;
3. a long time do not commit or long polling, the connection may consume more resources

Redis (cache) Distributed Lock achieve
disadvantages:

1. Delete failed lock expiration poor control
2 non-blocking, the operation fails, the need to poll, occupancy cpu resources;

ZK Distributed Lock achieve
Disadvantages: Performance is better redis achieve, mainly due to a write operation (to obtain release lock) need to be performed on the Leader, and then synchronized to the follower.

In short: ZooKeeper better performance and reliability.

From the perspective of ease appreciated (from low to high) Database> Cache> the Zookeeper

From the implementation point of view the complexity (low to high) Zookeeper> = Cache> Database

From a performance point (Low) caches> Zookeeper> = Database

From the perspective of reliability (high to low) the Zookeeper> Cache> Database

Published 33 original articles · won praise 0 · Views 846

Guess you like

Origin blog.csdn.net/ninth_spring/article/details/104806617