分布式设计与开发(三)------高一致性服务ZooKeeper

本文涉及的产品
任务调度 XXL-JOB 版免费试用,400 元额度,开发版规格
注册配置 MSE Nacos/ZooKeeper,182元/月
MSE Nacos/ZooKeeper 企业版试用,1600元额度,限量50份
简介:
分布式环境中大多数服务是允许部分失败,也允许数据不一致,但有些最基础的服务是需要高可靠性,高一致性的,这些服务是其他分布式服务运转的基础,比如naming service、分布式lock等,这些分布式的基础服务有以下要求:
  • 高可用性
  • 高一致性
  • 高性能
对于这种有些挑战CAP原则的服务该如何设计,是一个挑战,也是一个不错的研究课题,Apache的ZooKeeper也许给了我们一个不错的答案。ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,它暴露了一个简单的原语集,分布式应用程序可以基于它实现同步服务,配置维护和命名服务等。关于ZooKeeper更多信息可以参见官方文档
ZooKeeper的基本使用
搭一个分布式的ZooKeeper环境比较简单,基本步骤如下:
1)在各服务器安装ZooKeeper
下载ZooKeeper后在各服务器上进行解压即可
tar -xzf zookeeper-3.2.2.tar.gz
2)配置集群环境
分别各服务器的zookeeper安装目录下创建名为zoo.cfg的配置文件,内容填写如下:
  • # The number of milliseconds of each tick
  • tickTime=2000
  • # The number of ticks that the initial
  • # synchronization phase can take
  • initLimit=10
  • # The number of ticks that can pass between
  • # sending a request and getting an acknowledgement
  • syncLimit=5
  • # the directory where the snapshot is stored.
  • dataDir=/home/admin/zookeeper-3.2.2/data
  • # the port at which the clients will connect
  • clientPort=2181
  • server.1=zoo1:2888:3888
  • server.2=zoo2:2888:3888

其中zoo1和zoo2分别对应集群中各服务器的机器名或ip,server.1和server.2中1和2分别对应各服务器的zookeeper id,id的设置方法为在dataDir配置的目录下创建名为myid的文件,并把id作为其文件内容即可,在本例中就分为设置为1和2。其他配置具体含义可见官方文档。
3)启动集群环境
分别在各服务器下运行zookeeper启动脚本
/home/admin/zookeeper-3.2.2/bin/zkServer.sh start
4)应用zookeeper
应用zookeeper可以在是shell中执行命令,也可以在java或c中调用程序接口。
在shell中执行命令,可运行以下命令:
bin/zkCli.sh -server 10.20.147.35:2181
其中10.20.147.35为集群中任一台机器的ip或机器名。执行后可进入zookeeper的操作面板,具体如何操作可见官方文档
在java中通过调用程序接口来应用zookeeper较为复杂一点,需要了解watch和callback等概念,不过试验最简单的CURD倒不需要这些,只需要使用ZooKeeper这个类即可,具体测试代码如下:
  • public
    static
    void main(String[] args) {
  •     try {
  •         ZooKeeper zk = new ZooKeeper("10.20.147.35:2181", 30000, null);
  •         String name = zk.create("/company", "alibaba".getBytes(),
  •                 Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
  •         Stat stat = new Stat();
  •         System.out.println(new String(zk.getData(name, null, stat)));
  •         zk.setData(name, "taobao".getBytes(), stat.getVersion(), null, null);
  •         System.out.println(new String(zk.getData(name, null, stat)));
  •         stat = zk.exists(name, null);
  •         zk.delete(name, stat.getVersion(), null, null);
  •         System.out.println(new String(zk.getData(name, null, stat)));
  •     } catch (Exception e) {
  •         e.printStackTrace();
  •     }
  • }

以上代码比较简单,查看一下zooKeeper的api doc就知道如何使用了
ZooKeeper的实现机理
ZooKeeper的实现机理是我看过的开源框架中最复杂的,它的解决是分布式环境中的一致性问题,这个场景也决定了其实现的复杂性。看了两三天的源码还是有些摸不着头脑,有些超出了我的能力,不过通过看文档和其他高人写的文章大致清楚它的原理和基本结构。
1)ZooKeeper的基本原理
ZooKeeper是以Fast Paxos算法为基础的,在前一篇blog中大致介绍了一下paxos,而没有提到的是paxos存在活锁的问题,也就是当有多个proposer交错提交时,有可能互相排斥导致没有一个proposer能提交成功,而Fast Paxos作了一些优化,通过选举产生一个leader,只有leader才能提交propose,具体算法可见Fast Paxos。因此,要想弄得ZooKeeper首先得对Fast Paxos有所了解。
2)ZooKeeper的基本运转流程
ZooKeeper主要存在以下两个流程:
  • 选举Leader
  • 同步数据
选举Leader过程中算法有很多,但要达到的选举标准是一致的:
  • Leader要具有最高的zxid
  • 集群中大多数的机器得到响应并follow选出的Leader
同步数据这个流程是ZooKeeper的精髓所在,并且就是Fast Paxos算法的具体实现。一个牛人画了一个ZooKeeper数据流动图,比较直观地描述了ZooKeeper是如何同步数据的。
 
以上两个核心流程我暂时还不能悟透其中的精髓,这也和我还没有完全理解Fast Paxos算法有关,有待后续深入学习
ZooKeeper的应用领域
Tim在blog中提到了Paxos所能应用的几个主要场景,包括database replication、naming service、config配置管理、access control list等等,这也是ZooKeeper可以应用的几个主要场景。此外,ZooKeeper官方文档中提到了几个更为基础的分布式应用,这也算是ZooKeeper的妙用吧
1)分布式Barrier
Barrier是一种控制和协调多个任务触发次序的机制,简单说来就是搞个闸门把欲执行的任务给拦住,等所有任务都处于可以执行的状态时,才放开闸门。它的机理可以见下图所示:
 
在单机上JDK提供了CyclicBarrier这个类来实现这个机制,但在分布式环境中JDK就无能为力了。在分布式里实现Barrer需要高一致性做保障,因此ZooKeeper可以派上用场,所采取的方案就是用一个Node作为Barrer的实体,需要被Barrer的任务通过调用exists()检测这个Node的存在,当需要打开Barrier的时候,删掉这个Node,ZooKeeper的watch机制会通知到各个任务可以开始执行。
2)分布式Queue
与Barrier类似分布式环境中实现Queue也需要高一致性做保障,ZooKeeper提供了一个种简单的方式,ZooKeeper通过一个Node来维护Queue的实体,用其children来存储Queue的内容,并且ZooKeeper的create方法中提供了顺序递增的模式,会自动地在name后面加上一个递增的数字来插入新元素。可以用其children来构建一个queue的数据结构,offer的时候使用create,take的时候按照children的顺序删除第一个即可。ZooKeeper保障了各个server上数据是一致的,因此也就实现了一个分布式Queue。take和offer的实例代码如下所示:
  • /**
  • * Removes the head of the queue and returns it, blocks until it succeeds.
  • * @return The former head of the queue
  • * @throws NoSuchElementException
  • * @throws KeeperException
  • * @throws InterruptedException
  • */
  • public
    byte[] take() throws KeeperException, InterruptedException {
  •     TreeMap<Long,String> orderedChildren;
  •     // Same as for element.  Should refactor this.
  •     while(true){
  •         LatchChildWatcher childWatcher = new LatchChildWatcher();
  •         try{
  •             orderedChildren = orderedChildren(childWatcher);
  •         }catch(KeeperException.NoNodeException e){
  •             zookeeper.create(dir, new
    byte[0], acl, CreateMode.PERSISTENT);
  •             continue;
  •         }
  •         if(orderedChildren.size() == 0){
  •             childWatcher.await();
  •             continue;
  •         }
  •         for(String headNode : orderedChildren.values()){
  •             String path = dir +"/"+headNode;
  •             try{
  •                 byte[] data = zookeeper.getData(path, false, null);
  •                 zookeeper.delete(path, -1);
  •                 return data;
  •             }catch(KeeperException.NoNodeException e){
  •                 // Another client deleted the node first.
  •             }
  •         }
  •     }
  • }
  • /**
  • * Inserts data into queue.
  • * @param data
  • * @return true if data was successfully added
  • */
  • public
    boolean offer(byte[] data) throws KeeperException, InterruptedException{
  •     for(;;){
  •         try{
  •             zookeeper.create(dir+"/"+prefix, data, acl, CreateMode.PERSISTENT_SEQUENTIAL);
  •             return
    true;
  •         }catch(KeeperException.NoNodeException e){
  •             zookeeper.create(dir, newbyte[0], acl, CreateMode.PERSISTENT);
  •         }
  •     }
  • }

3)分布式lock

利用ZooKeeper实现分布式lock,主要是通过一个Node来代表一个Lock,当一个client去拿锁的时候,会在这个Node下创建一个自增序列的child,然后通过getChildren()方式来check创建的child是不是最靠前的,如果是则拿到锁,否则就调用exist()来check第二靠前的child,并加上watch来监视。当拿到锁的child执行完后归还锁,归还锁仅仅需要删除自己创建的child,这时watch机制会通知到所有没有拿到锁的client,这些child就会根据前面所讲的拿锁规则来竞争锁。



本文转自夜&枫博客园博客,原文链接:http://www.cnblogs.com/newstart/archive/2012/05/24/2516798.html,如需转载请自行联系原作者

相关文章
|
2月前
|
数据采集 监控 NoSQL
优化分布式采集的数据同步:一致性、去重与冲突解决的那些坑与招
本文讲述了作者在房地产数据采集项目中遇到的分布式数据同步问题,通过实施一致性、去重和冲突解决的“三板斧”策略,成功解决了数据重复和同步延迟问题,提高了系统稳定性。核心在于时间戳哈希保证一致性,URL归一化和布隆过滤器确保去重,分布式锁解决写入冲突。
149 2
 优化分布式采集的数据同步:一致性、去重与冲突解决的那些坑与招
|
2月前
|
消息中间件 运维 监控
《聊聊分布式》BASE理论 分布式系统可用性与一致性的工程平衡艺术
BASE理论是对CAP定理中可用性与分区容错性的实践延伸,通过“基本可用、软状态、最终一致性”三大核心,解决分布式系统中ACID模型的性能瓶颈。它以业务为导向,在保证系统高可用的同时,合理放宽强一致性要求,并借助补偿机制、消息队列等技术实现数据最终一致,广泛应用于电商、社交、外卖等大规模互联网场景。
|
2月前
|
消息中间件 分布式计算 资源调度
《聊聊分布式》ZooKeeper与ZAB协议:分布式协调的核心引擎
ZooKeeper是一个开源的分布式协调服务,基于ZAB协议实现数据一致性,提供分布式锁、配置管理、领导者选举等核心功能,具有高可用、强一致和简单易用的特点,广泛应用于Kafka、Hadoop等大型分布式系统中。
|
8月前
|
人工智能 安全 Java
智慧工地源码,Java语言开发,微服务架构,支持分布式和集群部署,多端覆盖
智慧工地是“互联网+建筑工地”的创新模式,基于物联网、移动互联网、BIM、大数据、人工智能等技术,实现对施工现场人员、设备、材料、安全等环节的智能化管理。其解决方案涵盖数据大屏、移动APP和PC管理端,采用高性能Java微服务架构,支持分布式与集群部署,结合Redis、消息队列等技术确保系统稳定高效。通过大数据驱动决策、物联网实时监测预警及AI智能视频监控,消除数据孤岛,提升项目可控性与安全性。智慧工地提供专家级远程管理服务,助力施工质量和安全管理升级,同时依托可扩展平台、多端应用和丰富设备接口,满足多样化需求,推动建筑行业数字化转型。
287 5
|
6月前
|
监控 算法 关系型数据库
分布式事务难题终结:Seata+DRDS全局事务一致性架构设计
在分布式系统中,CAP定理限制了可用性、一致性与分区容错的三者兼得,尤其在网络分区时需做出取舍。为应对这一挑战,最终一致性方案成为常见选择。以电商订单系统为例,微服务化后,原本的本地事务演变为跨数据库的分布式事务,暴露出全局锁失效、事务边界模糊及协议差异等问题。本文深入探讨了基于 Seata 与 DRDS 的分布式事务解决方案,涵盖 AT 模式实践、分片策略优化、典型问题处理、性能调优及高级特性实现,结合实际业务场景提供可落地的技术路径与架构设计原则。通过压测验证,该方案在事务延迟、TPS 及失败率等方面均取得显著优化效果。
345 61
|
7月前
|
安全 JavaScript 前端开发
HarmonyOS NEXT~HarmonyOS 语言仓颉:下一代分布式开发语言的技术解析与应用实践
HarmonyOS语言仓颉是华为专为HarmonyOS生态系统设计的新型编程语言,旨在解决分布式环境下的开发挑战。它以“编码创造”为理念,具备分布式原生、高性能与高效率、安全可靠三大核心特性。仓颉语言通过内置分布式能力简化跨设备开发,提供统一的编程模型和开发体验。文章从语言基础、关键特性、开发实践及未来展望四个方面剖析其技术优势,助力开发者掌握这一新兴工具,构建全场景分布式应用。
719 35
|
7月前
|
消息中间件 缓存 算法
分布式开发:数字时代的高性能架构革命-为什么要用分布式?优雅草卓伊凡
分布式开发:数字时代的高性能架构革命-为什么要用分布式?优雅草卓伊凡
342 0
分布式开发:数字时代的高性能架构革命-为什么要用分布式?优雅草卓伊凡
|
9月前
|
消息中间件 人工智能 监控
文生图架构设计原来如此简单之分布式服务
想象一下,当成千上万的用户同时要求AI画图,如何公平高效地处理这些请求?文生图/图生图大模型的架构设计看似复杂,实则遵循简单而有效的原则:合理排队、分工明确、防患未然。
346 14
文生图架构设计原来如此简单之分布式服务
|
11月前
|
SQL 分布式计算 DataWorks
MaxCompute MaxFrame评测 | 分布式Python计算服务MaxFrame(完整操作版)
在当今数字化迅猛发展的时代,数据信息的保存与分析对企业决策至关重要。MaxCompute MaxFrame是阿里云自研的分布式计算框架,支持Python编程接口、兼容Pandas接口并自动进行分布式计算。通过MaxCompute的海量计算资源,企业可以进行大规模数据处理、可视化数据分析及科学计算等任务。本文将详细介绍如何开通MaxCompute和DataWorks服务,并使用MaxFrame进行数据操作。包括创建项目、绑定数据源、编写PyODPS 3节点代码以及执行SQL查询等内容。最后,针对使用过程中遇到的问题提出反馈建议,帮助用户更好地理解和使用MaxFrame。
|
10月前
|
机器学习/深度学习 存储
DeepSeek进阶开发与应用4:DeepSeek中的分布式训练技术
随着深度学习模型和数据集规模的扩大,单机训练已无法满足需求,分布式训练技术应运而生。DeepSeek框架支持数据并行和模型并行两种模式,通过将计算任务分配到多个节点上并行执行,显著提高训练效率。本文介绍DeepSeek中的分布式训练技术,包括配置与启动方法,帮助用户轻松实现大规模模型训练。数据并行通过`MirroredStrategy`同步梯度,适用于大多数模型;模型并行则通过`ParameterServerStrategy`异步处理大模型。DeepSeek简化了分布式环境配置,支持单机多卡和多机多卡等场景。

热门文章

最新文章