单节点

1.拉取镜像:docker pull zookeeper

2.运行容器

a.我的容器同一放在/root/docker下面,然后创建相应的目录和文件,

mkdir zookeeper
cd zookeeper
mkdir data
mkdir datalog
mkdir conf
cd conf
touch zoo.cfg

其中zoo.cfg(这里是默认的主要延时怪哉文件)如下:

tickTime=
initLimit=
syncLimit=
dataDir=/data
dataLogDir=/datalog
clientPort=
maxClientCnxns=

这里也设置了zookeeper默认的环境变量

b.运行实例,切换到/root/docker/zookeeper下载执行(不知道为什么这里zoo.cfg一定要用相对路径,用绝对路径提示docker-entrypoint.sh: line 15: /conf/zoo.cfg: Is a directory)

docker run --name zookeeper --restart always -d -v$(pwd)/data:/data  -v$(pwd)/datalog:/datalog -v $(pwd)/conf/zoo.cfg:/conf/zoo.cfg  -p :  -p : -p :  zookeeperp :  -p : -p :  zookeeper
# 2181端口号是zookeeper client端口
# 2888端口号是zookeeper服务之间通信的端口
# 3888端口是zookeeper与其他应用程序通信的端口
#用绝对路径 docker run --name zookeeper --restart always -d -v/root/docker/zookeep/data:/data -v/root/docker/zookeep/datalog:/datalog -v /root/docker/zookeep/conf/zoo.cfg:/conf/zoo.cfg -p : -p : -p : zookeeper
#提示/docker-entrypoint.sh: line : /conf/zoo.cfg: Is a directory
docker run --name zookeeper --restart always -d -v/root/docker/zookeep/data:/data -v/root/docker/zookeep/datalog:/datalog -v /root/docker/zookeep/conf/:/conf/ -p : -p : -p : zookeeper #正确的用法是不指定文件

c.zookeeper常规操作,首先执行以下指令进入zookeeper客服端:

docker exec -it zookeeper zkCli.sh -server 192.168.100.5: #如果是集群server用逗号分割 -server 192.168.100.5:,192.168.100.6:

create /zk "zkval1" #创建zk节点
create /zk/test1 "testval1" #创建zk/test1节点
create /zk/test2 "testval2" #创建zk/test2节点
#create /test/node "node1" 失败,不支持递归创建,多级时,必须一级一级创建
#create /zk/test2/ null 节点不能以 / 结尾,会直接报错
ls -s /zk #查看zk节点信息
set /zk/test1 "{1111}" #修改节点数据
get /zk/test1 #查看节点数据
delete /zk #删除时,须先清空节点下的内容,才能删除节点
delete /zk/test2

集群搭建

我这里搞了很久,最后还是用官网的配置 创建docker-compose.yml文件如下:

version: '3.1'

services:
zoo1:
image: zookeeper
restart: always
hostname: zoo1
ports:
- :
environment:
ZOO_MY_ID:
ZOO_SERVERS: server.=0.0.0.0::; server.=zoo2::; server.=zoo3::; zoo2:
image: zookeeper
restart: always
hostname: zoo2
ports:
- :
environment:
ZOO_MY_ID:
ZOO_SERVERS: server.=zoo1::; server.=0.0.0.0::; server.=zoo3::; zoo3:
image: zookeeper
restart: always
hostname: zoo3
ports:
- :
environment:
ZOO_MY_ID:
ZOO_SERVERS: server.=zoo1::; server.=zoo2::; server.=0.0.0.0::;

最后运行docker-compose up指令,最后验证,

docker exec -it zookeeper_zoo1_1 zkCli.sh -server 192.168.100.5:
create /zk "test"
quit #退出容器1 docker exec -it zookeeper_zoo2_1 zkCli.sh -server 192.168.100.5:
get /zk #在容器2获取值
quit docker exec -it zookeeper_zoo3_1 zkCli.sh -server 192.168.100.5:
get /zk #在容器3获取值
quit

分布式锁

ZooKeeper 分布式锁是基于 临时顺序节点 来实现的,锁可理解为 ZooKeeper 上的一个节点,当需要获取锁时,就在这个锁节点下创建一个临时顺序节点。当存在多个客户端同时来获取锁,就按顺序依次创建多个临时顺序节点,但只有排列序号是第一的那个节点能获取锁成功,其他节点则按顺序分别监听前一个节点的变化,当被监听者释放锁时,监听者就可以马上获得锁。而且用临时顺序节点的另外一个用意是如果某个客户端创建临时顺序节点后,自己意外宕机了也没关系,ZooKeeper 感知到某个客户端宕机后会自动删除对应的临时顺序节点,相当于自动释放锁。

如上图:ClientA 和 ClientB 同时想获取锁,所以都在 locks 节点下创建了一个临时节点 1 和 2,而 1 是当前 locks 节点下排列序号第一的节点,所以 ClientA 获取锁成功,而 ClientB 处于等待状态,这时 ZooKeeper 中的 2 节点会监听 1 节点,当 1节点锁释放(节点被删除)时,2 就变成了 locks 节点下排列序号第一的节点,这样 ClientB 就获取锁成功了。如下是c#代码:

创建 .NET Core 控制台程序

Nuget 安装 ZooKeeperNetEx.Recipes

创建 ZooKeeper Client, ZooKeeprLock代码如下:

namespace ZookeeperDemo
{
using org.apache.zookeeper;
using org.apache.zookeeper.recipes.@lock;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
public class ZooKeeprLock
{
private const int CONNECTION_TIMEOUT = ;
private const string CONNECTION_STRING = "192.168.100.5:2181,192.168.100.5:2182,192.168.100.5:2183"; /// <summary>
/// 加锁
/// </summary>
/// <param name="key">加锁的节点名</param>
/// <param name="lockAcquiredAction">加锁成功后需要执行的逻辑</param>
/// <param name="lockReleasedAction">锁释放后需要执行的逻辑,可为空</param>
/// <returns></returns>
public async Task Lock(string key, Action lockAcquiredAction, Action lockReleasedAction = null)
{
// 获取 ZooKeeper Client
ZooKeeper keeper = CreateClient();
// 指定锁节点
WriteLock writeLock = new WriteLock(keeper, $"/{key}", null); var lockCallback = new LockCallback(() =>
{
lockAcquiredAction.Invoke();
writeLock.unlock();
}, lockReleasedAction);
// 绑定锁获取和释放的监听对象
writeLock.setLockListener(lockCallback);
// 获取锁(获取失败时会监听上一个临时节点)
await writeLock.Lock();
} private ZooKeeper CreateClient()
{
var zooKeeper = new ZooKeeper(CONNECTION_STRING, CONNECTION_TIMEOUT, NullWatcher.Instance);
Stopwatch sw = new Stopwatch();
sw.Start();
while (sw.ElapsedMilliseconds < CONNECTION_TIMEOUT)
{
var state = zooKeeper.getState();
if (state == ZooKeeper.States.CONNECTED || state == ZooKeeper.States.CONNECTING)
{
break;
}
}
sw.Stop();
return zooKeeper;
} class NullWatcher : Watcher
{
public static readonly NullWatcher Instance = new NullWatcher();
private NullWatcher() { }
public override Task process(WatchedEvent @event)
{
return Task.CompletedTask;
}
} class LockCallback : LockListener
{
private readonly Action _lockAcquiredAction;
private readonly Action _lockReleasedAction; public LockCallback(Action lockAcquiredAction, Action lockReleasedAction)
{
_lockAcquiredAction = lockAcquiredAction;
_lockReleasedAction = lockReleasedAction;
} /// <summary>
/// 获取锁成功回调
/// </summary>
/// <returns></returns>
public Task lockAcquired()
{
_lockAcquiredAction?.Invoke();
return Task.FromResult();
} /// <summary>
/// 释放锁成功回调
/// </summary>
/// <returns></returns>
public Task lockReleased()
{
_lockReleasedAction?.Invoke();
return Task.FromResult();
}
} }
}

测试代码:

namespace ZookeeperDemo
{
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Parallel.For(, , async (i) =>
{
await new ZooKeeprLock().Lock("locks", () =>
{
Console.WriteLine($"第{i}个请求,获取锁成功:{DateTime.Now},线程Id:{Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(); // 业务逻辑...
}, () =>
{
Console.WriteLine($"第{i}个请求,释放锁成功:{DateTime.Now},线程Id:{Thread.CurrentThread.ManagedThreadId}");
Console.WriteLine("-------------------------------");
});
});
Console.ReadKey();
}
}
}

运行结果:

关于分布式锁, 我们也可以采用数据库和redis来实现, 各有优缺点。

参考:

ZooKeeper 实现分布式锁

七张图彻底讲清楚ZooKeeper分布式锁的实现原理

面试请不要再问我Redis分布式锁的实现原理

Docker下Zookeeper集群搭建

zookeeper Docker Official

zookeeper客户端命令详解

How To Install and Configure an Apache ZooKeeper Cluster on Ubuntu 18.04

docker zookeeper 集群搭建

CSharpKit 微服务工具包

Redis实现分布式锁

分布式锁的几种使用方式(redis、zookeeper、数据库)

Docker 下的Zookeeper以及.ne core 的分布式锁的更多相关文章

  1. ZooKeeper学习笔记四:使用ZooKeeper实现一个简单的分布式锁

    作者:Grey 原文地址: ZooKeeper学习笔记四:使用ZooKeeper实现一个简单的分布式锁 前置知识 完成ZooKeeper集群搭建以及熟悉ZooKeeperAPI基本使用 需求 当多个进 ...

  2. Docker下安装zookeeper(单机 & 集群)

    启动Docker后,先看一下我们有哪些选择. 有官方的当然选择官方啦~ 下载: [root@localhost admin]# docker pull zookeeper Using default ...

  3. ZooKeeper典型应用场景:分布式锁

    分布式锁是控制分布式系统之间同步访问共享资源的一种方式.如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要通过一些互斥手段来防止彼此之间的干扰,以保证一致 ...

  4. Zookeeper--0300--java操作Zookeeper,临时节点实现分布式锁原理

    删除Zookeeper的java客户端有  : 1,Zookeeper官方提供的原生API, 2,zkClient,在原生api上进行扩展的开源java客户端 3, 一.Zookeeper原生API ...

  5. zookeeper学习实践1-实现分布式锁

    引言 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提 ...

  6. zookeeper应用场景练习(分布式锁)

    在寻常的高并发的程序中.为了保证数据的一致性.因此都会用到锁.来对当前的线程进行锁定.在单机操作中.非常好做到,比方能够採用Synchronized.Lock或者其它的读写多来锁定当前的线程.可是在分 ...

  7. Linux下搭建Zookeeper环境

    Zookeeper 是 Google 的 Chubby一个开源的实现,是 Hadoop 的分布式协调服务,它包含一个简单的原语集,分布式应用程序可以基于它实现同步服务,配置维护和命名服务等. 其工作原 ...

  8. ZooKeeper分布式锁的实现原理

    七张图彻底讲清楚ZooKeeper分布式锁的实现原理[石杉的架构笔记] 文章转载自:https://juejin.im/post/5c01532ef265da61362232ed#comment(写的 ...

  9. 利用Zookeeper实现分布式锁

    特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...

随机推荐

  1. JAVA I/O系统 Thinking in Java 之 File类

    File类的文件具有一定的误导性,我们可能会认为它指代的是文件,实际上并非如此.它技能代表一个特定文件的名称,又能代表一个目录下的一组文件的名称.如果它指的是一个文件集,我们就可以对此集合调用list ...

  2. HandBrake-QuickSync-Mac (内容:QuickSync encoder via VideoToolbox )

    来源:https://github.com/galad87/HandBrake-QuickSync-Mac/commit/2c1332958f7095c640cbcbcb45ffc955739d594 ...

  3. phpstorm分别在Mac和Windows下启动命令行,并启用ssh

    Mac:在terminal下运行 sudo -i 输入密码  就可以用ssh IP:端口  命令行登录了 DAssist是一个命令行开发辅助,可直接在系统命令行工具中使用,Linux和MacOS等自带 ...

  4. IIS 6.0 cmd iisapp -a C:\WINDOWS\system32\iisapp.vbs不存在

    心血来潮看下iis cmd>iisapp -a "噔" 弹出 windows脚本宿主错误:无法找到脚本文件 C:\WINDOWS\system32\iisapp.vbs 晕 ...

  5. 在istio中让prometheus跑起来

    使用microk8s安装,默认的prometheus已就位. 可直接弄. 一,映射本地端口(注意,命令行最后的两个端口,前一个为要映射的本地端口,后一个为POD的服务端口,如果本地相同端口被占用,则要 ...

  6. pypi 打包分发

    打包Python项目 本教程将指导您如何打包一个简单的Python项目.它将向您展示如何添加必要的文件和结构来创建包,如何构建包以及如何将其上载到Python包索引. 一个简单的项目 本教程使用一个名 ...

  7. mysql常用操作(测试必备)

    现在互联网的主流关系型数据库是mysql,掌握其基本的增.删.改.查是每一个测试人员必备的技能. sql语言分类 1.DDL语句(数据库定义语言): 数据库.表.视图.索引.存储过程,例如:CREAT ...

  8. contact form 7如何搭配Akismet过滤垃圾邮件

    contact form 7有很多站长在用,但是经常会有一些垃圾邮件进来,如何过滤呢?两个方法:1.表单提交启用验证码功能,很多垃圾邮件是用软件扫相应的端口,然后批量群发,如果用验证码了可以过滤很大一 ...

  9. 关于Socket踩过的一些坑

    Socket学习文档  http://developer.51cto.com/developer/javabook/images/3.pdf 1.socket.shutdownOutput(); 文档 ...

  10. Babel7 转码

    ES6 (ES2015)更新了很多新的js语法, 也添加了一些新的API, 但不是所有的浏览器对这些新特性都支持的很好, 通过babel可以高版本的js转成低版本的js (ES 5.1), 同时对于J ...