Distributed - distributed coordination framework Zookeeper (three) - Zookeeper distributed lock to achieve

Note: When asked what problems encountered in development, do not answer anything wrong report

Answered our project is to do a cluster, the cluster when it comes to doing a lot of problems distributed, ie distributed various distributed problem arising, direct answer to.

Then the interviewer usually draw a few let you tell us, how do you solve, how to use, this time to start speaking.

Here to talk about the knowledge of distributed lock:

First, the basic concepts of distributed lock

1.1 What is distributed lock

Distributed Lock generally used in a distributed system or in multiple applications, to control the execution order of performing the same task or tasks . Tomcat deployed multiple applications in the project, you will encounter the same situation might perform multiple tasks in carrying out its mandate. It can make use of distributed lock to ensure at the same time only a tomcat application is executed.

1.2, Zookeeper distributed lock principle to achieve

Temporary node + event notifications.

Create a temporary sequence of nodes, find the smallest sequence of nodes, distributed lock acquisition, after completion of the program to perform this sequence of nodes disappeared. By watch to monitor changes to a node, find the smallest node sequence from the rest of the nodes, access to distributed lock, perform the appropriate treatment, and so on ........

Implementation steps:

(1) while creating a plurality of one and the same JVM node / lock on ZK;

(2) Since ZK node is unique , and if there are multiple clients to create the same node / lock, see who will come to get quickly create a node requesting a lock ;

(3) In this case the node type is a temporary type. If JVM1 node has been created successfully, it will be reported when JVM3 JVM1 and then create the node "/ lock node already exists" error, then JVM2 and JVM3 waiting

The principle detailed steps:

        Zookeeper how to acquire a lock?

To see who will come to get a quick request to create a node lock

        Zookeeper how to achieve the release of the lock?

If jvm1 (server 1) program is now finished, the current ZK has closed the Session answer;

Then jvm2 (server 2) and jvm3 (server 3) use Watcher event notifications get to / lock has been deleted, then re-enter the request to obtain the lock; then jvm2 and jvm2 competition that step back to see who created node fast whoever got the lock, so the competition continues .......

        Zookeeper deadlock how to do?

If the program has not been processed, may lead to a deadlock, you can set the validity period, generally 60s can be.

Second, the use of distributed lock scene

If you are using a stand-alone version of the system can lock lock lock to lock and synchronized, but the cluster environment of distributed systems will use distributed lock.

2.1, the next generation of distributed scene order ID

Business scenario: the distributed case, generate the global order number.

Problem: In a distributed (clustered) environment, each JVM can not synchronize using timestamps generated order number may be repeated in a distributed scenario.

How to solve the case of distributed order number can not be repeated:

(1) using a distributed lock:

1. implementation of distributed database lock

Disadvantages: poor performance occurs when abnormal thread, prone to deadlock.

2. Implementation of a Distributed Lock redis (redisson framework implementation)

Disadvantages: time to failure of the lock difficult to control, prone to deadlocks, non-blocking, non-repeatable

3. Use the Zookeeper distributed lock to achieve

Relatively simple, high reliability, using a temporary node releases the lock, the dead time control is easy, efficient and simple

Built 4.SpringCloud achieve global lock (with less)

(2) good order number generated in advance, stored in redis, taken directly from the order number redis taken in;

 

Third, the use Zookeeper distributed lock implement the code (Template Method design pattern)

3.1, Maven relies

	<dependencies>
		<dependency>
			<groupId>com.101tec</groupId>
			<artifactId>zkclient</artifactId>
			<version>0.10</version>
		</dependency>
	</dependencies>

3.2, create an interface Lock

public interface Lock {
    //获取到锁的资源
	public void getLock();
    // 释放锁
	public void unLock();
}

3.3, create an abstract class ZookeeperAbstractLock

  • 1. Connect zkclient, create a / lock nodes on zk, temporary node type nodes
  • 2. If the node is successfully created, the direct implementation of business logic, if the node creation fails, wait
  • 3. Use the event monitor whether the node is removed if the lock is deleted to re-enter acquiring resources

The use of design patterns : Template Method pattern is the parent class defines a template, so subclass inherits the parent class to achieve, to be distributed to achieve ZK lock can also blown about design patterns (even simple) interview!

//将重复代码写入子类中..(设计模式:模板方法模式)
public abstract class ZookeeperAbstractLock implements Lock {
	// zk连接地址
	private static final String CONNECTSTRING = "127.0.0.1:2181";
	// 创建zk连接
	protected ZkClient zkClient = new ZkClient(CONNECTSTRING);
	protected static final String PATH = "/lock";

    //获取锁
	public void getLock() {
        //1.连接zkclient,在zk上创建一个/lock节点,节点类型为临时节点
        //2.如果节点创建成功,直接执行业务逻辑,如果节点创建失败,进行等待
		if (tryLock()) {
			System.out.println("##获取lock锁的资源####");
		} else {
			// 等待
            //3.使用事件监听该节点是否被删除,如果被删除重新进入获取锁资源
			waitLock();
			// 重新获取锁资源
			getLock();
		}

	}

	// 子类实现:获取锁资源,如果成功获取到锁返回true,否则返回false
	abstract boolean tryLock();
	// 子类实现:如果节点创失败,进行等待 ,使用事件监听该节点是否被删除,如果被删除重新进入获取锁资源
	abstract void waitLock();
    //释放锁
	public void unLock() {
        //当程序执行完毕,直接关闭连接
		if (zkClient != null) {
			zkClient.close();
			System.out.println("释放锁资源...");
		}
	}

}

3.4, ZookeeperDistrbuteLock class (subclass)

  • 1. subclass implementation: the resources to acquire the lock, the lock is acquired successfully return if true, or else return false;
  • 2. subclass implementation: If you create a node fails, wait, using event listeners whether the node is deleted if it is deleted to re-enter again into the parent getLock method - then enter the sub-category node tryLock way to create, again trying to acquire the lock.
public class ZookeeperDistrbuteLock extends ZookeeperAbstractLock {
	private CountDownLatch countDownLatch = null;
//1.获取锁
	@Override
	boolean tryLock() {
		try {
//创建临时节点PATH  获取锁
			zkClient.createEphemeral(PATH);
			return true;//创建成功则返回true
		} catch (Exception e) {
//如果创建该节点失败,这时直接catch
			return false;
		}

	}

//2.如果创建失败,等待
	@Override
	void waitLock() {
		IZkDataListener izkDataListener = new IZkDataListener() {
//表示节点被删除
			public void handleDataDeleted(String path) throws Exception {
				// 唤醒被等待的线程
				if (countDownLatch != null) {
					countDownLatch.countDown();//计数器一旦为0情况
				}
			}
//表示节点被修改
			public void handleDataChange(String path, Object data) throws Exception {

			}
		};
		// 注册监听事件通知
		zkClient.subscribeDataChanges(PATH, izkDataListener);
//如果控制程序等待
		if (zkClient.exists(PATH)) {
			countDownLatch = new CountDownLatch(1);
			try {
//等待
				countDownLatch.await();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

//后面代码继续执行,为了不影响后面代码执行,建议删除该事件监听
		// 删除监听
		zkClient.unsubscribeDataChanges(PATH, izkDataListener);
	}
//为什么要删除事件监听?  因为不删除服务端会多次监听,所以监听完就要删除一下,一走到这一步又重新进入父类getLock方法——然后进入子类创建节点tryLock方法,重新尝试获取锁
}

Question 1: Why did you want to delete an event listener?  

Because they do not delete the server will listen many times, so you should delete it finished listening 

 

3.5 Test --- use Zookeeper lock operating results

public class OrderService implements Runnable {
	private OrderNumGenerator orderNumGenerator = new OrderNumGenerator();
	// 使用lock锁
	// private java.util.concurrent.locks.Lock lock = new ReentrantLock();
	private Lock lock = new ZookeeperDistrbuteLock();
	public void run() {
		getNumber();
	}
	public void getNumber() {
		try {
			lock.getLock();
			String number = orderNumGenerator.getNumber();
			System.out.println(Thread.currentThread().getName() + ",生成订单ID:" + number);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unLock();
		}
	}
	public static void main(String[] args) {
		System.out.println("####生成唯一订单号###");
//注意这面这行必须注释掉,因为代表值创建一个ZK的Session连接,只创建一个订单号,所以如果没注释掉只能获取一次锁
//		OrderService orderService = new OrderService();
//		for (int i = 0; i < 100; i++) {
//			new Thread(orderService).start();
//		}

//改成这样,100个循环new100次才能生成100个订单号,获取100次锁
		for (int i = 0; i < 100; i++) {
//这样才能模拟出分布式锁的场景
			new Thread( new OrderService()).start();
		}
	}
}

 

Published 52 original articles · won praise 116 · views 50000 +

Guess you like

Origin blog.csdn.net/RuiKe1400360107/article/details/103796419