Zookeeper implements distributed lock to obtain instance resolution of unique order number

1. Business scenario

We usually have an order number when shopping. How to ensure the uniqueness of the order number in the case of high concurrency? For example, we should not only ensure the reliability of performance (distributed) but also ensure that duplicate order numbers are not generated. At this time, we need to use distributed locks. The implementation method of distributed locks introduced here is to use Zookeeper. We will not introduce Zookeeper too much here, but mainly look at how to implement distributed locks.

2. What is a distributed lock

Distributed lock is a way to control synchronous access to shared resources between distributed systems. In distributed systems, it is often necessary to coordinate their actions. If different systems or different hosts of the same system share one or a group of resources, they often need to be mutually exclusive to prevent interference with each other to ensure consistency. In this case, distributed locks need to be used. (quoted from Baidu Encyclopedia)

3. Use Zookeeper to realize distributed locking

Use zookeeper to create temporary sequence nodes to realize distributed locks. It is suitable for sequential execution. The general idea is to create temporary sequence nodes, find the smallest sequence node and obtain distributed locks. After the program execution is completed, the sequence node disappears. Monitor the changes of nodes through watch, find the smallest sequence node from the rest of nodes and obtain distributed locks, Execute the corresponding processing, and so on... (for simplicity, we only create temporary nodes without judging the order)

4. Practical projects

Maven dependency:
    <dependencies>
        <dependency>
            <groupId>com.101tec</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.10</version>
        </dependency>
    </dependencies>
OrderNumGenerator:
//Generate order class
public class OrderNumGenerator {
    //Global order id
    public static int count = 0;

    public String getNumber() {
        SimpleDateFormat simpt = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
        return simpt.format(new Date()) + "-" + ++count;
    }
}
Lock:
/**
 * Custom distributed lock
 */
public interface Lock {

    // Acquire lock
    void getLock();

    // Release lock
    void unlock();
}
ZookeeperAbstractLock:
/**
 * Refactor the duplicate code and hand over the duplicate code to the subclass for execution
 */
public abstract class ZookeeperAbstractLock implements Lock {

    // zk connection address
    private static final String CONNECTSTRING = "127.0.0.1:2181";
    // Create zk connection
    protected ZkClient zkClient = new ZkClient(CONNECTSTRING);
    protected static final String PATH = "/lock";


    @Override
    public void getLock() {
        if (tryLock()) {
            System.out.println("obtain zk Lock successful");
        } else {
            // wait for
            waitLock();
            // Reacquire lock
            getLock();
        }
    }

    // Waiting lock
    protected abstract void waitLock();

    // Whether to acquire the lock successfully. If successful, return true. If failed, return false
    protected abstract boolean tryLock();

    @Override
    public void unlock() {
        if (zkClient != null) {
            zkClient.close();
            System.out.println("Close connection release lock resource...");
        }
    }
}
ZookeeperDistrbuteLock:
public class ZookeeperDistrbuteLock extends ZookeeperAbstractLock {

    private CountDownLatch countDownLatch = null;

    @Override
    protected boolean tryLock() {
        try {
            zkClient.createEphemeral(PATH);
            return true;
        } catch (RuntimeException e) {
            return false;
        }
    }

    @Override
    protected void waitLock() {
        // Use event listening to get the notification of node deletion
        IZkDataListener iZkDataListener = new IZkDataListener() {
            // When a node is deleted
            @Override
            public void handleDataDeleted(String s) throws Exception {
                System.out.println("The node was deleted:" + s);
                if (countDownLatch != null) {
                    // awaken
                    countDownLatch.countDown();
                }
            }
            // When a node changes
            @Override
            public void handleDataChange(String s, Object o) throws Exception {

            }

        };
        // Registration node information acquisition event notification
        zkClient.subscribeDataChanges(PATH, iZkDataListener);
        if (zkClient.exists(PATH)) {
            // Create semaphore
            countDownLatch = new CountDownLatch(1);
            try {
                countDownLatch.await();
            } catch (Exception e) {
            }
        }
        // Delete event notification
        zkClient.unsubscribeDataChanges(PATH, iZkDataListener);
    }
}
OrderSerice:
// Order generation calls business logic
public class OrderSerice implements Runnable {

    // Generate order number
    OrderNumGenerator orderNumGenerator = new OrderNumGenerator();

    private ZookeeperDistrbuteLock lock = new ZookeeperDistrbuteLock();

    @Override
    public void run() {
        getnNumber();
    }

    private void getnNumber() {
        try {
            lock.getLock();
            // Simulate user generated order number
            String number = orderNumGenerator.getNumber();

            System.out.println("Current thread:" + Thread.currentThread().getName()
                    + "  Generated order number:" + number);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            // Release lock
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        System.out.println("Simulation generated order number");
        for (int i = 0; i < 100; i++) {
            new Thread(new OrderSerice()).start();
        }
    }

}

Added by khaine on Fri, 07 Jan 2022 11:49:45 +0200