﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-少年阿宾-随笔分类-zookeeper</title><link>http://blogjava.net/stevenjohn/category/54675.html</link><description>那些青春的岁月</description><language>zh-cn</language><lastBuildDate>Fri, 08 May 2015 16:30:03 GMT</lastBuildDate><pubDate>Fri, 08 May 2015 16:30:03 GMT</pubDate><ttl>60</ttl><item><title>Zookeeper 基本机制</title><link>http://www.blogjava.net/stevenjohn/archive/2015/05/08/424957.html</link><dc:creator>abin</dc:creator><author>abin</author><pubDate>Fri, 08 May 2015 14:10:00 GMT</pubDate><guid>http://www.blogjava.net/stevenjohn/archive/2015/05/08/424957.html</guid><wfw:comment>http://www.blogjava.net/stevenjohn/comments/424957.html</wfw:comment><comments>http://www.blogjava.net/stevenjohn/archive/2015/05/08/424957.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/stevenjohn/comments/commentRss/424957.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/stevenjohn/services/trackbacks/424957.html</trackback:ping><description><![CDATA[<div id="header"> <h1><span style="font-size: 14px;">实现</span></h1></div><div><div id="cnblogs_post_body"> <p>Zookeeper有两种运行模式：</p> <p>独立模式（standalone mode):只运行在一台服务器上，适合测试环境</p> <p>复制模式（replicated  mode)：运行于一个集群上，适合生产环境，这个计算机集群被称为一个&#8220;集合体&#8221;（ensemble）。Zookeeper通过复制来实现高可用性，只要集合体中半数以上的机器处于可用状态，它就能够保证服务继续。为什么一定要超过半数呢？这跟Zookeeper的复制策略有关：zookeeper确保对znode树的每一个修改都会被复制到集合体中超过半数的机器上。</p> <p>生产环境，zookeeper集群的服务器数目应该是奇数。</p> <h3>Zookeeper集群中的角色及其职责</h3> <p>领导者</p> <p>　　1.管理写请求</p> <p>跟随者</p> <p>　　1.响应客户端的读请求</p> <p>　　2.负责把客户端提交的写请求转发给领导者</p> <p>&nbsp;</p><p>znode的观察机制</p><p>&nbsp;</p><p>znode以某种方式发生变化时，&#8220;观察&#8221;（watch）机制可以让客户端得到通知。可以针对ZooKeeper服务的&#8220;操作&#8221;来设置观察，该服务的其他操作可以触发观察。比如，客户端可以对某个客户端调用exists操作，同时在它上面设置一个观察，如果此时这个znode不存在，则exists返回false，如果一段时间之后，这个znode被其他客户端创建，则这个观察会被触发，之前的那个客户端就会得到通知。<br /><br /></p><div>sync： 将客户端的znode视图与ZooKeeper同步</div><div>SYNC消息：返回SYNC结果到客户端，这个消息最初由客户端发起，用来强制得到最新的更新。</div><p style="line-height: 150%; text-indent: -21pt; margin-left: 21pt; tab-stops: 21.0pt; mso-list: l2 level1 lfo6"><span style="font-family: 宋体; color: blue; mso-ascii-font-family: 'Times new roman'; mso-hansi-font-family: 'Times new roman'">跨客户端视图的并发一致性：<br /><br /></span></p><p style="line-height: 150%; text-indent: 21pt;"><span style="color: blue" xmllang="EN-US">ZooKeeper</span><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'">并不保证在某时刻，两个不同的客户端具有一致的数据视图。因为网络延迟的原因，一个客户端可能在另一个客户端得到修改通知之前进行更新。假定有两个客户端</span><span style="color: blue" xmllang="EN-US">A</span><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'">和</span><span style="color: blue" xmllang="EN-US">B</span><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'">。如果客户端</span><span style="color: blue" xmllang="EN-US">A</span><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'">将一个节点</span><span style="color: blue" xmllang="EN-US">/a</span><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'">的值从</span><span style="color: blue" xmllang="EN-US">0</span><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'">修改为</span><span style="color: blue" xmllang="EN-US">1</span><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'">，然后通知客户端</span><span style="color: blue" xmllang="EN-US">B</span><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'">读取</span><span style="color: blue" xmllang="EN-US">/a</span><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'">，客户端</span><span style="color: blue" xmllang="EN-US">B</span><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'">读取到的值可能还是</span><span style="color: blue" xmllang="EN-US">0</span><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'">，这取决于它连接到了哪个服务器。如果客户端</span><span style="color: blue" xmllang="EN-US">A</span><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'">和</span><span style="color: blue" xmllang="EN-US">B</span><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'">读取到相同的值很重要，那么客户端</span><span style="color: blue" xmllang="EN-US">B</span><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'">应该在执行读取之前调用</span><span style="color: blue" xmllang="EN-US">sync()</span><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'">方法。</span></p> <p style="line-height: 150%; text-indent: 21pt;"><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'">所以，</span><span style="color: blue" xmllang="EN-US">ZooKeeper</span><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'">本身不保证修改在多个服务器间同步地发生，但是可以使用</span><span style="color: blue" xmllang="EN-US">ZooKeeper</span><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'">原语来构建高层功能，提供有用的客户端同步。<br /><br /><br /></span></p><div style="text-indent: 28px;"><font color="#0000ff" face="宋体"><br /></font></div><div style="text-indent: 28px;">&nbsp;设计目的</div><div style="text-indent: 28px;">1.最终一致性：client不论连接到哪个Server，展示给它都是同一个视图，这是zookeeper最重要的性能。</div><div style="text-indent: 28px;"></div><div style="text-indent: 28px;">2 .可靠性：具有简单、健壮、良好的性能，如果消息m被到一台服务器接受，那么它将被所有的服务器接受。</div><div style="text-indent: 28px;"></div><div style="text-indent: 28px;">3 .实时性：Zookeeper保证客户端将在一个时间间隔范围内获得服务器的更新信息，或者服务器失效的信息。但由于网络延时等原因，Zookeeper不能保证两个客户端能同时得到刚更新的数据，如果需要最新数据，应该在读数据之前调用sync()接口。</div><div style="text-indent: 28px;"></div><div style="text-indent: 28px;">4 .等待无关（wait-free）：慢的或者失效的client不得干预快速的client的请求，使得每个client都能有效的等待。</div><div style="text-indent: 28px;"></div><div style="text-indent: 28px;">5.原子性：更新只能成功或者失败，没有中间状态。</div><div style="text-indent: 28px;"></div><div style="text-indent: 28px;">6 .顺序性：包括全局有序和偏序两种：全局有序是指如果在一台服务器上消息a在消息b前发布，则在所有Server上消息a都将在消息b前被发布；偏序是指如果一个消息b在消息a后被同一个发送者发布，a必将排在b前面。</div><div style="text-indent: 28px;"></div><div style="text-indent: 28px;"></div><p style="line-height: 150%; text-indent: 21pt;"><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'"><br />节点宕机：<br /><br /></span></p><div style="text-indent: 28px;"><font color="#0000ff" face="宋体">应用集群中，我们常常需要让每一个机器知道集群中（或依赖的其他某一个集群）哪些机器是活着的，并且在集群机器因为宕机，网络断链等原因能够不在人工介入的情况下迅速通知到每一个机器。</font></div><div style="text-indent: 28px;">Zookeeper同样很容易实现这个功能，比如我在zookeeper服务器端有一个znode叫/APP1SERVERS,那么集群中每一个机器启动的时候都去这个节点下创建一个EPHEMERAL类型的节点，比如server1创建/APP1SERVERS/SERVER1(可以使用ip,保证不重复)，server2创建/APP1SERVERS/SERVER2，然后SERVER1和SERVER2都watch /APP1SERVERS这个父节点，那么也就是这个父节点下数据或者子节点变化都会通知对该节点进行watch的客户端。因为EPHEMERAL类型节点有一个很重要的特性，就是客户端和服务器端连接断掉或者session过期就会使节点消失，那么在某一个机器挂掉或者断链的时候，其对应的节点就会消失，然后集群中所有对/APP1SERVERS进行watch的客户端都会收到通知，然后取得最新列表即可。</div><div style="text-indent: 28px;"></div><p style="line-height: 150%; text-indent: 21pt;"><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'"><br /></span></p><div style="text-indent: 28px;"><font color="#0000ff" face="宋体">zookeeper是一个高可用性，高性能的协调服务</font></div><div style="text-indent: 28px;"></div><div style="text-indent: 28px;">解决哪些问题</div><div style="text-indent: 28px;">在分布式应用中，经常会出现部分失败的情况，即当节点间传递消息的时候由于网络或者接收者进程死掉等原因，发送者无法知道接收者是否收到消息。</div><div style="text-indent: 28px;"></div><div style="text-indent: 28px;">由于部分失败是分布式系统固有的特征因此zookeeper并不能避免部分失败，但是它可以帮你在部分失败的时候进行正确处理</div><div style="text-indent: 28px;"></div><div style="text-indent: 28px;">为了解决这个问题zookeeper具有以下特征：</div><div style="text-indent: 28px;">1：zookeeper提供丰富的构件（building block）来实现很多协调数据结构和协议</div><div style="text-indent: 28px;">2：访问原子性，客户端要么读到所有数据，要么读取失败，不会出现只读取部分的情况</div><div style="text-indent: 28px;">3：zookeeper运行在一组机器上，具有高可用性，帮助系统避免单点故障，同时删掉故障服务器</div><div style="text-indent: 28px;">4：顺序一致性：任意客户端的更新请求会被按照发送顺序提交</div><div style="text-indent: 28px;">5：单一系统映像：当一台服务器故障，导致它的客户端需要连接其它服务器的时候，所有更新晚于故障服务器的服务器都不会接收请求，一直到更新赶上故障服务器</div><div style="text-indent: 28px;">6：及时性：任何客户端能看到的滞后都是有限的，不会超过几十秒，且提供sync操作强制客户端所连的服务器与领导者同步</div><div style="text-indent: 28px;">7：会话：每个客户端连接时会尝试连接到配置列表中的一台服务器，一旦失败会自动连接另一台服务器依次类推，知道成功连接一台服务器，从而创建一个会话，客户端可以位每个会话设置超时时间，一旦会话过期，则所有短暂znode会丢失，因为zookeeper会自动发送心跳包，所以很少发生</div><div style="text-indent: 28px;">8：约会机制（rendezvous），在交互的过程中，被协调的各方不许要事先彼此了解，甚至不必同时存在</div><div style="text-indent: 28px;">9：ACL：zookeeper提供了digest（通过用户名密码），host（通过主机名），ip（通过ip地址）3种身份验证模式，依赖与zookeeper的身份验证机制每个ACL都是一个身份对应一组权限，如果我们要给demo.com的客户端域一个读权限在java语言中可以这样创建：</div><div style="text-indent: 28px;">new ACL(Perms.READ, new Id("host", "demo.com"));</div><div style="text-indent: 28px;">Ids.OPEN_ACL_UNSAFE是将所有ADMIN之外的权限授予每个人</div><div style="text-indent: 28px;">另zookeeper还可以集成第三方的身份验证系统</div><div style="text-indent: 28px;"></div><div style="text-indent: 28px;">10：提供关于通用协调模式的开源共享资源库</div><div style="text-indent: 28px;">11：高性能的（官方数据）对以写为主的工作负载来说使用5台不错的机器基准吞吐量达到10000+</div><div style="text-indent: 28px;"></div><p style="line-height: 150%; text-indent: 21pt;"><span style="font-family: 宋体; color: blue;'Times new roman';'Times new roman'"><br /><br /><br /></span></p></div></div><img src ="http://www.blogjava.net/stevenjohn/aggbug/424957.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/stevenjohn/" target="_blank">abin</a> 2015-05-08 22:10 <a href="http://www.blogjava.net/stevenjohn/archive/2015/05/08/424957.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ZooKeeper典型应用场景一览</title><link>http://www.blogjava.net/stevenjohn/archive/2015/01/11/422171.html</link><dc:creator>abin</dc:creator><author>abin</author><pubDate>Sat, 10 Jan 2015 18:57:00 GMT</pubDate><guid>http://www.blogjava.net/stevenjohn/archive/2015/01/11/422171.html</guid><wfw:comment>http://www.blogjava.net/stevenjohn/comments/422171.html</wfw:comment><comments>http://www.blogjava.net/stevenjohn/archive/2015/01/11/422171.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/stevenjohn/comments/commentRss/422171.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/stevenjohn/services/trackbacks/422171.html</trackback:ping><description><![CDATA[<p style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden; color: #2c2c2c; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">ZooKeeper是一个高可用的分布式数据管理与系统协调框架。基于对Paxos算法的实现，使该框架保证了分布式环境中数据的强一致性，也正是基于这样的特性，使得ZooKeeper解决很多分布式问题。网上对ZK的应用场景也有不少介绍，本文将结合作者身边的项目例子，系统地对ZK的应用场景进行一个分门归类的介绍。</span></p><p style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden; color: #2c2c2c; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">值得注意的是，ZK并非天生就是为这些应用场景设计的，都是后来众多开发者根据其框架的特性，利用其提供的一系列API接口（或者称为原语集），摸索出来的典型使用方法。因此，也非常欢迎读者分享你在ZK使用上的奇技淫巧。</span></p><table cellspacing="0" cellpadding="0" style="padding: 0px; margin: 0px auto 10px; font-size: 12px; border-collapse: collapse; color: #2c2c2c; font-family: 宋体, 'Arial Narrow', arial, serif; border-style: solid; background-color: #ffffff;"><tbody style="padding: 0px; margin: 0px;"><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#FF8F59" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><p align="center" style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden;">&nbsp;<span style="padding: 0px; margin: 0px; font-size: 28px;"><strong style="padding: 0px; margin: 0px;">ZooKeeper</strong><strong style="padding: 0px; margin: 0px;">典型应用场景一览</strong></span></p></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#8CEA00" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';"><span style="padding: 0px; margin: 0px; font-size: 18px;"><strong style="padding: 0px; margin: 0px;">数据发布与订阅（配置中心）</strong></span></span></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#C2C287" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">发布与订阅模型，即所谓的配置中心，顾名思义就是发布者将数据发布到ZK节点上，供订阅者动态获取数据，实现配置信息的集中式管理和动态更新。例如全局的配置信息，服务式服务框架的服务地址列表等就非常适合使用。</span></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#D0D0D0" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">1</strong>. 应用中用到的一些配置信息放到ZK上进行集中管理。这类场景通常是这样：应用在启动的时候会主动来获取一次配置，同时，在节点上注册一个Watcher，这样一来，以后每次配置有更新的时候，都会实时通知到订阅的客户端，从来达到获取最新配置信息的目的。</span><br style="padding: 0px; margin: 0px;" /><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">2</strong>. 分布式搜索服务中，索引的元信息和服务器集群机器的节点状态存放在ZK的一些指定节点，供各个客户端订阅使用。</span><br style="padding: 0px; margin: 0px;" /><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">3</strong>. 分布式日志收集系统。这个系统的核心工作是收集分布在不同机器的日志。收集器通常是按照应用来分配收集任务单元，因此需要在ZK上创建一个以应用名作为path的节点P，并将这个应用的所有机器ip，以子节点的形式注册到节点P上，这样一来就能够实现机器变动的时候，能够实时通知到收集器调整任务分配。</span><br style="padding: 0px; margin: 0px;" /><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">4</strong>. 系统中有些信息需要动态获取，并且还会存在人工手动去修改这个信息的发问。通常是暴露出接口，例如JMX接口，来获取一些运行时的信息。引入ZK之后，就不用自己实现一套方案了，只要将这些信息存放到指定的ZK节点上即可。</span><br style="padding: 0px; margin: 0px;" /><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';"><strong style="padding: 0px; margin: 0px;">注意</strong>：在上面提到的应用场景中，有个默认前提是：数据量很小，但是数据更新可能会比较快的场景。</span></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#8CEA00" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';"><span style="padding: 0px; margin: 0px; font-size: 18px;"><strong style="padding: 0px; margin: 0px;">负载均衡</strong></span></span></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#C2C287" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">这里说的负载均衡是指软负载均衡。在分布式环境中，为了保证高可用性，通常同一个应用或同一个服务的提供方都会部署多份，达到对等服务。而消费者就须要在这些对等的服务器中选择一个来执行相关的业务逻辑，其中比较典型的是消息中间件中的生产者，消费者负载均衡。</span></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#D0D0D0" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><p style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">消息中间件中发布者和订阅者的负载均衡，linkedin开源的KafkaMQ和阿里开源的</span><a href="http://metaq.taobao.org/" style="padding: 0px; margin: 0px; color: #2c628d; text-decoration: none;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">metaq</span></a><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">都是通过zookeeper来做到生产者、消费者的负载均衡。这里以metaq为例如讲下：</span></p><p style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';"><strong style="padding: 0px; margin: 0px;">生产者负载均衡</strong>：metaq发送消息的时候，生产者在发送消息的时候必须选择一台broker上的一个分区来发送消息，因此metaq在运行过程中，会把所有broker和对应的分区信息全部注册到ZK指定节点上，默认的策略是一个依次轮询的过程，生产者在通过ZK获取分区列表之后，会按照brokerId和partition的顺序排列组织成一个有序的分区列表，发送的时候按照从头到尾循环往复的方式选择一个分区来发送消息。</span></p><p style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';"><strong style="padding: 0px; margin: 0px;">消费负载均衡：</strong>&nbsp;在消费过程中，一个消费者会消费一个或多个分区中的消息，但是一个分区只会由一个消费者来消费。MetaQ的消费策略是：</span></p><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">1</strong>. 每个分区针对同一个group只挂载一个消费者。</span><br style="padding: 0px; margin: 0px;" /><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">2</strong>. 如果同一个group的消费者数目大于分区数目，则多出来的消费者将不参与消费。</span><br style="padding: 0px; margin: 0px;" /><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">3</strong>. 如果同一个group的消费者数目小于分区数目，则有部分消费者需要额外承担消费任务。</span><br style="padding: 0px; margin: 0px;" /><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp; &nbsp; 在某个消费者故障或者重启等情况下，其他消费者会感知到这一变化（通过 zookeeper watch消费者列表），然后重新进行负载均衡，保证所有的分区都有消费者进行消费。</span></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#8CEA00" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';"><span style="padding: 0px; margin: 0px; font-size: 18px;"><strong style="padding: 0px; margin: 0px;">命名服务(Naming Service)</strong></span></span></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#C2C287" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">命名服务也是分布式系统中比较常见的一类场景。在分布式系统中，通过使用命名服务，客户端应用能够根据指定名字来获取资源或服务的地址，提供者等信息。被命名的实体通常可以是集群中的机器，提供的服务地址，远程对象等等&#8212;&#8212;这些我们都可以统称他们为名字（Name）。其中较为常见的就是一些分布式服务框架中的服务地址列表。通过调用ZK提供的创建节点的API，能够很容易创建一个全局唯一的path，这个path就可以作为一个名称。</span></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#D0D0D0" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><p style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">阿里巴巴集团开源的分布式服务框架Dubbo中使用ZooKeeper来作为其命名服务，维护全局的服务地址列表，</span><a href="http://code.alibabatech.com/wiki/display/dubbo/Home" style="padding: 0px; margin: 0px; color: #2c628d; text-decoration: none;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">点击这里</span></a><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">查看Dubbo开源项目。在Dubbo实现中：</span></p><p style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';"><strong style="padding: 0px; margin: 0px;">服务提供者</strong>在启动的时候，向ZK上的指定节点/dubbo/${serviceName}/providers目录下写入自己的URL地址，这个操作就完成了服务的发布。</span></p><p style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';"><strong style="padding: 0px; margin: 0px;">服务消费者</strong>启动的时候，订阅/dubbo/${serviceName}/providers目录下的提供者URL地址， 并向/dubbo/${serviceName} /consumers目录下写入自己的URL地址。</span></p><p style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';"><strong style="padding: 0px; margin: 0px;">注意</strong>，所有向ZK上注册的地址都是临时节点，这样就能够保证服务提供者和消费者能够自动感应资源的变化。 另外，Dubbo还有针对服务粒度的监控，方法是订阅/dubbo/${serviceName}目录下所有提供者和消费者的信息。</span></p></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#8CEA00" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';"><span style="padding: 0px; margin: 0px; font-size: 18px;"><strong style="padding: 0px; margin: 0px;">分布式通知/协调</strong></span></span></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#C2C287" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">ZooKeeper中特有watcher注册与异步通知机制，能够很好的实现分布式环境下不同系统之间的通知与协调，实现对数据变更的实时处理。使用方法通常是不同系统都对ZK上同一个znode进行注册，监听znode的变化（包括znode本身内容及子节点的），其中一个系统update了znode，那么另一个系统能够收到通知，并作出相应处理</span></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#D0D0D0" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">1</strong>. 另一种心跳检测机制：检测系统和被检测系统之间并不直接关联起来，而是通过zk上某个节点关联，大大减少系统耦合。</span><br style="padding: 0px; margin: 0px;" /><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">2</strong>. 另一种系统调度模式：某系统有控制台和推送系统两部分组成，控制台的职责是控制推送系统进行相应的推送工作。管理人员在控制台作的一些操作，实际上是修改了ZK上某些节点的状态，而ZK就把这些变化通知给他们注册Watcher的客户端，即推送系统，于是，作出相应的推送任务。</span><br style="padding: 0px; margin: 0px;" /><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">3</strong>. 另一种工作汇报模式：一些类似于任务分发系统，子任务启动后，到zk来注册一个临时节点，并且定时将自己的进度进行汇报（将进度写回这个临时节点），这样任务管理者就能够实时知道任务进度。</span><br style="padding: 0px; margin: 0px;" /><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">总之，使用zookeeper来进行分布式通知和协调能够大大降低系统之间的耦合</span></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#8CEA00" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';"><span style="padding: 0px; margin: 0px; font-size: 18px;"><strong style="padding: 0px; margin: 0px;">集群管理与Master选举</strong></span></span></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#C2C287" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">1</strong>. 集群机器监控：这通常用于那种对集群中机器状态，机器在线率有较高要求的场景，能够快速对集群中机器变化作出响应。这样的场景中，往往有一个监控系统，实时检测集群机器是否存活。过去的做法通常是：监控系统通过某种手段（比如ping）定时检测每个机器，或者每个机器自己定时向监控系统汇报&#8220;我还活着&#8221;。 这种做法可行，但是存在两个比较明显的问题：</span><br style="padding: 0px; margin: 0px;" /><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">1</strong>. 集群中机器有变动的时候，牵连修改的东西比较多。</span><br style="padding: 0px; margin: 0px;" /><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">2</strong>. 有一定的延时。</span><br style="padding: 0px; margin: 0px;" /><p align="left" style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp; &nbsp; &nbsp; 利用ZooKeeper有两个特性，就可以实现另一种集群机器存活性监控系统：</span></p><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">1</strong>. 客户端在节点 x 上注册一个Watcher，那么如果 x?的子节点变化了，会通知该客户端。</span><br style="padding: 0px; margin: 0px;" /><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">2</strong>. 创建EPHEMERAL类型的节点，一旦客户端和服务器的会话结束或过期，那么该节点就会消失。</span><br style="padding: 0px; margin: 0px;" /><p align="left" style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp; &nbsp; &nbsp;例如，监控系统在 /clusterServers 节点上注册一个Watcher，以后每动态加机器，那么就往 /clusterServers 下创建一个 EPHEMERAL类型的节点：/clusterServers/{hostname}. 这样，监控系统就能够实时知道机器的增减情况，至于后续处理就是监控系统的业务了。</span></p><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">2</strong>. Master选举则是zookeeper中最为经典的应用场景了。</span><br style="padding: 0px; margin: 0px;" /><p align="left" style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">在分布式环境中，相同的业务应用分布在不同的机器上，有些业务逻辑（例如一些耗时的计算，网络I/O处理），往往只需要让整个集群中的某一台机器进行执行，其余机器可以共享这个结果，这样可以大大减少重复劳动，提高性能，于是这个master选举便是这种场景下的碰到的主要问题。</span></p><p align="left" style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">利用ZooKeeper的强一致性，能够保证在分布式高并发情况下节点创建的全局唯一性，即：同时有多个客户端请求创建 /currentMaster 节点，最终一定只有一个客户端请求能够创建成功。利用这个特性，就能很轻易的在分布式环境中进行集群选取了。</span></p><p align="left" style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">另外，这种场景演化一下，就是动态Master选举。这就要用到EPHEMERAL_SEQUENTIAL类型节点的特性了。</span></p><p align="left" style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">上文中提到，所有客户端创建请求，最终只有一个能够创建成功。在这里稍微变化下，就是允许所有请求都能够创建成功，但是得有个创建顺序，于是所有的请求最终在ZK上创建结果的一种可能情况是这样： /currentMaster/{sessionId}-1 ,/currentMaster/{sessionId}-2,/currentMaster/{sessionId}-3 &#8230;.. 每次选取序列号最小的那个机器作为Master，如果这个机器挂了，由于他创建的节点会马上小时，那么之后最小的那个机器就是Master了。</span></p></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#D0D0D0" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">1</strong>. 在搜索系统中，如果集群中每个机器都生成一份全量索引，不仅耗时，而且不能保证彼此之间索引数据一致。因此让集群中的Master来进行全量索引的生成，然后同步到集群中其它机器。另外，Master选举的容灾措施是，可以随时进行手动指定master，就是说应用在zk在无法获取master信息时，可以通过比如http方式，向一个地方获取master。</span><br style="padding: 0px; margin: 0px;" /><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">2</strong>. 在Hbase中，也是使用ZooKeeper来实现动态HMaster的选举。在Hbase实现中，会在ZK上存储一些ROOT表的地址和HMaster的地址，HRegionServer也会把自己以临时节点（Ephemeral）的方式注册到Zookeeper中，使得HMaster可以随时感知到各个HRegionServer的存活状态，同时，一旦HMaster出现问题，会重新选举出一个HMaster来运行，从而避免了HMaster的单点问题</span></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#8CEA00" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';"><span style="padding: 0px; margin: 0px; font-size: 18px;"><strong style="padding: 0px; margin: 0px;">分布式锁</strong></span></span></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#C2C287" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><p style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">分布式锁，这个主要得益于ZooKeeper为我们保证了数据的强一致性。锁服务可以分为两类，一个是<strong style="padding: 0px; margin: 0px;">保持独占</strong>，另一个是<strong style="padding: 0px; margin: 0px;">控制时序</strong>。</span></p><p style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">1</strong>. 所谓保持独占，就是所有试图来获取这个锁的客户端，最终只有一个可以成功获得这把锁。通常的做法是把zk上的一个znode看作是一把锁，通过create znode的方式来实现。所有客户端都去创建 /distribute_lock 节点，最终成功创建的那个客户端也即拥有了这把锁。</span><br style="padding: 0px; margin: 0px;" /><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">&nbsp; &nbsp;&nbsp;<strong style="padding: 0px; margin: 0px;">2</strong>. 控制时序，就是所有视图来获取这个锁的客户端，最终都是会被安排执行，只是有个全局时序了。做法和上面基本类似，只是这里 /distribute_lock 已经预先存在，客户端在它下面创建临时有序节点（这个可以通过节点的属性控制：CreateMode.EPHEMERAL_SEQUENTIAL来指定）。Zk的父节点（/distribute_lock）维持一份sequence,保证子节点创建的时序性，从而也形成了每个客户端的全局时序。</span></p></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#8CEA00" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';"><span style="padding: 0px; margin: 0px; font-size: 18px;"><strong style="padding: 0px; margin: 0px;">分布式队列</strong></span></span></td></tr><tr style="padding: 0px; margin: 0px;"><td valign="top" bgcolor="#C2C287" width="909" style="padding: 5px 10px; margin: 0px; border-style: solid; border-color: #dddddd; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span style="padding: 0px; margin: 0px; font-family: 'Comic Sans MS';">队列方面，简单地讲有两种，一种是常规的先进先出队列，另一种是要等到队列成员聚齐之后的才统一按序执行。对于第一种先进先出队列，和分布式锁服务中的控制时序场景基本原理一致，这里不再赘述。 第二种队列其实是在FIFO队列的基础上作了一个增强。通常可以在 /queue 这个znode下预先建立一个/queue/num 节点，并且赋值为n（或者直接给/queue赋值n），表示队列大小，之后每次有队列成员加入后，就判断下是否已经到达队列大小，决定是否可以开始执行了。这种用法的典型场景是，分布式环境中，一个大任务Task A，需要在很多子任务完成（或条件就绪）情况下才能进行。这个时候，凡是其中一个子任务完成（就绪），那么就去 /taskList 下建立自己的临时时序节点（CreateMode.EPHEMERAL_SEQUENTIAL），当 /taskList 发现自己下面的子节点满足指定个数，就可以进行下一步按序进行处理了。</span></td></tr></tbody></table><p style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden; color: #2c2c2c; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">&nbsp;</p><p style="padding: 0px; margin: 0px; clear: both; height: auto; overflow: hidden; color: #2c2c2c; font-family: 宋体, 'Arial Narrow', arial, serif; line-height: 28px; background-color: #ffffff;">本文出自 &#8220;<a href="http://nileader.blog.51cto.com/" style="padding: 0px; margin: 0px; color: #2c628d; text-decoration: none;">专栏：Paxos与ZooKeeper</a>&#8221; 博客，请务必保留此出处<a href="http://nileader.blog.51cto.com/1381108/1040007" style="padding: 0px; margin: 0px; color: #2c628d; text-decoration: none;">http://nileader.blog.51cto.com/1381108/1040007</a></p><img src ="http://www.blogjava.net/stevenjohn/aggbug/422171.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/stevenjohn/" target="_blank">abin</a> 2015-01-11 02:57 <a href="http://www.blogjava.net/stevenjohn/archive/2015/01/11/422171.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>