zookeeper客户端之Curator实现分布式锁案例以及实际场景案例

背景:

        背景很多,比如集群中多个节点生成某个序列ID, 多个节点同时在自身节点做某些事,但是这件事只能同时只有一个节点去做,网上看过一些案例,比如火车票,库存减少等很多案例,还有一种极端的情况,比如有两个内部的系统之间服务的交互,在A系统开启线程调用B系统之后执行下面逻辑,然而B系统中有的逻辑要等A系统执行完之后再执行,有的A系统要等B系统执行完部分逻辑在执行,以此交替,这种非常极端的情况,也是不符合分布式系统设计,感觉两个系统太耦合了,我就遇到这么吐血的分布式架构,也不知道之前拆分这两套系统的人怎么想的,完全没有好好的解耦就开始这样搞,感觉像是为了拆而拆,好了这里不吐槽了,感觉成了吐槽文章。

解决方案

        这里也利用zookeeper顺序创建节点的特性来解决锁的问题,curator客户已经帮我封装好了一系列逻辑,我们这里只需要用就行了,先附上《从paxos到zookeeper分布式一致原理与实践》的代码,下面来解释里面的实现的过程

引入的maven依赖

     <dependency>
	    <groupId>org.apache.zookeeper</groupId>
	    <artifactId>zookeeper</artifactId>
	    <version>3.4.6</version>
	</dependency>
	<dependency>
	    <groupId>org.apache.curator</groupId>
	    <artifactId>curator-framework</artifactId>
	    <version>2.4.2</version>
	</dependency>
	<dependency>
	    <groupId>org.apache.curator</groupId>
	    <artifactId>curator-recipes</artifactId>
	    <version>2.4.2</version>
	</dependency>
package com.test.zookeeper.curator;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.BackgroundCallback;
import org.apache.curator.framework.api.CuratorEvent;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.framework.recipes.cache.NodeCacheListener;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.framework.recipes.leader.LeaderSelector;
import org.apache.curator.framework.recipes.leader.LeaderSelectorListenerAdapter;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.framework.recipes.cache.PathChildrenCache.StartMode;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;

public class Curator {
	static String connectionString = "192.168.66.138:2181";
	static String lock_path = "/curator_recipes_lock_path";
	
	static CuratorFramework client = CuratorFrameworkFactory
			.builder().connectString(connectionString)
			.retryPolicy(new ExponentialBackoffRetry(1000, 3))
			.sessionTimeoutMs(5000).build();
	
	public static void main(String[] args) throws Exception {
		
		recipes_Lock();
		
		System.in.read();
	}
	
	/**
	 * 分布式锁
	 * 这里是一个客户端多个线程去执行,如果多个客户端模拟也是一样的,因为都是在相同的节点下
	 */
	static void recipes_Lock(){
		client.start();
		final InterProcessMutex lock = new InterProcessMutex(client, lock_path);
		final CountDownLatch down = new CountDownLatch(1);
		for(int i=0; i<10; i++){
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						down.await();
						lock.acquire();
					} catch (Exception e) {
					}
					SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss|SSS");
					String orderNo = format.format(new Date());
					System.out.println("生成的订单号是: "+orderNo);
					try {
						lock.release();
					} catch (Exception e) {
					}
				}
			}).start();
		}
		down.countDown();
	}
}

InterProcessMutex类通过CuratorFramework和path构造,当执行了acquire方法的时候会在/curator_recipes_master_path节点下生成尾号带顺序的节点,可以看下图

上面代码起了10个线程,所有生成了10个临时节点

zookeeper服务会获取/curator_recipes_master_path节点下所有的等待锁的临时节点,最小的节点获得锁,并非最小的节点会等待上一个节点释放锁,释放锁的时候会删除临时节点,所以并非最小的节点会在小1的节点注册事件,一旦监听到事件,会立马唤醒所有等待的线程,具体源码实现已经有很多文章可以观看

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值