Distributed - technology zone -Redis Distributed Lock achieve - the first step

To undertake front of a distributed lock principle introduced Redis

https://www.cnblogs.com/liboware/p/11921759.html

We re-define and improve the planning and implementation for conduct in the next chapter.

About Distributed Lock

  Long has a lock mechanism to lock talked about concurrent programming concurrent programming before: synchronized and lock. In the system in a single process, when there are a plurality of threads can be changed while a variable, the variable needs to be done synchronous or code block, so that this variable can be modified at the time of eliminating linear concurrent modification variable. The essence synchronization is achieved through the locks. In order to achieve multiple threads at the same time a code block only one thread can perform, you need to make a mark somewhere, this flag must each thread can see, when there is no mark may set the mark , subsequent threads have been found to have marked the thread is waiting for the end mark synchronized block unmarked and then to try to set the mark.

  Distributed environment, data consistency problem has been a more important topic, but unlike the case of a single process. The biggest difference in distributed and multi-process single case but that it is not multi-threaded. Because multiple threads can be shared heap memory, so you can simply take the mark memory as the storage location. And between processes may not even on the same physical machine, so we need to be able to see all processes in a flag storage place.

Common lock programs are as follows:

  • Based on implementation of distributed database lock
  • Based cache to achieve distributed lock, such as redis
  • Based achieve Zookeeper distributed lock

First, based on the database

  Lock database implementation, there are two ways, one is based on a database table, and the other is based on an exclusive lock on the database.

Based on the additions and deletions to the database table  

  Based on a database table additions and deletions is the easiest way to first create a lock of the main table contains the following fields: the method name, time stamp, and other fields.

  A method for specific use, when it is desired to lock a method, an insert into the table related records.

  2. It should be noted here, the method name is the only constraint, if there are multiple requests simultaneously submitted to the database, the database will ensure that only one operation can be successful, then we can assume that thread successfully won the method of operation lock, can perform the method body content.

  3. finished, you need to delete the record.

  For the above-described embodiment can be optimized, such as the application of two-way synchronization between the master database, data. Once the hang up quickly switch to the backup repository;

  Do a regular job, regular intervals to clean up the data in the database timeout again; use a while loop until the insert successful return success, although this is not recommended;

  You can also record machine host information and information about the current thread to acquire a lock, then the next time you acquire the lock when the first query the database, if the current host machine information and thread information in the database can be found, then directly assigned to him to lock They achieved reentrant lock.

Based database exclusive lock

We can also be achieved by a distributed lock exclusive lock on the database. Based on the MySql InnoDB engine, the lock operation may be implemented using the following methods:

Lock void public () {
  connection.setAutoCommit (to false)
  int COUNT = 0;
  the while (COUNT <. 4) {
  the try {
    SELECT * WHERE lock_name from Lock for Update = XXX;
    IF (the result is not null) {
      // Get the representatives lock
      return;
    }
   } the catch (exception E) {
   }
   // Throws is empty or if a lock is not acquired expressed
   SLEEP (1000);
   COUNT ++;
  }
  the throw new new LockException ();
} 

  Increase for update queries later, the database will increase to the database table row during a query lock. When a record is added exclusive lock, other threads can no longer record on the line to increase exclusive lock. The other did not get the lock will be blocked on the select statement, there are two possible outcomes, access to the lock before the timeout, the timeout before the lock is not acquired by.

  Exclusive locks can be obtained Distributed Lock thread, when the lock is acquired, the method can execute business logic, after the execution of the method, releases the lock connection.commit ().

  The main problem is not high performance and sql timeout exception.

Based on the advantages and disadvantages of database locks

  The above two methods are dependent on a database table, one is by the presence of the recording table to determine whether there is currently latched, the other is achieved by a distributed lock exclusive lock database.

  • The advantage is direct via the database, simple and easy to understand.
  • The disadvantage is that the database operation requires a certain overhead, performance issues to consider.

Second, based on Zookeeper

  Distributed Lock zookeeper temporary order node can be achieved. Each client of a locking method, the specified directory corresponding to the node on zookeeper method generates a unique node instantaneously ordered. Determining whether to acquire the lock is very simple, requires only a minimum determination number of ordered nodes. When the lock is released, simply delete this node can be instantaneous. At the same time, it avoids service downtime caused by lock can not be released, and the deadlock created.

  Provided there are third-party libraries curator, the specific use of readers to take a look. InterProcessMutex Curator offer is to achieve a distributed lock. acquire methods to acquire the lock, release method to release the lock. In addition, the lock is released, blocking locks, reentrant lock and other issues can have an effective solution.

  Achieve lower blocking locks speaking, the client can create ZK in the order of nodes, and binding listener on the node, the node once there is a change, Zookeeper will notify the client, the client can check the nodes create yourself is not all current the smallest node number, if it is acquired lock, can execute business logic.

  Finally, Zookeeper distributed lock realize there is actually a disadvantage that the performance may not be as high as caching service.

  • Because every time during the creation and release locks in, to be dynamically created and destroyed transient nodes to achieve lock.
  • ZK create and delete nodes can only be performed by Leader server, then the data is not the same on all machines Follower.
  • Concurrency issues, there may be network jitter, session client and cluster ZK connection is broken, zk cluster that the client hung up, it will remove the temporary node, this time other clients can get to a distributed lock.

Third, based cache

  With respect to program implementation of distributed database lock is based, in terms of performance cache to achieve performance will be a little better, much faster access speed. And many can be clustered cache is deployed, single-point problem can be solved. There are several cache-based locks, such as memcached, redis, mainly on the following paper redis distributed implementation.

redis Based Distributed Lock

SETNX

  Redis use of SETNX achieve distributed lock, Redis multiple processes execute the following command:

SETNX lock.id <current Unix time + lock timeout + 1>

SETNX is set to the value of the key value, if and only if the key does not exist. If a given key already exists, SETNX do nothing.

Return 1, indicating that the process to acquire a lock, the value of the key lock.id SETNX set the lock timeout time, the current time + time plus active lock.
Return 0, indicating that the lock has been obtained by other processes, the process can not enter the critical region. The process can continue to try SETNX operate in a loop to get the lock.

Deadlock problem

  SETNX achieve distributed lock, there may be a deadlock situation. Compared with the lock in stand-alone mode, distributed environments not only need to ensure that the process is visible, we also need to consider your network between a process and lock. After a thread acquired the lock, disconnect from the Redis, the lock is not released in time, the competition will lock the other threads hung, produce a deadlock situation.

  When using SETNX to acquire a lock, we set the value of the key to effective time lock.id lock after thread gets the lock, other threads will continue testing the lock has timed out, if the timeout, waiting threads will also have access to lock. However, lock timeout, we can not simply use the DEL command to delete a key lock.id to release the lock.

Consider the following scenario:

  A lock has been first obtained lock.id, and A broken line. B, C are waiting for the competition in the lock;
  B, C lock.id the read value, and comparing the current time to determine whether the key lock.id timeout discovery timeout;
  B DEL lock.id execution command, and executes SETNX lock.id command, and returns 1, B to acquire the lock;
  C immediately detected since each lock has timed out, the command execution DEL lock.id, just set the key deletion lock.id B, SETNX lock.id execute command, and returns 1, i.e., C acquire the lock. `

  The above steps are obviously a problem, resulting in B, C at the same time a lock is acquired. Upon detection of the lock timeout, the thread can not simply delete key DEL perform direct operations to obtain the lock.
  Improvements to the above steps, the problem is in operation above the delete key, then after acquiring the lock should be how to improve it?


  First look at the redis GETSET this operation, GETSET key value, the value of a given key is set to value, and returns the key of the old value (old value). With this operation instruction, we can improve what steps described above.

  A lock has been first obtained lock.id, and A broken line. B, C are waiting for the competition in the lock;
  B, C lock.id the read value, and comparing the current time to determine whether the key lock.id timeout discovery timeout;
  B detects that the lock has timed out, i.e., the current time lock.id key value is greater than a, B will be performed;
  getset lock.id <timestamp + the Unix current lock timeout. 1 +> time-stamping, by comparing the value of the old key lock.id is less than the current time, it is determined whether the process has been locked ; B
  returns the found value is smaller than the current time GETSET, DEL lock.id command is executed, and executes SETNX lock.id command, and returns 1, B to acquire the lock;
  C GETSET execution time is greater than the current time is obtained, it continues to wait.
  Before the thread releases the lock that the implementation DEL lock.id, you need to first determine whether the lock has timed out. If the lock has timed out, then the lock may have been obtained by other threads, then executed directly DEL lock.id operation will lead to lock the other threads have been obtained released.

 

public boolean lock(long acquireTimeout, TimeUnit timeUnit) throws InterruptedException {
  acquireTimeout = timeUnit.toMillis(acquireTimeout);
  long acquireTime = acquireTimeout + System.currentTimeMillis();
  //使用J.U.C的ReentrantLock
  threadLock.tryLock(acquireTimeout, timeUnit);
  try {
    //循环尝试
    while (true) {
    //调用tryLock
    boolean hasLock = tryLock();
    if (hasLock) {
      //获取锁成功
      return true;
    } else if (acquireTime < System.currentTimeMillis()) {
      break;
    }
    Thread.sleep(sleepTime);
  }
  } finally {
    if (threadLock.isHeldByCurrentThread()) {
      threadLock.unlock ();
    }
  }
  return to false;
}
public Boolean tryLock () {
  Long currentTime = System.currentTimeMillis ();
  String Expires = String.valueOf (currentTime + timeout);
  // set mutex
  if (redisHelper.setNx (the mutex, Expires)> 0) {
  // acquiring the lock, set the timeout
    setLockStatus (Expires);
    return to true;
  } the else {
    String currentLockTime = redisUtil.get (the mutex);
    // check the lock timeout
    if (Objects.nonNull ( currentLockTime) && Long.parseLong (currentLockTime) <currentTime) {
      // Get the old time and set the mutex lock
      String oldLockTime = redisHelper.getSet (the mutex, Expires);
      // old value with the current time
      if (Objects.nonNull (oldLockTime) && Objects.equals (oldLockTime, currentLockTime)) { // can be seen later unlocked whichever
        // acquire the lock, set the timeout
        setLockStatus (Expires);
        return to true;
      }
    }
    return to false ;
  }
}

  lock tryLock method call, the timeout parameter to the unit acquired a thread within the timeout period, acquiring the lock operation will spin there until the spin lock holder releases the lock.

  tryLock method, the main logic is as follows:

  setnx (lockkey, the current time + timeout expires), if it returns 1, the lock is acquired successfully; returns 0 if the lock is not acquired

  get (lockkey) Gets the value oldExpireTime, and this value and the current value of the system time, and if less than the current system time, the lock is considered to have timed out, may allow other reacquisition request.

  Calculating newExpireTime = current time + time-out expires, then getset (lockkey, newExpireTime) returns the determining whether the current value currentExpireTime oldExpireTime lockkey currentExpireTime with equal if they are equal, indicating that the current setting getset successfully, it acquires the lock. If not equal, indicating that the lock has been requested else get away, then the current request failure can return directly, or continue to try again.

Release the lock

UNLOCK boolean public () {
  // only the thread holding the lock to unlock
  IF (lockHolder == Thread.currentThread ()) {
  // determine whether the lock timeout, no timeout will only delete the mutex
    if (lockExpiresTime> System.currentTimeMillis ()) {
      redisHelper.del (the mutex);
      logger.info ( "delete mutex [{}]", mutex);
    }
    lockHolder = null;
    logger.info ( "release [{}] lock success", mutex) ;
    return to true;
  } {the else
    the throw new new IllegalMonitorStateException ( "not acquired lock thread can not perform the unlock operation");
  }
}

 

to sum up

  This paper explains the realization redis Distributed Lock based in a distributed environment, data consistency problem has been a more important topic, and synchronized lock and lock in a distributed environment has lost its effect. Common lock the program has achieved a distributed database locks, lock-based implementation of distributed cache, based on the Zookeeper distributed lock to achieve a brief introduction to achieve the characteristics of each lock on; then, the paper explored a bit implementation redis lock; finally , in this paper, based on distributed lock redis Java implementation, the reader can verify themselves.

reference

Distributed Lock little understanding of
distributed lock 1 Java common technical program
distributed lock of several implementations
http://blueskykong.com/2018/01/06/redislock/

 

 

Guess you like

Origin www.cnblogs.com/liboware/p/11944948.html