基于zookeeper实现分布锁

描述:场景

分布式场景下,当用户下单时,需要对商品的库存进行操作,这是后如果在高并发情况下,可能会出现数据一致性问题,因此,就需要要求在操作时候对操作的商品进行进行锁处理,这里使用zookeeper的znode特性(znode分为临时性节点和永久性节点,在创建时可设定。临时性节点依附于客户端会话。永久性节点必须显示的由任一一个有权限的客户端进行删除。并且一个临时性的节点不应该有子节点。一个临时性节点即使绑定在客户端的会话上,对其他客户端也是可见的。)通过节点的监听(当znode改变时,watch使客户端了解相应的信息。watch由zookeeper服务的操作来设置,同时有服务的其他操作来触发。)状态来触发一些列其他操作。

思路:假设我们需要对id=1001的商品进行库存操作,此时我们可以提前在zookeeper上建立一个父节点,路径为/products,注意父节点需要是永久性节点(临时节点下不能创建子节点),然后我们可以查询/products/1001的路径是否存在,如果存在则等待,如果不存在则新建一个节点/products/1001,创建成功以后就可以对库存进行操作,操作完成后,就可以删除此节点,此时就会触发watch事件,那么等待的线程就会重新执行。

import java.io.IOException;
import java.lang.annotation.ElementType;
import java.util.Collection;
import java.util.Collections;
import java.util.List;


import com.sun.xml.internal.bind.v2.TODO;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.ZooDefs.Ids;
import org.junit.Test;
import org.apache.zookeeper.ZooKeeper;


public class DemoServer {


	private ZooKeeper zkCli = null;


	Boolean haveLock = false;


	private final String groupName = "/locks";


	private String nodePath;


	private static String hostname;


	public void gainLockAndDoSomething() throws Exception {
		zkCli = new ZooKeeper("hostName:2181", 2000, new Watcher() {


			@Override
			public void process(WatchedEvent event) {
				if (event.getType() != EventType.NodeChildrenChanged)
					return;
				try {
					// 用zk客户端去获取锁权限
					haveLock = gainLock();
					if (haveLock) {
						System.out.println(hostname + " gained the lock....");
						// 拿到锁之后,调用业务处理方法进行业务处理
						doSomeThing();
						// 释放锁
						releaseLock();
						// 重新创建锁节点并注册监听
						registerLock();
					}


				} catch (Exception e) {
				}
			}


		});


		// 用zk客户端向"/locks"下注册一把自己的锁节点
		registerLock();
		// 让线程稍微休眠一下
		Thread.sleep((long) (Math.random() * 500 + 500));
		// 用zk客户端去获取锁权限
		haveLock = gainLock();


		if (haveLock) {
			System.out.println(hostname + " gained the lock....");
			// 拿到锁之后,调用业务处理方法进行业务处理
			doSomeThing();
			// 释放锁
			releaseLock();
			// 重新创建锁节点并注册监听
			registerLock();
		}


	}


	private Boolean gainLock() throws KeeperException, InterruptedException {
		List<String> children = zkCli.getChildren(groupName, true);
		if (children.size() == 1)
			return true;
		Collections.sort(children);
		if (children.get(0).equals(nodePath.substring(groupName.length() + 1)))
			return true;
		return false;
	}


	private void doSomeThing() throws InterruptedException {
		System.out.println("begin working .......");
		Thread.sleep((long) (Math.random() * 1000 + 500));
		System.out.println("work has complished.....");
	}


	private void releaseLock() throws InterruptedException, KeeperException {
		zkCli.delete(nodePath, -1);
	}


	private void registerLock() throws KeeperException, InterruptedException {

		nodePath = zkCli.create(groupName + "/lock", null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
		System.out.println(nodePath);
	}


	@Test
	public void test() throws KeeperException, InterruptedException, IOException {
		zkCli = new ZooKeeper("hostName:2181", 2000, new Watcher() {


			@Override
			public void process(WatchedEvent event) {
				// TODO Auto-generated method stub


			}
		});
		String create = zkCli.create("/locks", null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
		System.out.println(create);
		Thread.sleep(2000);
		create = zkCli.create("/locks/a", "ab".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
		System.out.println(create);
		byte[] data = zkCli.getData("/locks/a", true, null);
		System.out.println(new String(data, "utf-8"));
	}


	/**
	 * 程序的入口
	 *
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		hostname = args[0];
		// 去获取锁并且进行业务处理
		DemoServer demoServer = new DemoServer();
		demoServer.gainLockAndDoSomething();
		// 主线程休眠
		Thread.sleep(Long.MAX_VALUE);
	}
}

使用Curator实现

http://blog.csdn.net/luckyzhoustar/article/details/50628419

其他分布式解决方案

http://blog.csdn.net/fansunion/article/details/52302650

猜你喜欢

转载自blog.csdn.net/m0_37556124/article/details/79153369