第二十四讲 Zookeeper案例:分布式环境中实现共享锁
- 格式:pptx
- 大小:12.58 MB
- 文档页数:2
zookeeper集群工作原理Zookeeper集群工作原理Zookeeper是一个开源的分布式协调服务,它提供了一个高可用的、有序的、一致性的数据管理和协调服务。
在分布式系统中,Zookeeper集群起到了关键的作用,负责管理和维护分布式系统中的各种数据和状态。
一、Zookeeper集群的基本概念1. 服务器角色:Zookeeper集群中的每个节点都可以担任Leader 或Follower的角色。
Leader负责处理客户端请求和写操作,Follower则负责处理读操作和同步数据。
2. 数据模型:Zookeeper将数据存储在树形结构的命名空间中,类似于文件系统的目录结构,每个节点都有一个路径和一个关联的数据。
3. 会话:客户端与Zookeeper集群之间的连接被称为会话,会话可以保持一段时间,并且可以处理客户端请求。
二、Zookeeper集群的工作原理1. Leader选举:在Zookeeper集群中,只有一个节点可以担任Leader角色,其余节点为Follower。
当集群启动或Leader节点宕机时,会发起一次Leader选举。
选举过程通过ZAB协议(Zookeeper Atomic Broadcast)进行,节点首先互相通信,然后通过投票的方式选择出新的Leader节点。
2. 数据一致性:Zookeeper通过使用ZAB协议来实现数据的一致性。
当客户端向Leader节点发送写请求时,Leader节点将该请求转发给所有的Follower节点,一旦大多数Follower节点都返回成功响应,Leader节点就会将数据变更应用到自身的数据副本中,并通知Follower节点更新数据。
这样就保证了数据的一致性。
3. 数据同步:Zookeeper集群中的Follower节点会定期从Leader 节点同步数据,以保持数据的一致性。
Follower节点会向Leader 节点发送请求,获取最新的数据更新,然后更新到自身的数据副本中。
Zookeeper最典型的应⽤场景(理论+实战)1.前⾔之前⾃⼰写了⼀些关于Zookeeper的基础知识,Zookeeper作为⼀种协调分布式应⽤⾼性能的调度服务,实际的应⽤场景也⾮常的⼴泛,这⾥主要通过⼏个例⼦来具体的说明Zookeeper在特定场景下的使⽤⽅式(下⾯的这些功能估计consul和etcd也能实现,以后学到了再说吧)。
2.具体应⽤2.1.⼀致性配置管理我们在开发的时候,有时候需要获取⼀些公共的配置,⽐如数据库连接信息等,并且偶然可能需要更新配置。
如果我们的服务器有N多台的话,那修改起来会特别的⿇烦,并且还需要重新启动。
这⾥Zookeeper就可以很⽅便的实现类似的功能。
2.1.1.思路将公共的配置存放在Zookeeper的节点中应⽤程序可以连接到Zookeeper中并对Zookeeper中配置节点进⾏读取或者修改(对于写操作可以进⾏权限验证设置),下⾯是具体的流程图:2.1.2.事例数据库配置信息⼀致性的维护配置类:public class CommonConfig implements Serializable{// 数据库连接配置private String dbUrl;private String username;private String password;private String driverClass;public CommonConfig() {}public CommonConfig(String dbUrl, String username, String password, String driverClass) {super();this.dbUrl = dbUrl;ername = username;this.password = password;this.driverClass = driverClass;}public String getDbUrl() {return dbUrl;}public void setDbUrl(String dbUrl) {this.dbUrl = dbUrl;}public String getUsername() {return username;}public void setUsername(String username) {ername = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getDriverClass() {return driverClass;}public void setDriverClass(String driverClass) {this.driverClass = driverClass;}@Overridepublic String toString() {return "CommonConfig:{dbUrl:" + this.dbUrl +", username:" + ername +", password:" + this.password +", driverClass:" + this.driverClass + "}";}}配置管理中⼼获取本地配置信息修改配置,并同步同步配置信息到Zookeeper服务器public class ZkConfigMng {private String nodePath = "/commConfig";private CommonConfig commonConfig;private ZkClient zkClient;public CommonConfig initConfig(CommonConfig commonConfig) {if(commonConfig == null) {monConfig = new CommonConfig("jdbc:mysql://127.0.0.1:3306/mydata?useUnicode=true&characterEncoding=utf-8", "root", "root", "com.mysql.jdbc.Driver");} else {monConfig = commonConfig;}return monConfig;}/*** 更新配置** @param commonConfig* @return*/public CommonConfig update(CommonConfig commonConfig) {if(commonConfig != null) {monConfig = commonConfig;}syncConfigToZookeeper();return monConfig;}public void syncConfigToZookeeper() {if(zkClient == null) {zkClient = new ZkClient("127.0.0.1:2181");}if(!zkClient.exists(nodePath)) {zkClient.createPersistent(nodePath);}zkClient.writeData(nodePath, commonConfig);}}以上是提供者,下⾯我们需要⼀个客户端获取这些配置public class ZkConfigClient implements Runnable {private String nodePath = "/commConfig";private CommonConfig commonConfig;@Overridepublic void run() {ZkClient zkClient = new ZkClient(new ZkConnection("127.0.0.1:2181", 5000));while (!zkClient.exists(nodePath)) {System.out.println("配置节点不存在!");try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}}// 获取节点commonConfig = (CommonConfig)zkClient.readData(nodePath);System.out.println(commonConfig.toString());zkClient.subscribeDataChanges(nodePath, new IZkDataListener() {@Overridepublic void handleDataDeleted(String dataPath) throws Exception {if(dataPath.equals(nodePath)) {System.out.println("节点:" + dataPath + "被删除了!");}}@Overridepublic void handleDataChange(String dataPath, Object data) throws Exception {if(dataPath.equals(nodePath)) {System.out.println("节点:" + dataPath + ", 数据:" + data + " - 更新");commonConfig = (CommonConfig) data;}}});}}下⾯启动Main函数配置管理服务启动public static void main(String[] args) throws InterruptedException {SpringApplication.run(ZookeeperApiDemoApplication.class, args);ZkConfigMng zkConfigMng = new ZkConfigMng();zkConfigMng.initConfig(null);zkConfigMng.syncConfigToZookeeper();TimeUnit.SECONDS.sleep(10);// 修改值zkConfigMng.update(new CommonConfig("jdbc:mysql://192.168.1.122:3306/mydata?useUnicode=true&characterEncoding=utf-8","root", "wxh", "com.mysql.jdbc.Driver"));}}客户端启动:public static void main(String[] args) throws InterruptedException {SpringApplication.run(ZookeeperApiDemoApplication.class, args);ExecutorService executorService = Executors.newFixedThreadPool(3);// 模拟多个客户端获取配置executorService.submit(new ZkConfigClient());executorService.submit(new ZkConfigClient());executorService.submit(new ZkConfigClient());}}2.2.分布式锁在我们⽇常的开发中,如果是单个进程中对共享资源的访问,我们只需要⽤synchronized或者lock就能实现互斥操作。
zoonkeeper原理
Zookeeper是一个分布式的协调服务,它可以管理大规模的集群,并为分布式应用程序提供一致性、可靠性和高效性的服务。
Zookeeper 的基本原理是通过维护一个树形结构的数据模型来存储和管理分布
式应用程序的元数据信息,同时提供一系列的原子操作,实现分布式应用程序之间的同步、协调和管理。
在Zookeeper中,数据模型被组织为一个类似于文件系统的树形结构,每个节点都可以存储数据和子节点。
Zookeeper通过提供一系列的API,允许分布式应用程序对这个数据模型进行读写操作,同时,Zookeeper也会监控这个数据模型的变化,并将这些变化通知给注册了相关事件的应用程序。
针对分布式应用程序需要实现的一些核心功能,Zookeeper提供了一些高级抽象概念,例如锁、队列和选举。
这些抽象概念都是基于数据模型的节点实现的,通过这些抽象概念,Zookeeper使得分布式应用程序可以实现更高层次的协同工作。
除了数据存储和高级抽象概念,Zookeeper还具备高度的可靠性和容错性。
Zookeeper使用ZAB协议来实现主从复制,使得即使某个节点宕机,整个系统依然可以正常工作。
同时,Zookeeper还提供了多种方式来保证其可靠性,例如数据的持久化存储和节点之间的心跳检测等。
总之,Zookeeper是一个非常重要的分布式协调服务,它可以为分布式应用程序提供一致性、可靠性和高效性的支持。
对于需要实现
分布式协同工作的应用程序而言,Zookeeper是一个不可或缺的组件。
分布式锁的底层原理
分布式锁是分布式系统中常用的同步机制之一,它通过协调多个节点的操作,实现对共享资源的互斥访问。
分布式锁的底层原理就是基于分布式协议实现的。
通常,分布式锁的实现需要考虑以下几个方面:
1. 选举机制:在分布式系统中,多个节点之间需要选举一个节点作为锁的持有者。
选举机制需要考虑节点的可用性、网络延迟等因素。
2. 超时机制:为了避免锁的持有者挂掉或者网络延迟等原因导致锁无法释放,需要设置一个超时机制,当锁的持有者长时间没有释放锁时,其他节点可以尝试获取锁。
3. 锁的实现:锁的实现可以是基于缓存、数据库等方式。
在缓存中实现锁通常比在数据库中实现锁效率更高,但是缓存的可靠性和持久性比数据库低。
4. 锁的管理:在分布式系统中,需要对锁进行管理,包括锁的创建、获取、释放等操作。
同时还需要考虑锁的可重入性、死锁等问题。
总的来说,分布式锁的底层原理就是利用分布式协议实现多个节点之间的同步和协调,保证共享资源的互斥访问。
在实际应用中,需要根据具体场景选择不同的实现方式和策略,以达到最优的效果。
- 1 -。
ZooKeeper 的工作原理1. 简介ZooKeeper(简称zk)是一个分布式的开源协调服务,它提供了高可用性、高性能、顺序一致性和持久性的数据存储。
它被广泛应用于分布式系统中,用于解决分布式系统中的一致性问题。
ZooKeeper 的基本原理是通过共享状态来实现协调和同步。
它提供了一个类似文件系统的数据模型,可以存储和管理分布式应用程序所需的数据。
ZooKeeper 提供了一组原子操作,可以对这些数据进行读写操作,并且保证这些操作是顺序一致的。
2. 数据模型ZooKeeper 的数据模型类似于一个层次化的文件系统,由多个节点(Node)组成。
每个节点都有一个路径标识符(Path),以斜杠(/)作为路径分隔符。
根节点为“/”,其他节点通过路径标识符来表示其在层次结构中的位置。
每个节点可以存储一个小于1MB大小的数据,以及一些元数据信息。
除了普通节点外,还有两种特殊类型的节点:•持久节点(Persistent Node):创建后会一直存在,直到被显式删除。
•临时节点(Ephemeral Node):当创建该节点的客户端会话结束后,该节点会被自动删除。
3. 原子操作ZooKeeper 提供了一组原子操作,用于对数据进行读写和监听:•创建节点(create):创建一个新节点,并为其设置初始值。
•读取数据(getData):获取指定节点的数据内容。
•更新数据(setData):更新指定节点的数据内容。
•删除节点(delete):删除指定的节点。
•获取子节点列表(getChildren):获取指定节点的子节点列表。
•监听器(Watcher):可以为指定的节点设置一个监听器,当该节点发生变化时,客户端会收到通知。
4. 集群架构ZooKeeper 通过将数据存储在多个服务器上来实现高可用性和容错性。
它采用了一种主从复制的方式进行数据复制和同步。
集群中的每个服务器可以承担三种角色中的一种:•Leader(领导者):负责处理所有客户端请求,并协调其他服务器之间的同步。
利用ZooKeeper简单实现分布式锁下面讲解下怎么利用ZooKeeper简单实现分布式锁,对于zk的安装和简单使用请参考我的文章:Hadoop集群之ZooKeeper和Hbase环境搭建1.分布式锁的由来:在程序开发过程中不得不考虑的就是并发问题。
在java中对于同一个jvm而言,jdk已经提供了lock和同步等。
但是在分布式情况下,往往存在多个进程对一些资源产生竞争关系,而这些进程往往在不同的机器上,这个时候jdk中提供的已经不能满足。
分布式锁顾明思议就是可以满足分布式情况下的并发锁。
下面我们讲解怎么利用zk实现分布式锁。
2.实现思路:2.1 zk简单介绍:ZooKeeper是Apache软件基金会的一个软件项目,他为大型分布式计算提供开源的分布式配置服务、同步服务和命名注册。
在ZooKeeper 中,节点类型可以分为持久节点(PERSISTENT )、临时节点(EPHEMERAL),以及时序节点(SEQUENTIAL ),具体在节点创建过程中,一般是组合使用,可以生成4 种节点类型:持久节点(PERSISTENT),持久顺序节点(PERSISTENT_SEQUENTIAL),临时节点(EPHEMERAL),临时顺序节点(EPHEMERAL_SEQUENTIAL);具体节点含义,谷歌之。
2.2 利用zk实现:当很多进程需要访问共享资源时,我们可以通过zk来实现分布式锁。
主要步骤是:1.建立一个节点,假如名为:lock 。
节点类型为持久节点(PERSISTENT)2.每当进程需要访问共享资源时,会调用分布式锁的lock()或tryLock()方法获得锁,这个时候会在第一步创建的lock节点下建立相应的顺序子节点,节点类型为临时顺序节点(EPHEMERAL_SEQUENTIAL),通过组成特定的名字name+lock+顺序号。
3.在建立子节点后,对lock下面的所有以name开头的子节点进行排序,判断刚刚建立的子节点顺序号是否是最小的节点,假如是最小节点,则获得该锁对资源进行访问。
ZooKeeper的三种典型应⽤场景引⾔ ZooKeeper是中典型的pub/sub模式的分布式数据管理与协调框架,开发⼈员可以使⽤它进⾏分布式数据的发布与订阅。
另外,其丰富的数据节点类型可以交叉使⽤,配合Watcher事件通知机制,可以应⽤于分布式都会涉及的⼀些核⼼功能:数据发布/订阅、Master选举、命名服务、分布式协调/通知、集群管理、分布式锁、分布式队列等。
本博⽂主要介绍:发布/订阅、分布式锁、Master选举三种最常⽤的场景 本⽂中的代码⽰例均是由Curator客户端编写的,已经对ZooKeeper原⽣API做好很多封装。
参考资料《从Paxos到Zookeeper 分布式⼀致性原理与实践》(有需要电⼦PDF的朋友,可以评论私信我)⼀、数据发布/订阅1、基本概念(1)数据发布/订阅系统即所谓的配置中⼼,也就是发布者将数据发布到ZooKeeper的⼀个节点或者⼀系列节点上,提供订阅者进⾏数据订阅,从⽽实现动态更新数据的⽬的,实现配置信息的集中式管理和数据的动态更新。
ZooKeeper采⽤的是推拉相结合的⽅式:客户端向服务器注册⾃⼰需要关注的节点,⼀旦该节点的数据发⽣改变,那么服务端就会向相应的客户端发送Wacher事件通知,客户端接收到消息通知后,需要主动到服务端获取最新的数据。
(2)实际系统开发过程中:我们可以将初始化配置信息放到节点上集中管理,应⽤在启动时都会主动到ZooKeeper服务端进⾏⼀次配置读取,同时在指定节点注册Watcher监听,主要配置信息⼀旦变更,订阅者就可以获取读取最新的配置信息。
通常系统中需要使⽤⼀些通⽤的配置信息,⽐如机器列表信息、运⾏时的开关配置、数据库配置信息等全局配置信息,这些都会有以下3点特性: 1) 数据量通常⽐较⼩(通常是⼀些配置⽂件) 2) 数据内容在运⾏时会经常发⽣动态变化(⽐如数据库的临时切换等) 3) 集群中各机器共享,配置⼀致(⽐如数据库配置共享)。
zookeeper实现原理Zookeeper(动物园管理员)是一个分布式服务框架,提供分布式系统的强一致性、高可用性的支持,可以实现诸如分布式锁、分布式协调、分布式配置管理等功能。
Zookeeper的核心是一个分布式协调服务,它维护了一个分布式数据结构——Znode (Zookeeper节点),以及所有的客户端和服务端的会话和状态信息。
Znode是Zookeeper 中最基本的数据单元,可以被认为是一个文件或目录,支持创建、修改、删除等基本操作,还支持访问ACL(访问控制列表)和Watch(监视器)等机制。
Zookeeper的实现原理基于Paxos算法以及Zab协议。
Paxos算法是一种分布式一致性算法,其核心是要求所有参与者达成一致,确定一个值,具有高可用性和良好的扩展性。
Zab协议是为了Zookeeper的实际应用场景而设计的一种分布式协议,它维护了一个主节点和多个从节点的关系,并且保证了数据的一致性和高可用性。
Zookeeper的核心模块包括:客户端模块、服务端模块和选举模块。
客户端模块用于和Zookeeper服务器进行通信,负责实现分布式服务的应用逻辑。
服务端模块用于实现分布式协调服务,负责维护Znode的数据结构、会话和状态信息。
选举模块用于选举主节点,保证分布式系统的高可用性。
在Zookeeper中,主从节点的划分是通过选举过程实现的。
每个服务端启动时都会参与选举,参与选举的服务端称为投票者,投票者通过通信协议将自己的信息发送给其他服务端,以便进行投票。
每个投票者会根据预定义的算法进行投票,并选出一个主节点。
如果主节点宕机或者与其他从节点失去联系,其他从节点会重新发起选举,选择一个新的主节点。
通过主从节点的协调,Zookeeper实现了一种高效的分布式锁和分布式协调机制。
对于分布式锁,Zookeeper可以通过竞争Znode的创建和删除来实现锁定和解锁,锁定过程中所有以该Znode为标识的客户端都等待解锁。
分布式锁(Zookeeper实现)分布式锁分布式锁,这个主要得益于 ZooKeeper 为我们保证了数据的强⼀致性。
锁服务可以分为两类,⼀个是保持独占,另⼀个是控制时序。
1. 所谓保持独占,就是所有试图来获取这个锁的客户端,最终只有⼀个可以成功获得这把锁。
通常的做法是把 zk 上的⼀个 znode 看作是⼀把锁,通过 create znode 的⽅式来实现。
所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁。
2. 控制时序,就是所有视图来获取这个锁的客户端,最终都是会被安排执⾏,只是有个全局时序了。
做法和上⾯基本类似,只是这⾥ /distributelock 已经预先存在,客户端在它下⾯创建临时有序节点(这个可以通过节点的属性控制:CreateMode.EPHEMERALSEQUENTIAL 来指定)。
Zk 的⽗节点(/distribute_lock)维持⼀份 sequence, 保证⼦节点创建的时序性,从⽽也形成了每个客户端的全局时序。
分布式锁单纯的Lock锁或者synchronize只能解决单个jvm线程安全问题分布式 Session ⼀致性问题分布式全局id(也可以使⽤分布式锁)分布式锁,产⽣的原因是集群在单台服务器上如何⽣成订单号(保证唯⼀),⽅案 UUid+时间戳⽅式, redis⽅式⽣成订单号,秒杀抢购时候,⾸先预测100w订单号,⽣成放在redis。
客户端下单,直接redis去获取即可。
因为redis单线程的,多个线程去获取时候,安全呀。
实际150w⽤户。
当redis剩下50w订单号时候,继续⽣成补充之。
如果在集群情况,UUid+时间戳。
不能保证唯⼀性!,原因:如果单台:uuid+时间戳,⽣成的代码逻辑:package com.toov5.Lock;import java.text.SimpleDateFormat;import java.util.Date;//⽣成订单号时间戳public class OrderNumGenerator {//区分不同的订单号private static int count = 0;//单台服务器,多个线程同事⽣成订单号public String getNumber(){try {Thread.sleep(300);} catch (Exception e) {// TODO: handle exception}SimpleDateFormat simpt = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");return simpt.format(new Date()) + "-" + ++count; //时间戳后⾯加了 count}}开启100个线程调⽤之:package com.toov5.Lock;public class OrderService implements Runnable {private OrderNumGenerator orderNumGenerator = new OrderNumGenerator(); //定义成全局的public void run() {getNumber();}public void getNumber(){String number = orderNumGenerator.getNumber();System.out.println(Thread.currentThread().getName()+"num"+number);}public static void main(String[] args) {OrderService orderService = new OrderService();for (int i = 0; i <100; i++) { //开启100个线程new Thread(orderService).start();}}}结果:多个线程共享区同⼀个全局变量,线程安全问题!解决⽅案就是加锁嘛!或者使⽤ lock锁也可以public class OrderService implements Runnable {private OrderNumGenerator orderNumGenerator = new OrderNumGenerator();// 使⽤lock锁private java.util.concurrent.locks.Lock lock = new ReentrantLock();public void run() {getNumber();}public void getNumber() {try {// synchronized (this) {lock.lock();String number = orderNumGenerator.getNumber();System.out.println(Thread.currentThread().getName() + ",⽣成订单ID:" + number);// }} catch (Exception e) {} finally {lock.unlock();}}public static void main(String[] args) {System.out.println("####⽣成唯⼀订单号###");OrderService orderService = new OrderService();for (int i = 0; i < 100; i++) {new Thread(orderService).start();}}}如果是集群环境下:每台jvm都有⼀个 count 都有⾃增的代码操作这个 count 三个不同的jvm 独⽴的⽤户请求过来映射到哪个就操作哪个这时候就产⽣分布式锁的问题这时候需要分布式锁:共享⼀个countjvm1 操作时候其他的jvm2 和 jvm3 不可以操作他!分布式锁保证分布式领域中共享数据安全问题1、数据库实现(效率低,不推荐)2、redis实现(使⽤redission实现,但是需要考虑思索,释放问题。
zookeeper案例Zookeeper是一个开源的分布式协调服务,主要用于构建可靠的分布式系统。
它提供了一个简单的分层命名空间,并通过对命名空间的读写操作,来协调分布式系统中各个节点之间的状态同步。
下面我将为大家介绍两个实际应用中使用Zookeeper的案例。
案例一:分布式锁在分布式系统中,往往需要保证某个共享资源在同一时间只能被一个节点访问修改。
这就需要使用分布式锁来实现。
而Zookeeper正是为了解决这类问题而诞生的。
使用Zookeeper实现分布式锁的步骤如下:第一步,节点尝试在Zookeeper的指定路径下创建临时顺序节点。
第二步,节点获取指定路径下所有子节点列表,并判断自己是否是最小的节点。
若是,则节点获得锁,否则监听自己前一个节点,等待其删除。
第三步,节点完成任务后,删除自己创建的临时节点,释放锁。
通过这种方式,Zookeeper可以实现高效可靠的分布式锁,确保同一时间只有一个节点可以访问共享资源。
案例二:配置管理在分布式系统中,各个节点的配置一致性是非常重要的。
而Zookeeper可以用作配置管理的中心节点。
使用Zookeeper进行配置管理的步骤如下:第一步,节点将配置信息写入Zookeeper的指定路径。
第二步,其他节点通过监听指定路径,实现配置信息的实时更新。
第三步,节点在配置信息更新时,按照新的配置进行相应的业务逻辑操作。
通过这种方式,Zookeeper可以实现分布式系统的配置一致性管理,确保各个节点使用最新的配置信息。
总结Zookeeper作为一个分布式协调服务,可以应用于各种复杂的分布式系统中。
从以上两个案例可以看出,Zookeeper能够通过提供简单的命名空间和读写操作,实现分布式锁和配置管理等功能。
通过Zookeeper的分布式锁,我们可以有效地解决多个节点在访问共享资源时的冲突问题,确保数据的一致性和正确性。
而Zookeeper的配置管理功能可以帮助我们实现分布式系统中各个节点的配置一致性,确保系统的正常运行。