preface

As for distributed lock, there are many application scenarios in the Internet industry, such as inventory deduction of e-commerce, seckilling activities, cluster timed task execution and other scenarios requiring mutually exclusive processes. And the means to achieve distributed lock are also many, we are more common is Redis and ZooKeeper, today we mainly introduce the distributed lock based on ZooKeeper.

This article is mainly to borrow Curator framework implementation approach of zk distributed lock, everyone understand the later can fully manual to realize again, but in the work or recommend the use of mature open source framework, others have helped us a lot of pit stepping well, unless as a last resort, needs highly customized meeting the needs of your project, started their own packaging.

The body of the

This section describes ZooKeeper

Since it is based on ZooKeeper distributed lock, first of all must have a certain understanding of this ZooKeeper, here is not much to explain, only with distributed lock associated with a simple introduction, more detailed features you can refer to the official documentation.

Zookeeper maintains a file system-like data structure with four types of nodes


  • PERSISTENT: PERSISTENT nodes. Once created, the node still exists even if the client is disconnected from zK.

  • PERSISTENT_SEQUENTIAL: Persistent sequential numbered node. More than PERSISTENT nodes nodes are automatically numbered sequentially.

  • EPHEMERAL: the temporary node. When the client disconnects from ZK, the node is removed.

  • EPHEMERAL_SEQUENTIAL: temporary sequential node. More than EPHEMERAL nodes are automatically numbered sequentially. (Distributed lock implementation uses this node type)

Toth implements distributed locking principle

Ok, when we simply understand the node type of ZK, now we formally analyze the realization principle of distributed lock for Curator. Here we define a “/curator_lock” lock node to hold temporary sequential nodes created by related clients.

If two clients, ClientA and ClientB, are competing for a lock at the same time, and ClientA reaches ZK first, it will create a temporary order node of “/curator_lock/ XXX-0000000000” on our ZK.


It then obtains all the children of the “/curator_lock/” lock node. Since these nodes are ordered, it determines whether the node it created is the first in order. ClientA is the first client that created the node, so it holds the lock. We use zkCli to view the node information as follows.

[zk: localhost:2182(CONNECTED) 4] ls /curator_lock

[_c_f3f38067-8bff-47ef-9628-e638cfaad77e-lock-0000000000]

Copy the code

ClientB follows the same steps to create a temporary sequential node “/curator_lock/ XXX-0000000001” under “/curator_lock/”, and then to obtain all the children of that node. And check whether the node serial number currently generated is the smallest among these sub-nodes. Since the node with the smallest serial number is created by ClientA at this time and has not been released, ClientB cannot get the lock by itself.


[zk: localhost:2182(CONNECTED) 4] ls /curator_lock[_c_2a8198e4-2039-4a3c-8606-39c65790d637-lock-0000000001,_c_f3f38067-8bff-47ef-9628-e638cfaad77e-lock-00000 00000]Copy the code

Since ClientB can’t get the lock and won’t give it up, it adds a listener to its previous node (the API implementation provided by ZK), and as soon as it listens for the previous node to be deleted, that is, the lock is released, it will immediately re-acquire the lock.

When the following ClientC, ClientD… The same is true when it comes in, only the number on the node changes, which increases according to the number of Client connections.

You may also worry about what happens if the client that got the lock goes down. Will it not release the lock? In fact, this problem has been solved above. Because the distributed lock is implemented by temporary sequential node, when the client disconnects from ZK, the node will disappear, which is equivalent to releasing the lock.

The code below shows the basic usage of Curator. This is only a reference example, so don’t use it casually in a production environment.

CuratorFramework client = CuratorFrameworkFactory. NewClient (127.0.0.1:2182, 5000100, 00, new ExponentialBackoffRetry(1000, 3)); client.start(); InterProcessMutex interProcessMutex = new InterProcessMutex(client, "/curator_lock"); / / lock interProcessMutex. Acquire (); / / / / business logic releases the lock interProcessMutex. Release (); client.close();Copy the code

conclusion

After we understand the principle, we can abandon the Curator and implement a distributed lock by ourselves. We believe that experienced engineers can implement basic functions without any problem, but to achieve production level, we may still need to work on details, such as some exception handling and performance optimization.

“Programming monkey in the Middle of the night” – share the driest dry stuff