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

分布式环境中大多数服务是允许部分失败,也允许数据不一致,但有些最基础的服务是需要高可靠性,高一致性的,这些服务是其他分布式服务运转的基础,比如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的配置文件,内容填写如下:

[xhtml] view plaincopy

  1. # The number of milliseconds of each tick
  2. tickTime=2000
  3. # The number of ticks that the initial
  4. # synchronization phase can take
  5. initLimit=10
  6. # The number of ticks that can pass between
  7. # sending a request and getting an acknowledgement
  8. syncLimit=5
  9. # the directory where the snapshot is stored.
  10. dataDir=/home/admin/zookeeper-3.2.2/data
  11. # the port at which the clients will connect
  12. clientPort=2181
  13. server.1=zoo1:2888:3888
  14. 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这个类即可,具体测试代码如下:

[java] view plaincopy

  1. public static void main(String[] args) {
  2. try {
  3. ZooKeeper zk = new ZooKeeper("10.20.147.35:2181", 30000, null);
  4. String name = zk.create("/company", "alibaba".getBytes(),
  5. Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
  6. Stat stat = new Stat();
  7. System.out.println(new String(zk.getData(name, null, stat)));
  8. zk.setData(name, "taobao".getBytes(), stat.getVersion(), null, null);
  9. System.out.println(new String(zk.getData(name, null, stat)));
  10. stat = zk.exists(name, null);
  11. zk.delete(name, stat.getVersion(), null, null);
  12. System.out.println(new String(zk.getData(name, null, stat)));
  13. } catch (Exception e) {
  14. e.printStackTrace();
  15. }
  16. }

以上代码比较简单,查看一下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的实例代码如下所示:

[java] view plaincopy

  1. /**
  2. * Removes the head of the queue and returns it, blocks until it succeeds.
  3. * @return The former head of the queue
  4. * @throws NoSuchElementException
  5. * @throws KeeperException
  6. * @throws InterruptedException
  7. */
  8. public byte[] take() throws KeeperException, InterruptedException {
  9. TreeMap<Long,String> orderedChildren;
  10. // Same as for element.  Should refactor this.
  11. while(true){
  12. LatchChildWatcher childWatcher = new LatchChildWatcher();
  13. try{
  14. orderedChildren = orderedChildren(childWatcher);
  15. }catch(KeeperException.NoNodeException e){
  16. zookeeper.create(dir, new byte[0], acl, CreateMode.PERSISTENT);
  17. continue;
  18. }
  19. if(orderedChildren.size() == 0){
  20. childWatcher.await();
  21. continue;
  22. }
  23. for(String headNode : orderedChildren.values()){
  24. String path = dir +"/"+headNode;
  25. try{
  26. byte[] data = zookeeper.getData(path, false, null);
  27. zookeeper.delete(path, -1);
  28. return data;
  29. }catch(KeeperException.NoNodeException e){
  30. // Another client deleted the node first.
  31. }
  32. }
  33. }
  34. }
  35. /**
  36. * Inserts data into queue.
  37. * @param data
  38. * @return true if data was successfully added
  39. */
  40. public boolean offer(byte[] data) throws KeeperException, InterruptedException{
  41. for(;;){
  42. try{
  43. zookeeper.create(dir+"/"+prefix, data, acl, CreateMode.PERSISTENT_SEQUENTIAL);
  44. return true;
  45. }catch(KeeperException.NoNodeException e){
  46. zookeeper.create(dir, new byte[0], acl, CreateMode.PERSISTENT);
  47. }
  48. }
  49. }

3)分布式lock

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

时间: 2024-11-05 03:54:30

分布式设计与开发(三)------高一致性服务ZooKeeper的相关文章

分布式设计与开发(一)------宏观概述

在IDF05(Intel Developer Forum 2005)上,Intel首席执行官Craig Barrett就取消4GHz芯片计划一事,半开玩笑当众单膝下跪致歉,给广大软件开发者一个明显的信号,单纯依靠垂直提升硬件性能来提高系统性能的时代 已结束,分布式开发的时代实际上早已悄悄地成为了时代的主流,吵得很热的云计算实际上只是包装在分布式之外的商业概念,很多开发者(包括我)都想加入研究 云计算这个潮流,在google上通过“云计算”这个关键词来查询资料,查到的都是些概念性或商业性的宣传资料

分布式进阶(十七)分布式设计介绍

分布式设计介绍 前言 分布式设计与开发在IDF05(Intel Developer Forum 2005)上,Intel首席执行官Craig Barrett就取消4GHz芯片计划一事,半开玩笑当众单膝下跪致歉,给广大软件开发者一个明显的信号,单纯依靠垂直提升硬件性能来提高系统性能的时代已结束,分布式开发的时代实际上早已悄悄地成为了时代的主流,吵得很热的云计算实际上只是包装在分布式之外的商业概念,很多开发者(包括我)都想加入研究云计算这个潮流,在google上通过"云计算"这个关键词来查

java架构师课程、性能调优、高并发、tomcat负载均衡、大型电商项目实战、高可用、高可扩展、数据库架构设计、Solr集群与应用、分布式实战、主从复制、高可用集群、大数据

15套Java架构师详情 * { font-family: "Microsoft YaHei" !important } h1 { background-color: #006; color: #FF0 } 15套java架构师.集群.高可用.高可扩展.高性能.高并发.性能优化.Spring boot.Redis.ActiveMQ.Nginx.Mycat.Netty.Jvm大型分布式项目实战视频教程 视频课程包含: 高级Java架构师包含:Spring boot.Spring  clo

百万级高并发WebRTC流媒体服务器设计与开发

第1章 课程导学与准备工作本章主要介绍为何要学习WebRTC流媒体服务器开发,以及本门课能为我们带来哪些收获.之后会为大家介绍本课程内容具体安排,最后给出如何学好这门课程的一些学习建议.希望大家都能通过这门课程,学有所成,学有所归. 第2章 C++语言基础回顾[已掌握,可略过]为了便于大家更好的学习流媒体服务器的开发,本章将带大家对WebRTC服务器开发中用到的C++基础知识进行回顾梳理,如类的定义与使用,继承,多态,名存空间等相关知识. 第3章 服务器基础编程本章将带你学习最基础的服务器开发,

百万级高并发WebRTC流媒体服务器设计与开发教程云

百万级高并发WebRTC流媒体服务器设计与开发 资源获取链接:点击获取完整教程 百万级高并发WebRTC流媒体服务器设计与开发 5G时代音视频为王,随着实时音视频应用的爆发,来自Google 的WebRTC成为了人们关注的焦点,但很多人却不知道如何使用WebRTC实现多人实时互动,本课就将围绕与浏览器互通.级联.可扩展等6大痛点手把手带你学习大负载.高并发.高性能 WebRTC 流媒体服务器的设计与开发,揭秘万人互动直播背后的深层奥秘,打造可负载百万用户量的企业级的流媒体服务器 播答题的核心需求

WCF分布式开发步步为赢(3)WCF服务元数据交换、配置及编程开发

今天我们继续WCF分布式开发步步为赢(3)WCF服务元数据交换.配置及编程开发的学习.经过前面两节的学习,我们了解WCF分布式开发的相关的基本的概念和自定义宿主托管服务的完整的开发和配置过程.今天我们来详细学习WCF服务元数据交换的相关内容.WCF服务元数据究竟是什么?为什么WCF服务要暴露元数据交换节点?这些和以前的Web Service有什么关系?WCF服务元数据交换的方式有那些?我们如何实现WCF服务元数据交换,本节我们会详细讲解.全文结构如下:[1]WCF服务元数据的基本概念.[2]WC

了解如何设计和开发基于Http请求的数据接口服务系统

如今互联网的蓬勃发展离不开Http这个应用层面上的网络通信协议的诞生和发展,在经历着信息技术时代,到现在"数据时代"一词屡见不鲜之后,可以洞悉数据在影响着我们生活,昨晚在下载百度地图的离线数据包就发现,广州市的离线数据包明显大于全国其它市区不少. 数据作为一种服务已成常态,比如:12306火车票查询数据接口,商标信息服务接口,甚至车辆违章高发路段数据接口,这些数据来自各行各业并且通过数据接口服务提供给更多需要的人或信息系统. 本文主要介绍如何设计和开发数据接口服务系统,主要涉及到数据接

如何基于 k8s 开发高可靠服务?容器云牛人有话说

?? k8s 是当前主流的容器编排服务,它主要解决「集群环境」下「容器化应用」的「管理问题」,主要包括如下几方面:?? 容器集群管理 编排? 调度? 访问? ? 基础设施管理 计算资源? 网络资源? 存储资源?? k8s 的强大依赖于它良好的设计理念和抽象,吸引了越来越多的开发者投入到 k8s 社区,把 k8s 作为基础设施运行服务的公司也逐步增多.?在设计理念方面,k8s 只有 APIServer 与 etcd (存储) 通信,其他组件在内存中维护状态,通过 APIServer 持久化数据.管

WCF分布式开发步步为赢(13):WCF服务离线操作与消息队列MSMQ

之前曾经写过一个关于MSMQ消息队列的文章:WCF分布式开发必备知识(1):MSMQ消息队列 ,当时的目的也是用它来作为学习WCF 消息队列MSMQ编程的基础文章.在那篇文章里,我们详细介绍了MSMQ消息队列的基本概念.安装.部署.开发.调试等相关问题.今天我们来学习WCF分布式开发步步为赢(13):WCF服务离线操作与消息队列MSMQ.在WCF框架下使用MSMQ消息队列服务编程.  这里我会给出一个使用WCF MSMQ实现离线请求的DEMO示例程序. 全文结构是:[1]MSMQ基本概念[2]W