Advances in microprocessor technology have made it possible to buy, for a few hundred dollars, a CPU chip that executes more instructions per second than the processors of the largest mainframe computers of the 1980s. If you’re willing to pay twice as much, you’ll get the same CPU running at a higher clock rate. Therefore, the most cost-effective approach is usually to have a large number of cheap cpus clustered together in one system. So, the main reason to favor distributed systems is that they can potentially get a much better price performance than a single, large centralized system. In fact, distributed systems achieve similar performance at a lower cost.

With the rise of the Internet, more and more people use Internet products. Generally, Internet systems are distributed. Distributed deployment can indeed improve performance and efficiency. While improving efficiency, we also need to pay attention to ensuring data consistency in a distributed environment.

V Overview of distributed locks

In stand-alone era, although there is no distributed lock, but will face resources mutually exclusive, but in the case of a single machine, if there are multiple threads to access a Shared resource at the same time, we can use thread locking mechanism, namely when a thread access to this resource, you need to lock the resources, after when using the resources, to unlock, The other threads can then take over. In JAVA, for example, there are even apis for handling locking mechanisms (Synchronize /Lock, etc.).

However, in the era of distributed systems, this locking mechanism between threads does not work, the system may have multiple and deployed on different machines, these resources are no longer shared between threads, but are shared between processes. Therefore, in order to solve this problem, “distributed lock” has made a strong appearance.

Distributed locking is a way to control synchronous access to shared resources between distributed systems. In distributed systems, they often need to coordinate their actions. If different systems or hosts on the same system share one or a group of resources, the access to these resources must be mutually exclusive to prevent interference and ensure consistency. In this case, distributed locks are required.

In distributed systems, they often need to coordinate their actions. If different systems or hosts on the same system share one or a group of resources, the access to these resources must be mutually exclusive to prevent interference and ensure consistency. In this case, distributed locks are required.

What are the requirements for distributed locks?

  • Exclusivity: Only one client can acquire the lock at a time. No other client can acquire the lock at the same time
  • Avoid deadlocks: This lock must be released (normally or abnormally) after a limited time.
  • High availability: The mechanism for acquiring or releasing locks must be highly available and perform well
  • .

At present, there are three relatively mainstream ones, which are increasingly difficult from top to bottom in terms of the complexity of implementation:

  • Database (MySQL)
  • Redis
  • ZooKeeper

V Based on database implementation

There are two ways to do distributed locking based on a database:

  • Database-based optimistic locking
  • Pessimistic database-based locking

Optimistic locking

Optimistic lock characteristics of the first business operations, not to take the lock. That is, “optimistic” people think that the lock is likely to be successful, so it is good to take the lock at the last step of the business operation that needs to actually update the data.

Optimistic locking is implemented by introducing a version field into the database table. When we read data from the database, we also read the version field. If we want to update the read data and write it back to the database, we need to increment version by 1 and update the new data and the new version to the table. In addition, you must also check whether the current version value in the database is the previous version during the update. If so, the update will be normal. If not, the update fails, indicating that another process updated the data during the process.

Look at pictures and tell stories. Simulate actual combat scenarios.

 

As shown in the picture above, the hero of the story (hereinafter referred to as the hero) wants to withdraw 3,000 yuan from an ATM machine, while the heroine of the story (hereinafter referred to as the heroine) wants to buy something on a certain treasure. It costs 3,000 yuan to buy a bag, and the balance of the account is 5,000 yuan. If the lock is not adopted, when two people withdraw money and buy something at the same time, a total consumption of 6000 May appear, resulting in an abnormal account balance. Therefore, the lock mechanism is needed. When the male and female protagonists or even more minor protagonists consume at the same time, in addition to reading the account balance of 6000, they also need to read the current version number version=1. When the protagonist who consumes first (no matter who consumes first) starts to modify the account balance, version=version+1 will be triggered. The version = 2. Then when other people use the unupdated version(1) to update the account balance, they will find that the version number is not correct, which will lead to the update failure, and they have to read the latest account balance and version number again.

Optimistic locking follows two rules:

  • The lock service must have an increasing version number, version
  • Each time the data is updated, the correct version number must be checked before the new version number is written

Pessimistic locking

Pessimistic locks are characterized by obtaining locks first and then performing service operations. That is, pessimistic locks believe that obtaining locks is highly likely to fail. Therefore, ensure that the locks are successfully obtained before performing service operations.

The common term “one lock, two checks, and three updates” refers to the use of pessimistic locks. In general, pessimistic locking on a database requires support from the database itself, via the usual select… The for Update operation implements pessimistic locking. When the database performs a SELECT for update, it acquires a row lock on the selected row. Therefore, any other concurrent select for update attempts to select the same row will be rejected (waiting for the row lock to be released), thus obtaining the lock effect. Row locks obtained by select for UPDATE are automatically released at the end of the current transaction and therefore must be used in a transaction.

Example:

@param cost * @param cost * @return */ public Boolean consume(consume Long bankId, consume Long bankId) BankAccount product = query("SELECT * FROM bank_account WHERE bank_id=#{bankId} FOR UPDATE", "SELECT * FROM bank_account WHERE bank_id=#{bankId} FOR UPDATE", bankId); if (product.getNumber() > 0) { int updateCnt = update("UPDATE tb_product_stock SET number=#{cost} WHERE product_id=#{productId}", cost, bankId); If (updateCnt > 0){return true; } } return false; }Copy the code

The difference between optimistic and pessimistic locks

The idea of optimistic locking is to add the version field in the table, And add the version judgment in the WHERE statement during update, which is a CAS operation. In the banking consumption scenario, version plays the role of version control (And version=#{version}).

Pessimistic lock is pessimistic because he thinks the operation will have concurrent conflicts, so he starts the bank account with the lock (SELECT… FOR UPDATE), then you can safely make judgments and updates because no one else will be updating your account balance.

V is implemented based on Redis

The locking mechanism based on Redis mainly relies on the atomic operation of Redis itself, for example:

SET user_key user_value NX PX 100

The SET command only supports these parameters as of 2.6.12:

NX: Sets the key only when the key does not exist. The SET key value NX effect is the same as SETNX key value

PX millisecond: Specifies a time (millisecond) when the key is invalid

The code example above indicates that a user_key key is set only when user_key does not exist in Redis, and the value of the key is set to user_value, and the lifetime of the key is 100ms

Why does this command help us implement the locking mechanism?

This command is executed successfully only when a key does not exist. When multiple processes concurrently attempt to set the same key, only one process will succeed. After a process is set successfully, the service logic can be executed. After the service logic is executed, unlock the process.

Unlocking is very simple, just need to delete the key, but before deleting, you need to check that the value corresponding to the key is the original set by yourself.

In addition, redis’s Redlock(possibly wall-locked) mechanism can be used for distributed locks in redis cluster mode.

V Implemented based on ZooKeeper

In fact, based on ZooKeeper, is the use of its temporary ordered nodes to achieve a distributed lock.

The principle of

When a client wants to perform logical lock, it generates a unique temporary ordered node in the directory of a specified node on ZooKeeper, and then determines whether it is the one with the smallest serial number among these ordered nodes. If so, it is considered as obtaining the lock. If it is not, it means that the lock has not been obtained. Then we need to find the node smaller than ourselves in the sequence and call exist() method to register event listening for it. When this node is monitored to be deleted, we need to judge again whether the node we created has become the smallest in the sequence. If so, acquire the lock; if not, repeat the above steps.

When the lock is released, only the temporary node is removed.

 

Locker is a persistent node, node_1/node_2/… /node_n is a temporary node created by the client.

client_1/client_2/… /clien_n are both clients that want to acquire locks. In the case of client_1, if it wants to acquire a distributed lock, it needs to go to locker and create a temporary node (if node_1). After that, it needs to see if its node number is the smallest under Locker, and if so, it has acquired the lock. If not, find the smaller node (if node_2), and then listen for node_2 until it is removed. Then start again to determine if node_1 is the smallest in the sequence. If so, get the lock, and if not, continue to find another node.

V Blog Summary

There are many different types of distributed locks, and the “three relatively mainstream ones” mentioned in the opening paragraph are just the ones I have encountered. The future of distributed locking is definitely changing, and no matter what kind of company you are in, you may want to start as simple as possible. I hope you can choose the right solution for your project according to the business scenario of your company.

Other references:

  • Comics: What is distributed locking? www.360doc.com/content/18/…
  • A little understanding of distributed lock www.cnblogs.com/suolu/p/658…
  • MySQL optimistic locks vs. pessimistic locks blog.csdn.net/top_code/ar…
  • Various ways for realizing distributed lock www.cnblogs.com/yuyutianxia…
  • Architects show you how to play the distributed lock mp.weixin.qq.com/s/29FI3t7BY…

About the author: Focus on basic platform project development. If you have any questions or suggestions, please feel free to comment! Copyright notice: The copyright of this article belongs to the author and the blog garden, welcome to reprint, but without the consent of the author must retain this statement, and give the original text link in a prominent place on the page of the article. For the record: all comments and messages will be answered as soon as possible. You are welcome to correct your mistakes and make progress together. Or direct private message I support the blogger: if you think the article is helpful to you, you can click on the lower right corner of the article [recommendation]. Your encouragement is the author to adhere to the original and continuous writing of the biggest power! \