Distributed - Distributed Lock

Foreword

I suddenly felt really want to secure a long life can be called imagination, think of prosperity in history, but mostly three or four years, how can we ensure big time in their lives that must be among the three or four years (but really hope that the future is getting better, the general trend is better, individuals must also be good). A steady job, love themselves, their loved ones feel a little luxury. I know these are found in species of life slowly will probably blink of an eye will look back on the past, and found that the selection of these things are not free, but is time-driven. With age, more and more like the feel of small, things of the past and more and more a foregone conclusion, and the future of the less choices, but also the less optional.
Well, Closer to home, it would have been the last to finish the CAP, felt checked a lot of information, write pretty good. Now a look back, what is written in it! Or the brain stupid, remember that one of those slow, slow to understand, forget the kind of people quickly. So think of this not say how how Well, at least than the last good. Yes, on one so I have time to replenish in detail, first set up a flag to say.

Idempotence

definition

HTTP / 1.1 is defined to be idempotent of: a primary and multiple requests for a resource of the resource itself should have the same result (except for the network timeout issues). Represented by a function word is f .... f (f (x) ) = f (x).

purpose

1. To prevent catastrophic consequences request retry operation brings important (e.g., transaction, transfer) of.

Idempotent range

request

1. Read request - born idempotent
2. Write request - non-idempotent need to be controlled.

Database level

1.INSERT-- non-idempotent, need to be controlled by the content.
By controlling 2.UPDATE-- idempotent WHERE condition, to minimize a relative value operation. The UPDATE table1 SET column1 = column1 + 1 WHERE column2 = 2;
The results of each execution will change, this is not idempotent. The UPDATE table1 SET column1 = 1 WHERE column2 = 2; no matter how many times the successful implementation of the state are the same, and therefore power and other operations.
Also by controlling 3.DELETE-- WHERE condition, to minimize a relative value operation. If
DELETE table1 WHERE column1 <now () ; should read DELETE table1 WHERE column1 < "2019-10-01" ; better.

Operational level

1. In the case where a plurality of redundant deployment services, presence of concurrent requests consumption needs to be requested by the parallel to serial conversion.

The guarantee of power and other strategies

Idempotency ensure essence is to do serial processing resources, such serialization is multi-faceted.
Queries Needless to say, the new request needs to do to control important properties of anti-heavy process, the update request by optimistic locking can be well controlled.
The distributed system requests serialized by the parallel processing of a distributed lock into.

Lock attributes

1. reentrant / non-reentrant

Reentrant: same thread layer after obtaining the lock function, the function comprising the inner code is not affected to acquire the lock, the lock is not necessary to apply again, it can be directly called.
Non-reentrant: ibid contrary, we must get the same inside and outside a thread to lock before the execution. It can easily lead to deadlock.
They are synchronized and reentrant lock Reentrantlock

2. fair / unfair

Fair: first come first served, requesting the lock queue thread composed of consumer lock.
Non-Equity: to lock the first request, the request to the implementation, not to get thrown into the tail of the queue waiting to acquire the lock.
synchronized unfair
Reentrantlock optional

3. Read / Write

Read lock: people can read, but not write, when read, the read lock.
Write lock: write when you can not read, write and only one person, the write lock.

4. Sharing / Exclusive

Exclusive lock: Only one thread holds the lock, mutex ReentrantLock is exclusively implemented. Exclusive is a pessimistic locking strategy.
Shared locks: The locks can be held by multiple threads, such as ReadWriteLock. Relaxed locking strategy that allows multiple threads simultaneously read access to shared resources.
note: AQS (AbstractQueuedSynchronized) also provide exclusive mode (exclusive) and a share mode (Shared) two different synchronization logic.

5. interruptible / non-interruptible

Interruptible: the operation of the lock can be interrupted. ReentrantLock be interrupted.
Can not be interrupted: contrast to the above. synchronized lock that can not be interrupted.

Distributed Lock

To ensure mutually exclusive access under a multi-process environment of shared resources in a particular non-identical system. Essence is serialized by the resource request, to avoid repeated. However idempotent request does not solve the problem still needs to be controlled in idempotent business code. We need to create a shared storage server in an external system, used to store lock information.

Design goals

Security Properties

1. mutually exclusive . Regardless of any time there can be only one client holds the same lock. That lock is the presence of strong global consistency.
2. deadlock , with lock failure mechanisms. First, to provide system lock service itself highly available, robust system. Multi-service node, any node crash or network partition does not affect access to the lock; the second is the client for automatic renewal and automatic release lock.
3. symmetry , for any lock which must be the same locking and unlocking a client.

Efficiency property

1. The fault-tolerant , high availability, high performance. Service itself highly available, robust system. Multi-service node, any node crash or network partition does not affect access to the lock.
2. reentrant , which can effectively reduce the occurrence of a deadlock situation.
3. Multi-choice, you can choose to try to time acquire a lock.
4. The client calls simple. Lock code requires highly abstract, minimalist service access.

Design ideas

1. control of shared resources. Key identifier can be used as a resource lock, so that resources can be controlled to a unique process.
The only control 2 locks. Get locked in the process to obtain a single unique identifier (value), as a condition when the lock is released, to avoid the lock is released by another process. Analyzing and also need to ensure that atomic del operation, prevent accidental deletion behavior. Usually lua scripts.
3. Avoid process is not executing the lock is released, the resources are accessed in parallel. Timely renewal process, avoiding unfinished business lock is released.
4. prevent deadlock. Regular release the lock, set the release time.

Boundary conditions

1. Provide lock registered service itself, stability and consistency.
2. Lock failed to renew as expected. Such as heartbeat renewal is not successful, the service starts GC, GC during the service suspended time exceeds the effective time locks and so on.
3. Business suspended animation, TTL continues.

Design Points

1. lock registration. Ensure that the lock register is atomic, i.e., determines whether there is a lock register and are serialized.
2. Renewal of the lock. How to lock lease renewal in the case of the invasion of the smallest business code. CAS atomicity.
3. release the lock. User lock only release their locks held.

Different implementations

redis achieve

principle
1. Single Instance implementation principle

Thread redis unique serial processing, i.e., a system itself is linear idempotent. But this will have a single point of failure. If redis use master-slave mode, because redis replication is asynchronous, so there will be:

1.客户端A在master节点获取到锁。
2.master节点在将信息写入slave之前宕机。
3.slave被提升为master。
4.客户端B获取到与A同一资源的锁。此时该资源进入多进程并行消费状态。有悖互斥原则。

Of course, the probability of this happening is very low, if the resources are not sensitive to this situation, usually acceptable.
Or using a single instance redis implementations, i.e. in this case the process required higher tolerance issues job single point of failure.

2.RedLock algorithm

This implementation is essentially to achieve a consensus protocol in redis clusters to achieve key only. But it requires that all nodes are redis master node, and completely independent of each other, master-slave replication or other cluster coordination mechanism does not exist.

如果要获取锁,客户端进行的操作需要有:

1.客户端获取当前时间(毫秒)
2.使用相同的key和不同的value去顺序请求存在的N个master节点。(
该步骤需要客户端设置一个比自动释放时间小的多请求超时时间。比如说,当自动释放时间为10秒时,设置超时时间为5~50毫秒。这是用来防止在宕掉的节点上消耗过多的时间。一个节点不可用,应立即进行下个节点的请求。
)
3.客户端计算获取锁消耗的时间(step2消耗的时间——当前时间-step1获取到的时间)。当且仅当在N/2+1个节点获取到锁,获取锁的消耗时间小于锁的失效时间,才认为锁的获取是成功的。
4.若锁被获得,其有效时间可以被视为——初始的过期时间-获取锁的消耗时间。
5.如果客户端获取锁失败,无论什么原因(其实就两种原因,一是成功节点小于N/2+1,二是超时),都将在所有节点进行锁的释放(即便是哪些根本没有获取到锁的节点);

According to the algorithm described above, at, redis cluster master node requires at least three. And the realization is also more complicated. Locking overhead is too large. Requirements are also higher for redis operational problems. Overall implementation costs are too high. Fortunately, however, it has already been achieved --Redisson

Single Instance implementation

Data are generally seen before to register the lock with setNX this command, but the command can not set up automatic expiration time expired can only be controlled by setting the timestamp value, in fact, not very good. Now redis official also recommend using the SET command.

SET resource-name anystring NX EX max-lock-time

自2.6.12版本SET命令支持多种操作:
    EX seconds -- Set the specified expire time, in seconds.
    PX milliseconds -- Set the specified expire time, in milliseconds.
    NX -- Only set the key if it does not already exist.
    XX -- Only set the key if it already exist.

When the lock is released, we can use lua scripting language used to ensure the release of atomic conducted lock

    if redis.call("get",KEYS[1]) == ARGV[1]
    then
        return redis.call("del",KEYS[1])
    else
        return 0
    end   

Specific code implements
used here is lettuce

1. Lock implementation
 /** 
 *  如果锁处于空闲状态,当前线程获取到锁 
 *  如果锁已经被其它线程持有,禁用当前线程,直到当前线程获取到锁 
 */
 @Override
 public void lock() {    
 //选定同步方式    
    while (true){        
        if (tryLock())return;        
        this.sleepByMillisecond(renewalTime >> 1);    
    }
 }
 /** 
 *  尝试获取锁 
 *  如果锁可用返回true 否则返回 false 
 * @return 
 */
 @Override
 public boolean tryLock() {    
    //使用ThreadLocal保存当前锁对象 作为可重入锁的控制
    if (threadLocal.get() != null) return true;
    String set = statefulRedisConnection.sync().set(lockKey, lockValue, new SetArgs().nx().ex(lockTime));   
    if (set != null && "OK".equals(set)){        
        System.out.println("线程id:"+Thread.currentThread().getId() + "加锁成功!时间:"+ LocalTime.now());        
        isOpenExpirationRenewal = true; 
        threadLocal.set(this);
        this.scheduleExpirationRenewal();        
        return true;    
    }    
    return false;
 }
 /** 
 *  尝试获取锁 
 *  在指定时间内可以获取到  返回true 否则返回false 
 * @param time 
 * @param unit 
 * @return 
 * @throws InterruptedException 
 */
 @Override
 public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {   
     //获取进入时间    
     LocalTime now = LocalTime.now();    
     while (now.isBefore(now.plus(time, (TemporalUnit) unit))){       
        if (tryLock())return true;    
     }    
     return false;
 }
2. The lock of renewal

There may be two problems, one is the main thread hang, to renew the thread can not be closed; the second is the failure to renew itself. Currently abnormal feeling is provided to capture a first lock code, where the best way, and finally the finally block perform the unlock. The second approach is the need to make log analysis code to solve a specific problem. But you realize if there is a better way to welcome preaching FAQ.


@Override
protected void scheduleExpirationRenewal() {    
    Thread thread = new Thread(new ExpirationRenewal());    
    thread.start();
}
private class ExpirationRenewal implements Runnable{    
    @Override    
    public void run() {        
        while (isOpenExpirationRenewal){            
            try {                
                Thread.sleep(renewalTime);           
            } catch (InterruptedException e) {               
                e.printStackTrace();           
            }            
            String expirFromLua = "if redis.call('get', KEYS[1]) == ARGV[1]"                    
                    + " then "                    
                    + "return redis.call('expire',KEYS[1],ARGV[2])"                    
                    + " else "                   
                    + "return 0"                   
                    + " end";            
            Object eval = statefulRedisConnection.sync().eval(expirFromLua, 
                ScriptOutputType.INTEGER, new String[]{lockKey}, lockValue, lockTime.toString());            
            System.out.println("续租获取的结果值:" + eval + ((long)eval==1?" 续租成功":" 续租失败"));        
        }   
    }
}
3. Lock release
@Override
public void unlock() {    
//关闭续租    
isOpenExpirationRenewal = false;    
    //删除锁    
    String delFromLua = "if redis.call(\"get\", KEYS[1]) == ARGV[1]"    
        + " then "    
        + "return redis.call(\"del\",KEYS[1])"    
        + " else "    
        + "return 0"    
        + " end";    
    Long eval = statefulRedisConnection.sync().eval(delFromLua, ScriptOutputType.INTEGER, new String[]{lockKey}, lockValue);    
    if (eval == 1){       
        System.out.println("锁释放成功");    
    }else {       
        //最好做好日志记录
        System.out.println("锁 早已经释放");    
    }
}
4. Summary

The above only achieved reentrant, need to consider how to achieve a fair and non-equity switch, and read-write locks. The key to the lock is to maintain a fair cross-process lock request queue, it can only be achieved by redis itself.

2.RedLock algorithm
1.Redisson Profile

Lazy, move directly to the official introduction

Based on high-performance async and lock-free Java Redis client and Netty framework.

Redisson function is very powerful, it is recommended have time to go and see (oh documents in Chinese).

Algorithm to achieve 2.RedLock

Redissond red lock (RedissonRedLock) RedLock object implements the algorithm described locking. Use the following

RLock lock1 = redissonInstance1.getLock("lock1");
RLock lock2 = redissonInstance2.getLock("lock2");
RLock lock3 = redissonInstance3.getLock("lock3");

RedissonRedLock lock = new RedissonRedLock(lock1, lock2, lock3);
// 同时加锁:lock1 lock2 lock3// 红锁在大部分节点上加锁成功就算成功。
lock.lock();
...
lock.unlock();

We need to create multiple redissonInstance1 RLock and create multiple objects, use them to make up a distributed lock. Species in which the selected data structure is redis hash, is convenient to achieve fairness lock.

Use is quite troublesome.

zookeeper achieve

principle

zookeeper is a distributed coordination services to achieve coherence protocol. Client-side end and is divided into Sever. Server-side application which is distributed. zab coherence protocol, the interim order of the nodes znode, watchs mechanism is the key to achieve zookeeper distributed lock.

1.zookeeper data model

hierarchal name space (hierarchical name space), can be seen as a distributed file system. Having a tree structure, each node a "/" separator. Most unicode character can be used as a node name.
zookeeper tree is called a node znode. znode node maintains a data structure of a stat in which to save the data changes, acl (Access Control List-- access control lists, each node exists, the list restricting who can do what, equivalent to a list of permissions node, are: CREATE, READ, WRITE, DELETE, ADMIN) changing the version number and corresponding time stamp.
znode write is atomic.

znode nodes can be divided into:

  • Persistent Nodes node lasting
    even after the creation of this particular znode client disconnects, lasting node still exists. By default, unless otherwise indicated, all znode are persistent.
  • Temporary node Ephemeral Nodes
    temporary node is accompanied by a session the client and server created when a session ends, it corresponds znode will be deleted. Therefore, the temporary node is unable to create a child node. Interim leader node plays an important role in the election.
  • Sequence Nodes node sequence
    order of the nodes may be permanent or temporary. Znode When a new node is created as a sequence, ZooKeeper by 10-bit serial number appended to the original name set znode path. The sequence number is a monotonically increasing number of columns. For example, if the path to create a / mynode znode of a sequential node, then the path will change ZooKeeper / mynode0000000001, and the next sequence number to 0,000,000,002. When the increment over 2,147,483,647 - When (2 ^ 311), the counter will overflow (leading to the name "-2147483648"). In order node locking and synchronization play an important role
  • Nodes Container 3.5.3 version adds
    the node type is set to the special conditions make such leader, lock and so on. When the last child node within the container is removed, the container will be a candidate server you want to remove (delete personal feeling is similar to a regular in redis) sometime in the future. Therefore, it is possible to create Container node when the child node throws KeeperException.NoNodeException, so when the child node needs to determine whether the exception is thrown, and re-create the container node after thrown.
  • Nodes TTL 3.5.3 release adds
    the class node node can only be lasting. When you create a node lasting or permanent order of nodes, you can select the TTL setting node. If the TTL time of the node changes did not occur, and no child nodes, then the node server will be removed at some point in the future. TTL node must be enabled via system properties, because they are disabled by default.
2.Watchs

The client can be set to monitor a Watchs znode node information to obtain change information nodes.

Implementation steps

The key lock is usually implemented temporary order of nodes and Watchs mechanisms. The creation of a queue to acquire the lock by temporary order of nodes, before a monitor data consumption by watchs mechanism to determine whether they have been spending.

1.创建持久节点lock作为锁的父节点。
2.请求锁的客户端A在lock节点下创建临时顺序节点lock000000N;
3.获取lock下的节点列表,获取编号比客户端A次小的节点,若不存在,表示当前线程序号最小,获取到锁。
4.若编号比客户端A次小的节点存在,设置Watchs监听次小节点。次小节点删除,判断自己是不是最小的节点,是则获取到锁。

apache open source library Curator provides a corresponding distributed lock implementation.
However, there is a time to achieve myself, than using conventional means above, it can also be used Container TTL node or nodes.

to sum up

zookeeper implementation compared to redis terms, without regard to consistency locks, eliminating the need for a big trouble. So I have time to look Curator source.

etcd achieve

What is etcd

A distributed key-value pair (KV) storage services. Which achieves consensus algorithm Raft (Oh forgot, this feeling consensus algorithm written or not detailed enough, so I have time to look carefully), it must be highly available 2N + 1 Ge. Mainly used to store data changes occur infrequently, and provides monitoring queries. Can use http / https / grpc call server api, grpc way comes api, do not care about a contract extension when using. Grpc v3 version of which is available to add. v3 version still supports the rest way http / https calls, but note that the version is not compatible with v2 and v3, most of the command is modified, the data do not exchange, such as the use of data created with version v2, v3 are not visible. And v3 version support is not good for the rest of the way calls.

principle
Data Model

etcd Key-Value is the basic structure.

  • Logical View:
    logical view of the storage area is a flat binary (flat binary to tell the truth I do not understand this word, you need to look up information, I understand that the hierarchical structure of a data, a tree-like structure there is to know hope. wing, Baoquan ) key space. Key space to maintain multiple Revision. Every transaction will create a new Revision on Key space. Key is the Key from creation to destruction of a life cycle (generation). Each Key likely to have a more lifecycle (creation means that holds the key repeatedly modify the destruction of detailed records). If the Key does not exist in the current modification, the current version of Key's (version) from the beginning. Delete Key is generated a flag that contains the current is turned off key generation information (by resetting the version is 0),. Each time you modify key will increment the version. In a key life cycle version is monotonically increasing. Once compaction occurs, any key life cycle record before compaction revision of (ended generation) will be deleted, and delete the value set before compaction revision (except the latest).

  • Physical view
    KV etcd data in the form of book B + persisted to disk types, not to update the original data to update its data structure, but generating a data structure after update. So the read and write performance can not be compared with redis like.

Basis etcd implementation of distributed lock
  • Lease (A short-lived renewable contract that deletes keys associated with it on its expiry) mechanism: the lease mechanism (TTL, Time To Live). Renewal issues.
  • Revision (A 64-bit cluster-wide counter that is incremented each time the keyspace is modified) mechanism: each provided with a Key Revision, each time a new transaction is created in Revision key space, which increases monotonically Revision The initial value of zero. Revision may know by size sequential write operations. When implementing a distributed lock, the lock can be acquired in accordance with the order of the size of Revision equity and locks.
  • Prefix mechanism: the prefix mechanism, also known as directory mechanism. key can be created in the form of a directory, such as key1 = "/ mylock / 00001", key2 = "/ mylock / 00002". By the prefix / mylock range queries, KV get a list, by order of acquisition Revision of the size of the control locks, lock fairness.
  • Watch mechanism: sensing mechanism, Watch can monitor a single key, but also supports a range monitoring.
Implementation steps

Etcd contrast zookeeper and we will find the same mechanism as a whole. This is achieved so that substantially the same.
It comprises the following steps:

1.创建对应资源的分布式锁的全局key的前缀,如/mylock,则第一个请求的客户端创建的key则为/mylock/uuid001,第二个为/mylock/uuid002。
2.为该对应资源创建租约Lease为特定合适时间。
3.客户端put自己的key,如/mylock/uuid001。这里的value不为空即可。获取自己put后的revision号,并记录。
4.获取key前缀下的所有键值对信息,并根据revision号大小排序,小的在前。
5.对比put的revision值是否是最小的,是的话获取锁,并开启续租线程。不是,则获取前一个加锁操作索引,并创建一个Watcher,用于监听前一一个key(将处于阻塞状态)。

The latest version etcd has provided implementation of distributed lock. Do not care about lock release and renew automatically released when calling unlock. Key lock, speak the same basic implementation principle above.
etcd the java client has etcd4j, jetcd and so on.

to sum up

etcd implementation is relatively simple, and its own distributed lock has been achieved, with only a lock command can easily acquire the lock. But etcd does not seem very common in other ecological applications in java, if only used for distributed lock acquired, then in fact not very cost-effective.

Conclusion

Finally finished, in fact, is the crashing of the middle of the zookeeper and no detailed to write, did not realize that the fair redis lock. Now these things provide a more comprehensive, and some do not have to write their own, but the principle must understand. In fact, these are relatively - renewal - to achieve specific release. Still have the opportunity to look at the source code, develop your own ideas, I hope the next time can Redisson, Curator, Jetcd implementation source code to see the locks. Alas, upstanding flag has been cool, has also been dragged cool, do not know what more one can ...
sleep it, sleep it ...
Distributed - Distributed Lock


参考资料:
redis:https://redis.io/topics/distlock
zookeeper:http://zookeeper.apache.org/
etcd:https://etcd.io/

Idempotence: HTTPS: //www.cnblogs.com/javalyy/p/8882144.html
ZooKeeper Distributed Lock implementation: HTTPS: //www.cnblogs.com/javalyy/p/8882144.html
ETCD lock achieved: http : //blogspring.cn/view/120
jetcd: HTTPS: //github.com/etcd-io/jetcd

Guess you like

Origin www.cnblogs.com/chengbaiyi/p/11615457.html