﻿<?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-SIMONE-随笔分类-solr</title><link>http://www.blogjava.net/wangxinsh55/category/52093.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 09 Jul 2012 08:40:38 GMT</lastBuildDate><pubDate>Mon, 09 Jul 2012 08:40:38 GMT</pubDate><ttl>60</ttl><item><title>Searching  </title><link>http://www.blogjava.net/wangxinsh55/archive/2012/07/09/382584.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Mon, 09 Jul 2012 02:29:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2012/07/09/382584.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/382584.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2012/07/09/382584.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/382584.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/382584.html</trackback:ping><description><![CDATA[<div>http://beijingit.blog.163.com/blog/static/29639092201212145312231/</div><br /><div>Solr's XML response format<br />status：始终为0。除非查询发生错误，将返回错误码<br />QTime: 查询耗时。由于有内部缓存，所以两个相同的查询的QTime是相同的，但是查询速度更快<br />numFound: 总共查询到的结果数<br />start:查询返回结果集的起始数<br />maxScore:查询结果中所有数据的最高得分，如果查询请求的fl请求参数没有指定score,那么返回结果中doc中是不会有得分字段的<br />返回的结果中的每一个doc对应的就是一条查询出来的数据，一一对应于索引中的document，数据类型使用solr中的基本数据类型呈现，如果是多值字段，则以排序的多个字段呈现，每个字段同样是简单类型。<br />result节点之后可能会有facet highlight等<br /><br /><strong>Parsing the URL</strong><br />url中的文本必须是utf-8编码，<br /><br /><strong>Request handlers</strong><br />在solrconfig.xml中配置，允许配置两件事情1.配置默认的参数和一些不会改变的常量。2。注册solr查询组件，例如faceting highlighting等<br />建议在实际应用中针对每一种类型的查询配置单独的request handler，这样做的好处是可以通过配置修改参数，并且对于查询统计提供更好的粒度<br />qt="handler name";<br /><br />&lt;requestHandler name="bands" class="solr.SearchHandler"&gt;<br />&lt;lst name="defaults"&gt;<br />&lt;str name="echoParams"&gt;none&lt;/str&gt;<br />&lt;int name="rows"&gt;20&lt;/int&gt;<br />&lt;/lst&gt;<br />&lt;lst name="appends"&gt;<br />&lt;str name="fq"&gt;a_type:group&lt;/str&gt;<br />&lt;/lst&gt;<br />&lt;lst name="invariants"&gt;<br />&lt;str name="facet"&gt;false&lt;/str&gt;<br />&lt;/lst&gt;<br />&lt;/requestHandler&gt;<br />1。defaults: 默认参数设置，请求时参数会覆盖此值<br />2。appends:可以设置多次的参数。像fq,除了请求参数中指定的同时此值也会被设置。<br />3.invariants:此值是常量值，并且不会被覆盖（此值用于安全目的).<br />4.first-components,  components,  last-components:注册当前handler可能会用到的handler。默认情况下已经注册了一些组件，例如faceting  highlighting等。设置first-components和last-components会分别前置或追加到这个列表中，设置 components会完全覆盖默认的列表设置。<br /><br /><strong>Query parameters</strong><br />对于boolean类型的参数，真值可以是true,on,yes，假值可以为false,off,no.<br /><br /><strong>Search criteria related parameters</strong><br /><div>q: query的简写，指查询字符串，查询语法使用defType的设定</div><div>defType：默认是lucene,大多数情况下将会使用dismax 或edismax</div><div>dismax和edismax支持许多增强的功能，更少的语法限制可以防止用户得到不希望的结果或者是不小心使用lucene语法时提示出错。</div><div>fq：用户查询时过滤条件的范围，类似于sql中的where，此参数不会影响得分(scoring),此参数可以重复。</div><div>qt：查询类型。就是前边提到的request handler,一种方法就是用/aaa来命名，然后就可以在url中用aaa?....来访问</div><div></div><div><strong>Result pagination related parameters</strong></div><div>start：默认是0，返回结果集中的起始位置，如果此值大于结果集的总数，那么将不会返回任何document，但是solr也不认为这是一个错误</div><div>rows：默认是10，</div><div></div><div><strong>Output related parameters</strong></div><div>fl：返回的字段列表，值用，/ 或空格分格，使用*符号返回所有字段但是不包括score，要想返回此字段必须添加</div><div>sort：排序字段，例如r_name asc,score desc，默认是score desc,也可以用function进行排序</div><div>wt：返回的格式，在solrconfig.xml中定义，目前支持的有xml（默认的），json,phthon,php,phps,ruby,javabin,csv,xslt,velocity.</div><div>version：不是很有用。</div><div></div><div><strong>Diagnostic related parameters</strong></div><div>用于开发调试，</div><div>indent：boolean值，用于使输出更容易阅读。</div><div>debugQuery： 如果为true,那么接下来的查询结果会有&lt;lst  name="debug"&gt;的调试信息，其中包括转换的查询字符串，score的计算，以及处理faceting所耗时 间，explainOther：如果想知道为什么某个document没有被匹配，或者得分不高，那么可以设置此值来进行查询，例如 id:"Release:12345",这样debugQuery的输出肯定会包含第一个匹配此查询的结果。</div><div>echoHandler：如果为true，将输出与solr request handler匹配的java 类名。</div><div>echoParams： 控制是否在response header中包含查询参数，可以用来调试url编码过的查询字符串，none禁用，默认的request  handler设置此属性为explicit,可以使用all来包含所有request handler中的配置参数，除了url中的。</div><div>timeAllowed：用来指定查询的最长时间，以毫秒为单位。</div><br /><div><strong>Query parsers and local-params</strong></div><div>solr中默认的query parser是lucene,</div><div></div><div><strong>Query syntax (the lucene query parser)</strong></div><div>solr完整的查询语法是实现的lucene query parser.</div><div>lucene不支持查询所有文档，solr使用*:*可以查询所有文档</div><div></div><div><strong>mandatory(强制性）prohibited(禁止）和优化</strong></div><div><strong style="line-height: 22px;">mandatory：</strong>+aaa:只匹配包含aaa的&nbsp;</div><div><strong style="line-height: 22px;">prohibited：</strong>&nbsp;-aaa：匹配所有的,<span style="line-height: 22px;">但是除了包含aaa的</span></div><div>optional: aaa 可选的</div><div>如果查询语句至少有一个mandatory，那么optional就是可选的，但是他有一个很有用的功能就是文档得分，会匹配更多的（也就是说文档中可以包含optional也可以没有）</div><div>如果查询语句没有mandatory,那么至少要匹配一个optional（也就是说文档中必须要包含optional）。</div><div>optional也可以指定一个确定的数或百分比来进行匹配或不匹配，这样的话就必须用dismax的min-should-match功能。</div><div>solr4将不再使用这种方法</div><div></div><div><strong>Boolean operators</strong></div><div>AND OR NOT</div><div>如果没有明确标记为prohibited，那么AND or &amp;&amp; 两边的操作会被认为是mandatory，例如aaa AND bbb 等同于+aaa +bbb</div><div>同样的，OR操作会被认为是optional的 NOT等同于prohibited</div><div></div><div><strong>Sub-queries</strong></div><div>(aaa AND bbb) OR (cccc || ddd )</div><div></div><div><strong>Limitations of prohibited clauses is sub-queries</strong></div><div>lucene  不支持纯粹的否定查询，例如-Smashing  -Pumpkins。solr对lucene进行增强来支持这种查询，但是仅仅只能在顶层查询，看下面这个例子 Smashing  (-Pumpkins),这个查询是在问：那个document包含Smashing或者不包含pumpkins吗？无论怎样，这样写都不会有正确结果 的。正确的写法应该是让子表达式只包含否定语句，并且添加查询所有的查询&#8220;*:*"就像这样Smashing (-Pumpkins  *:*)，这个限制只能应用在edismax查询中。</div><div></div><div><strong>Field qualifier</strong></div><div>member_name:aaa &nbsp;</div><div>+member_name:aaa +member_name:bbb 也可以用简写形式+member_name:(+aaa +bbb),圆括号代表的是子查询，这个查询的目标字段都是同一个。</div><div></div><div><strong>Wildcard queries</strong></div><div>要注意的几点</div><div>1. 不要对包含通配符的查询字符串应用文本分析，甚至是小写，假如你想查找Sma开头的单词，并且索引中的字段类型包含小写，那么就应该使用sma*而不能用 Sma*。这是SOLR-219中的一个缺点。此外，假如你要使用的字段是应用了文本分析的，那么smashing*是不会匹配到Smashing的，因 为文本分析会把Smash转换为smash，因此，不要应用文本分析。</div><div>2.通配符查询是很慢的，使用ReversedWildcardFilterFactory可以提高很多，最坏的情况是在单词两端应用*号。</div><div>3.起始通配符应用*号的话结果会返回错误，除非使用<span style="line-height: 22px;">ReversedWildcardFilterFactory。</span></div><div>例子：sma* ,sma*ing, sma??*(至少后边跟两个或者更多)</div><div>每一个匹配项都会得到相同的score，不管他使用那种查询模式。lucene以牺牲性能来支持多种score，不过得进行一些设置让solr来完成</div><div>有一个问题只是一个*号会怎么样呢？结果取决于schema文件中是否有任何一个字段类型，即使索引链中没有应用一个ReversedWildcardFilterFactory,*号都会应用所有field，如果不是这样，那么会得到一个&#8221;不支持前导通配符&#8220;的错误。</div><div></div><div><strong>Fuzzy queries</strong></div><div>例子: Smashing~</div><div>波浪号用于模糊查询，可以通过修改相似度（0-1，默认0.5）来进行查询如：Smashing~0.7</div><div>就像使用通配符查询一样，如果要使用模糊查询就应该将查询字符串转为小写。</div><div></div><div><strong>Range queries</strong></div><div>例如：a_type:2 AND a_begin_date:[1990-01-01T00:00:00.000Z TO 1999-02-02T22:59:59.999Z]&nbsp;</div><div>"[]"包含两端的值，&#8221;{}&#8220;不包含两端的值，solr3中，要么都包含，要么都不包含。solr4两个都允许。</div><div>也可以使用a_duration:[3000 TO *] 此处"*"号的方式lucene是不支持的</div><div>范围查询也可用于文本字段（不常用），此时所应用的索引字段只能有一个term 例如:somefield:([B TO C] -C)</div><div></div><div><strong>Date math</strong></div><div>solr 扩展了lucene原始的查询转换器，使date应用范围查询时再加方便，就像数字计算一样。另外还可以通过&#8221;NOW&#8220;(精确到毫秒级)来获取当前时间， 其语法还提供了补充，如减法，四舍五入根据不同的粒度，如年，秒等。操作可以链接到一起，并且从左向右执行，不允许有空格。例</div><div>r_event_date:[* TO NOW-2YEAR]</div><div>因为NOW是精确到毫秒级的，所以如果只是想到天的话可以用&#8221;/"向下舍入（此符号只会向下舍入）</div><div>r_event_date:[* To NOW/DAY-2YEAR]</div><div>可选的单位有YEAR,MONTH,DAY,DATE(与DAY相同)，HOUR,MINUTE,SECOND,MILISECOND,MILIT(与MILISECOND相同)</div><div>DateMath 不只是用于查询，同样用于索引，用于索引时应该使用正确的精度，否则精确到毫秒级的话不仅占用更多的磁盘空间，而且也会降低查询速度，常用的索引日期字段 是这样的&lt;field name="indexedAt" type="tdate" default="NOW/SECOND" /&gt;</div><div></div><div><strong>Score boosting</strong></div><div>通过添加乘数可以修改查询字符串中的条文贡献给最终得分的程度，这叫做增强，0到1之间的值减少得分，大于1的值增加得分，</div><div>例：a_member_name:Billy^2 OR Smashing 或者 +Billy Bob Corgan^0.7</div><br /><div><strong>Existence (and non-existence) queries</strong></div><div>如果要查询某个字段下的所有文档可以这样a_name:[* TO * ]</div><div>也可以查询某个字段下没有值的所有文档，-a_name:[* TO *]</div><div></div><div><strong>Escaping special characters</strong></div><div>+ - &amp;&amp; || ! () {} [] ^ '' ~ * ? : \ 要想使用这些字符的原意可以用"\" 例id:artist\:aaa 通过双引号也可以实现同样效果id:"artist:aaa"</div><div>如果使用solrj与solr交互，可以使用ClientUtils.escapeQueryChars()进行转义</div><div></div><div><strong>The Dismax query parser</strong></div><div>dismax 是lucene的DisjunctionMaxQuery之后的名字,这个query parser对于scoring 有直接关系.</div><div>edismax中的e是extended的意思，这个parser是在solr3.1中增加的，他由dismax的演化而来。</div><div></div><div><strong>Searching multiple fields</strong></div><div>&lt;str name="qf"&gt;a_name a_alias^0.7 a_member_name^0.4&lt;/str&gt;如果想根据scoring排序，可以将scoring设大一点，这样就会排在最上边</div><div>关 于schema中定义的stop words的效果，如果qf指定的字段中其中一些字段使用stop words而别一些没有使用，那么查询stop  words将不会返回任何结果。edismax把查询字符串中的stop  words认为都是可选的（也就是可有可无），除非查询字符串中全部使用stop words，使用dismax  你可以确保查询字段中的查询分板链过滤出相同的stop words值。</div><div></div><div><div style="line-height: 22px;"><strong style="line-height: 22px;">Limited query syntax</strong></div><div style="line-height: 22px;">edismax首先会把用户的查询使用lucene支持的所有语法进行转换，进行两次调整，如果转换失败，它接下来会跳到原始的dismax的语法规则。</div><div style="line-height: 22px;">or和and还有布尔运算可以用小写形式，并且支持纯否定子查询。</div><div style="line-height: 22px;">如果使用dismax，对于terms,phrase它都会限制可以使用的语法,并且使用+和-（而不是AND,OR,&amp;&amp;,||）来对条文应用强制应用和禁止应用。</div><div style="line-height: 22px;">还有就是是否需要对相关查询的有效性进行转义。为了不触发错误，除非使用edismax否则就必须编码来处理某些突出的问题。</div><div style="line-height: 22px;"></div><div style="line-height: 22px;"><strong style="line-height: 22px;">Min-should-match</strong></div><div style="line-height: 22px;">lucene  query  parser有两种操作，一是默认操作是or,也就是说只要有一个条文匹配就可以，另一个就是使用AND来使所有条文匹配。它不能使用+或-进行明确指 定。这是两种极端的情况。dismax有一个方法叫min-should-mathc,它用来指定多少条文必须匹配，或者有多少个是禁止的。这个值可以设 置为百分比或确定的数值。在配置文件中可以通过查询参数&#8220;mm"来设置。语法也比较简单。</div><div style="line-height: 22px;"></div><div style="line-height: 22px;"><strong style="line-height: 22px;">Basic rules</strong></div><div style="line-height: 22px;">mm参数的四个基本语法如下：</div><div style="line-height: 22px;">1：3&nbsp; 必须匹配3个条文，其余的是可选的。</div><div style="line-height: 22px;">2：-2 2个条文是可选的，其余的是必须的。</div><div style="line-height: 22px;">3：66% 66%的条文是必须的，其余的是可选的。</div><div style="line-height: 22px;">4：-25% 25%的条文是可选的，其余的是必须的。</div><div style="line-height: 22px;">注 意：-是对必须的除以可选的的逆向取值，它在这儿的定义其实没有否定多少的意思。虽然75%和-25%看起来一样，但是在rounding的时候就不一样 了，例如有五个查询条文，第一个条文需要三次，第二个条文需要四次，这也就说明如果要进行rounding计算，那么就需要反转标志再用100减去此值。</div><div style="line-height: 22px;">另外两点：1.如果mm的值是一个确定的值n，但是查询的条文数小于此值，那么n会减少到查询结果中的条文总数。例如mm值为-5但是查询中的条文一共只有2个，所以结果就是所有条文都是可选的。</div><div style="line-height: 22px;"> 2.记住一点,不管是lucene还是solr，在所有查询中，必须有一个条文是匹配的，即使所有条文都是可选的，</div><div style="line-height: 22px;"></div><div style="line-height: 22px;"><strong style="line-height: 22px;">Multiple rules</strong></div></div>是 以空格分隔的一个串，例如number&lt;basicmm ，意思是说如果条文的数量大于number,  那么就应用basicmm规则。（规则的从左向右升序排列的）。只有最右端的规则才会被计算，执行的规则肯定是满足最大的条文总数。如果不满足任何一个规 则，那么所有条文都是必须的。例如：<div>2&lt;75% 9&lt;-3 这个规则的意思是说，如果条文总数大于9，那么其中3个是可选的，其它的都是必须的。如果条文总数大于2，那么75%是必须的。其它情况（也就是条文总数只有1个或2个）那么所有条文都是必须的（这是默认）。</div><div></div><div><strong>What to choose</strong></div><div><span style="line-height: 22px;">Min-should-match的简单配置是使所有terms都是可选的。它的效果相当于默认的Lucene query parser 的OR操作，默认是0%。反过来的另一种极端就是所有terms都是必须的，这个就相当于AND操作，就像100%。</span></div><div><span style="line-height: 22px;">注 意：你可能想让所有terms都匹配，实事上这也是默认设置。但是如果有一个term没有找到，那么不会返回任何结果。当你设置一些terms是可选的时 候，匹配的结果会以score排序，包含最多terms的结果会排在顶部。还有一方法就是在没有返回结果的时候进行二次查询，但是solr是不支持的，不 过可以通过客户端很容易的实现。</span></div><div><span style="line-height: 22px;"><br /></span></div><div><span style="line-height: 22px;"><strong>A default search</strong></span></div><div><span style="line-height: 22px;">dismax 查询支持一个默认查询。也就是用户没有指定q的时候。参数是q.alt。例如&lt;str  name="q.alt"&gt;*:*&lt;/str&gt;。这个参数通常设置在solrconfig.xml文件的request  handler中来查询所有文档。在faceting中会使用到这个设置。如果不想返回任何结果可以设置为-*:*;</span></div><div><span style="line-height: 22px;"><br /></span></div><div><span style="line-height: 22px;"><strong>Filtering</strong></span></div><div><span style="line-height: 22px;">filter查询不会影响scoring，不像用户查询。要添加一个filter，只要使用fq参数。使用filter可以改进执行效率，因为每一个filter查询都会缓存在solr的filter cache中并且执行速度相当快。</span></div><div><span style="line-height: 22px;">solr 3.4通过本地参数cache来控制是否启用缓存</span></div><div><span style="line-height: 22px;"><br /></span></div><div><span style="line-height: 22px;"><strong>Sorting</strong></span></div><div><span style="line-height: 22px;">使用sort参数，默认是score desc。例：sort=a_type desc,score desc</span></div><div>进行排序字段的数值类型必须是single valued,indexed,并且是not-tokenized。</div><div>另外solr还支持function query ，它通常用来计算空间地理位置的距离，或现在与字段值的时间差等。例sort=sub(begin_time,end_time) desc</div></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/382584.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2012-07-09 10:29 <a href="http://www.blogjava.net/wangxinsh55/archive/2012/07/09/382584.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入剖析SolrCloud（四）</title><link>http://www.blogjava.net/wangxinsh55/archive/2012/07/04/382220.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Wed, 04 Jul 2012 10:42:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2012/07/04/382220.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/382220.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2012/07/04/382220.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/382220.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/382220.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: http://www.cnblogs.com/phinecos/archive/2012/02/29/2372682.html &nbsp; &nbsp;&nbsp; 在上一篇中介绍了连接Zookeeper集群的方法，这一篇将围绕一个有趣的话题---来展开，这就是Replication（索引复制），关于Solr Replication的详细介绍，可以参考http://wiki.apache.org...&nbsp;&nbsp;<a href='http://www.blogjava.net/wangxinsh55/archive/2012/07/04/382220.html'>阅读全文</a><img src ="http://www.blogjava.net/wangxinsh55/aggbug/382220.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2012-07-04 18:42 <a href="http://www.blogjava.net/wangxinsh55/archive/2012/07/04/382220.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Phinecos(洞庭散人) 专注于开源技术的研究与应用 深入剖析SolrCloud（三） </title><link>http://www.blogjava.net/wangxinsh55/archive/2012/07/04/382219.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Wed, 04 Jul 2012 10:41:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2012/07/04/382219.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/382219.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2012/07/04/382219.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/382219.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/382219.html</trackback:ping><description><![CDATA[<div>http://www.cnblogs.com/phinecos/archive/2012/02/16/2354834.html</div><br /><div><div id="cnblogs_post_body"><p style="text-indent: 21pt"><span style="font-family: 宋体">在</span><a href="http://www.cnblogs.com/phinecos/archive/2012/02/15/2353007.html"><span style="font-family: 宋体">上一篇</span></a><span style="font-family: 宋体">中介绍了</span>SolrCloud<span style="font-family: 宋体">的第一个模块</span>---<span style="font-family: 宋体">构建管理</span>solr<span style="font-family: 宋体">集群状态信息的</span>zookeeper<span style="font-family: 宋体">集群。当我们在</span>solr<span style="font-family: 宋体">服务器启动时拥有了这样一个</span>Zookeeper<span style="font-family: 宋体">集群后，显然我们需要连接到</span>Zookeeper<span style="font-family: 宋体">集群的方便手段，在这一篇中我将对</span>Zookeeper<span style="font-family: 宋体">客户端相关的各个封装类进行分析。</span></p> <p style="text-indent: 21pt">SolrZkClient<span style="font-family: 宋体">类是</span>Solr<span style="font-family: 宋体">服务器用来与</span>Zookeeper<span style="font-family: 宋体">集群进行通信的接口类，它包含的主要组件有：</span></p> <div> <div>&nbsp;&nbsp;<span style="color: #0000ff">private</span>&nbsp;ConnectionManager&nbsp;connManager;<br />&nbsp;&nbsp;<span style="color: #0000ff">private</span>&nbsp;<span style="color: #0000ff">volatile</span>&nbsp;SolrZooKeeper&nbsp;keeper;<br />&nbsp;&nbsp;<span style="color: #0000ff">private</span>&nbsp;ZkCmdExecutor&nbsp;zkCmdExecutor&nbsp;=&nbsp;<span style="color: #0000ff">new</span>&nbsp;ZkCmdExecutor();</div></div>  <p><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: 宋体; color: black; font-size: 10pt">其中</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">ConnectionManager</span><span style="font-family: 宋体; color: black; font-size: 10pt">是</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">Watcher</span><span style="font-family: 宋体; color: black; font-size: 10pt">的实现类，主要负责对客户端与</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">Zookeeper</span><span style="font-family: 宋体; color: black; font-size: 10pt">集群之间连接的状态变化信息进行响应，关于</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">Watcher</span><span style="font-family: 宋体; color: black; font-size: 10pt">的详细介绍，可以参考</span><a href="http://zookeeper.apache.org/doc/trunk/zookeeperProgrammers.html#ch_zkWatches">http://zookeeper.apache.org/doc/trunk/zookeeperProgrammers.html#ch_zkWatches</a><span style="font-family: 宋体">，</span></p> <p style="text-indent: 21pt"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">SolrZooKeeper</span><span style="font-family: 宋体; color: black; font-size: 10pt">类是一个包装类，没有实际意义，</span><span style="font-family: 'Courier New';background: silver; color: black; font-size: 10pt">ZkCmdExecutor</span><span style="font-family: 宋体; color: black; font-size: 10pt">类是负责在连接失败的情况下，重试某种操作特定次数，具体的操作是</span><span style="font-family: 'Courier New';background: silver; color: black; font-size: 10pt">ZkOperation</span><span style="font-family: 宋体; color: black; font-size: 10pt">这个抽象类的具体实现子类，其</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">execute</span><span style="font-family: 宋体; color: black; font-size: 10pt">方法中包含了具体操作步骤，这些操作包括新建一个</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">Znode</span><span style="font-family: 宋体; color: black; font-size: 10pt">节点，读取</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">Znode</span><span style="font-family: 宋体; color: black; font-size: 10pt">节点数据，创建</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">Znode</span><span style="font-family: 宋体; color: black; font-size: 10pt">路径，删除</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">Znode</span><span style="font-family: 宋体; color: black; font-size: 10pt">节点等</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">Zookeeper</span><span style="font-family: 宋体; color: black; font-size: 10pt">操作。</span></p> <p style="text-indent: 21pt"><span style="font-family: 宋体">首先来看它的构造函数，先创建</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">ConnectionManager</span><span style="font-family: 宋体; color: black; font-size: 10pt">对象来响应两端之间的状态变化信息，然后</span><span style="font-family: 'Courier New';background: silver; color: black; font-size: 10pt">ZkClientConnectionStrategy</span><span style="font-family: 宋体; color: black; font-size: 10pt">类是一个连接策略抽象类，它包含连接和重连两种策略，并且采用模板方法模式，具体的实现是通过静态累不类</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">ZkUpdate</span><span style="font-family: 宋体; color: black; font-size: 10pt">来实现的，</span><span style="font-family: 'Courier New';background: silver; color: black; font-size: 10pt">DefaultConnectionStrategy</span><span style="font-family: 宋体; color: black; font-size: 10pt">是它的一个实现子类，它覆写了</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">connect</span><span style="font-family: 宋体; color: black; font-size: 10pt">和</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">reconnect</span><span style="font-family: 宋体; color: black; font-size: 10pt">两个连接策略方法。</span></p> <div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div> <div>&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;SolrZkClient(String&nbsp;zkServerAddress,&nbsp;<span style="color: #0000ff">int</span>&nbsp;zkClientTimeout,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ZkClientConnectionStrategy&nbsp;strat,&nbsp;<span style="color: #0000ff">final</span>&nbsp;OnReconnect&nbsp;onReconnect,&nbsp;<span style="color: #0000ff">int</span>&nbsp;clientConnectTimeout)&nbsp;<span style="color: #0000ff">throws</span>&nbsp;InterruptedException,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TimeoutException,&nbsp;IOException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;connManager&nbsp;=&nbsp;<span style="color: #0000ff">new</span>&nbsp;ConnectionManager("ZooKeeperConnection&nbsp;Watcher:"<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+&nbsp;zkServerAddress,&nbsp;<span style="color: #0000ff">this</span>,&nbsp;zkServerAddress,&nbsp;zkClientTimeout,&nbsp;strat,&nbsp;onReconnect);<br />&nbsp;&nbsp;&nbsp;&nbsp;strat.connect(zkServerAddress,&nbsp;zkClientTimeout,&nbsp;connManager,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">new</span>&nbsp;ZkUpdate()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;<span style="color: #0000ff">void</span>&nbsp;update(SolrZooKeeper&nbsp;zooKeeper)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SolrZooKeeper&nbsp;oldKeeper&nbsp;=&nbsp;keeper;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keeper&nbsp;=&nbsp;zooKeeper;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(oldKeeper&nbsp;!=&nbsp;<span style="color: #0000ff">null</span>)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">try</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;oldKeeper.close();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff">catch</span>&nbsp;(InterruptedException&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000">//</span><span style="color: #008000">&nbsp;Restore&nbsp;the&nbsp;interrupted&nbsp;status</span><span style="color: #008000"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.currentThread().interrupt();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.error("",&nbsp;e);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">throw</span>&nbsp;<span style="color: #0000ff">new</span>&nbsp;ZooKeeperException(SolrException.ErrorCode.SERVER_ERROR,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"",&nbsp;e);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />&nbsp;&nbsp;&nbsp;&nbsp;connManager.waitForConnected(clientConnectTimeout);<br />&nbsp;&nbsp;&nbsp;&nbsp;numOpens.incrementAndGet();<br />&nbsp;&nbsp;}</div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div></div> <p style="text-indent: 21pt"><span style="font-family: 宋体">值得注意的是，构造函数中生成的</span><span style="font-family: 'Courier New';background: silver; color: black; font-size: 10pt">ZkUpdate</span><span style="font-family: 宋体">匿名类对象，它的</span><span style="font-family: 'Courier New';background: silver; color: black; font-size: 10pt">update</span><span style="font-family: 宋体; color: black; font-size: 10pt">方法会被调用，</span></p> <p style="text-indent: 21pt"><span style="font-family: 宋体; color: black; font-size: 10pt">在这个方法里，会首先将已有的老的</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">SolrZooKeeperg</span><span style="font-family: 宋体; color: black; font-size: 10pt">关闭掉，然后放置上一个新的</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">SolrZooKeeper</span><span style="font-family: 宋体; color: black; font-size: 10pt">。做好这些准备工作以后，就会去连接</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">Zookeeper</span><span style="font-family: 宋体; color: black; font-size: 10pt">服务器集群，</span></p> <p style="text-indent: 21pt">connManager.waitForConnected(clientConnectTimeout);//<span style="font-family: 宋体">连接</span>zk<span style="font-family: 宋体">服务器集群，默认</span>30<span style="font-family: 宋体">秒超时时间</span></p> <p style="text-indent: 21pt"><span style="font-family: 宋体">其实具体的连接动作是</span>new SolrZooKeeper(serverAddress, timeout, watcher)<span style="font-family: 宋体">引发的，上面那句代码只是在等待指定时间，看是否已经连接上。</span></p> <p style="text-indent: 21pt"><span style="font-family: 宋体">如果连接</span>Zookeeper<span style="font-family: 宋体">服务器集群成功，那么就可以进行</span>Zookeeper<span style="font-family: 宋体">的常规操作了：</span></p> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt">1）&nbsp;<span style="font-family: 宋体">是否已经连接</span></p> <div> <div>&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;<span style="color: #0000ff">boolean</span>&nbsp;isConnected()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>&nbsp;keeper&nbsp;!=&nbsp;<span style="color: #0000ff">null</span>&nbsp;&amp;&amp;&nbsp;keeper.getState()&nbsp;==&nbsp;ZooKeeper.States.CONNECTED;<br />&nbsp;&nbsp;}</div></div> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt;"><span>2）&nbsp;</span><span style="font-family: 宋体;">是否存在某个路径的</span>Znode</p> <div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div> <div>&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;Stat&nbsp;exists(<span style="color: #0000ff">final</span>&nbsp;String&nbsp;path,&nbsp;<span style="color: #0000ff">final</span>&nbsp;Watcher&nbsp;watcher,&nbsp;<span style="color: #0000ff">boolean</span>&nbsp;retryOnConnLoss)&nbsp;<span style="color: #0000ff">throws</span>&nbsp;KeeperException,&nbsp;InterruptedException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(retryOnConnLoss)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>&nbsp;zkCmdExecutor.retryOperation(<span style="color: #0000ff">new</span>&nbsp;ZkOperation()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;Stat&nbsp;execute()&nbsp;<span style="color: #0000ff">throws</span>&nbsp;KeeperException,&nbsp;InterruptedException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>&nbsp;keeper.exists(path,&nbsp;watcher);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff">else</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>&nbsp;keeper.exists(path,&nbsp;watcher);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}</div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div></div> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt">3）&nbsp;<span style="font-family: 宋体">创建一个</span>Znode<span style="font-family: 宋体">节点</span></p> <div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div> <div>&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;String&nbsp;create(<span style="color: #0000ff">final</span>&nbsp;String&nbsp;path,&nbsp;<span style="color: #0000ff">final</span>&nbsp;<span style="color: #0000ff">byte</span>&nbsp;data[],&nbsp;<span style="color: #0000ff">final</span>&nbsp;List&lt;ACL&gt;&nbsp;acl,&nbsp;<span style="color: #0000ff">final</span>&nbsp;CreateMode&nbsp;createMode,&nbsp;<span style="color: #0000ff">boolean</span>&nbsp;retryOnConnLoss)&nbsp;<span style="color: #0000ff">throws</span>&nbsp;KeeperException,&nbsp;InterruptedException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(retryOnConnLoss)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>&nbsp;zkCmdExecutor.retryOperation(<span style="color: #0000ff">new</span>&nbsp;ZkOperation()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;String&nbsp;execute()&nbsp;<span style="color: #0000ff">throws</span>&nbsp;KeeperException,&nbsp;InterruptedException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>&nbsp;keeper.create(path,&nbsp;data,&nbsp;acl,&nbsp;createMode);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff">else</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>&nbsp;keeper.create(path,&nbsp;data,&nbsp;acl,&nbsp;createMode);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}</div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div></div> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt;"><span>4）&nbsp;</span><span style="font-family: 宋体;">获取指定路径下的孩子</span>Znode<span style="font-family: 宋体;">节点</span></p> <div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div> <div>&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;List&lt;String&gt;&nbsp;getChildren(<span style="color: #0000ff">final</span>&nbsp;String&nbsp;path,&nbsp;<span style="color: #0000ff">final</span>&nbsp;Watcher&nbsp;watcher,&nbsp;<span style="color: #0000ff">boolean</span>&nbsp;retryOnConnLoss)&nbsp;<span style="color: #0000ff">throws</span>&nbsp;KeeperException,&nbsp;InterruptedException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(retryOnConnLoss)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>&nbsp;zkCmdExecutor.retryOperation(<span style="color: #0000ff">new</span>&nbsp;ZkOperation()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;List&lt;String&gt;&nbsp;execute()&nbsp;<span style="color: #0000ff">throws</span>&nbsp;KeeperException,&nbsp;InterruptedException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>&nbsp;keeper.getChildren(path,&nbsp;watcher);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff">else</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>&nbsp;keeper.getChildren(path,&nbsp;watcher);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}</div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div></div> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt">5）&nbsp;<span style="font-family: 宋体">获取指定</span>Znode<span style="font-family: 宋体">上附加的数据</span></p> <div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div> <div>&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;<span style="color: #0000ff">byte</span>[]&nbsp;getData(<span style="color: #0000ff">final</span>&nbsp;String&nbsp;path,&nbsp;<span style="color: #0000ff">final</span>&nbsp;Watcher&nbsp;watcher,&nbsp;<span style="color: #0000ff">final</span>&nbsp;Stat&nbsp;stat,&nbsp;<span style="color: #0000ff">boolean</span>&nbsp;retryOnConnLoss)&nbsp;<span style="color: #0000ff">throws</span>&nbsp;KeeperException,&nbsp;InterruptedException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(retryOnConnLoss)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>&nbsp;zkCmdExecutor.retryOperation(<span style="color: #0000ff">new</span>&nbsp;ZkOperation()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;<span style="color: #0000ff">byte</span>[]&nbsp;execute()&nbsp;<span style="color: #0000ff">throws</span>&nbsp;KeeperException,&nbsp;InterruptedException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>&nbsp;keeper.getData(path,&nbsp;watcher,&nbsp;stat);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff">else</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>&nbsp;keeper.getData(path,&nbsp;watcher,&nbsp;stat);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}</div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div></div> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt;"><span>6）&nbsp;</span><span style="font-family: 宋体;">在指定</span>Znode<span style="font-family: 宋体;">上设置数据</span></p> <div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div> <div>&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;Stat&nbsp;setData(<span style="color: #0000ff">final</span>&nbsp;String&nbsp;path,&nbsp;<span style="color: #0000ff">final</span>&nbsp;<span style="color: #0000ff">byte</span>&nbsp;data[],&nbsp;<span style="color: #0000ff">final</span>&nbsp;<span style="color: #0000ff">int</span>&nbsp;version,&nbsp;<span style="color: #0000ff">boolean</span>&nbsp;retryOnConnLoss)&nbsp;<span style="color: #0000ff">throws</span>&nbsp;KeeperException,&nbsp;InterruptedException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(retryOnConnLoss)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>&nbsp;zkCmdExecutor.retryOperation(<span style="color: #0000ff">new</span>&nbsp;ZkOperation()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;Stat&nbsp;execute()&nbsp;<span style="color: #0000ff">throws</span>&nbsp;KeeperException,&nbsp;InterruptedException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>&nbsp;keeper.setData(path,&nbsp;data,&nbsp;version);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff">else</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>&nbsp;keeper.setData(path,&nbsp;data,&nbsp;version);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}</div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div></div> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt">7）&nbsp;<span style="font-family: 宋体">创建路径</span></p> <div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div> <div>&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;<span style="color: #0000ff">void</span>&nbsp;makePath(String&nbsp;path,&nbsp;<span style="color: #0000ff">byte</span>[]&nbsp;data,&nbsp;CreateMode&nbsp;createMode,&nbsp;Watcher&nbsp;watcher,&nbsp;<span style="color: #0000ff">boolean</span>&nbsp;failOnExists,&nbsp;<span style="color: #0000ff">boolean</span>&nbsp;retryOnConnLoss)&nbsp;<span style="color: #0000ff">throws</span>&nbsp;KeeperException,&nbsp;InterruptedException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(log.isInfoEnabled())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info("makePath:&nbsp;"&nbsp;+&nbsp;path);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">boolean</span>&nbsp;retry&nbsp;=&nbsp;<span style="color: #0000ff">true</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(path.startsWith("/"))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;path&nbsp;=&nbsp;path.substring(1,&nbsp;path.length());<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;String[]&nbsp;paths&nbsp;=&nbsp;path.split("/");<br />&nbsp;&nbsp;&nbsp;&nbsp;StringBuilder&nbsp;sbPath&nbsp;=&nbsp;<span style="color: #0000ff">new</span>&nbsp;StringBuilder();<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">for</span>&nbsp;(<span style="color: #0000ff">int</span>&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;paths.length;&nbsp;i++)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">byte</span>[]&nbsp;bytes&nbsp;=&nbsp;<span style="color: #0000ff">null</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;pathPiece&nbsp;=&nbsp;paths[i];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sbPath.append("/"&nbsp;+&nbsp;pathPiece);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">final</span>&nbsp;String&nbsp;currentPath&nbsp;=&nbsp;sbPath.toString();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;exists&nbsp;=&nbsp;exists(currentPath,&nbsp;watcher,&nbsp;retryOnConnLoss);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(exists&nbsp;==&nbsp;<span style="color: #0000ff">null</span>&nbsp;||&nbsp;((i&nbsp;==&nbsp;paths.length&nbsp;-1)&nbsp;&amp;&amp;&nbsp;failOnExists))&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CreateMode&nbsp;mode&nbsp;=&nbsp;CreateMode.PERSISTENT;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(i&nbsp;==&nbsp;paths.length&nbsp;-&nbsp;1)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mode&nbsp;=&nbsp;createMode;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bytes&nbsp;=&nbsp;data;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(!retryOnConnLoss)&nbsp;retry&nbsp;=&nbsp;<span style="color: #0000ff">false</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">try</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(retry)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">final</span>&nbsp;CreateMode&nbsp;finalMode&nbsp;=&nbsp;mode;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">final</span>&nbsp;<span style="color: #0000ff">byte</span>[]&nbsp;finalBytes&nbsp;=&nbsp;bytes;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zkCmdExecutor.retryOperation(<span style="color: #0000ff">new</span>&nbsp;ZkOperation()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;Object&nbsp;execute()&nbsp;<span style="color: #0000ff">throws</span>&nbsp;KeeperException,&nbsp;InterruptedException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keeper.create(currentPath,&nbsp;finalBytes,&nbsp;ZooDefs.Ids.OPEN_ACL_UNSAFE,&nbsp;finalMode);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>&nbsp;<span style="color: #0000ff">null</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff">else</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keeper.create(currentPath,&nbsp;bytes,&nbsp;ZooDefs.Ids.OPEN_ACL_UNSAFE,&nbsp;mode);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff">catch</span>&nbsp;(NodeExistsException&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(!failOnExists)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000">//</span><span style="color: #008000">&nbsp;TODO:&nbsp;version&nbsp;?&nbsp;for&nbsp;now,&nbsp;don't&nbsp;worry&nbsp;about&nbsp;race</span><span style="color: #008000"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setData(currentPath,&nbsp;data,&nbsp;-1,&nbsp;retryOnConnLoss);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000">//</span><span style="color: #008000">&nbsp;set&nbsp;new&nbsp;watch</span><span style="color: #008000"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exists(currentPath,&nbsp;watcher,&nbsp;retryOnConnLoss);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000">//</span><span style="color: #008000">&nbsp;ignore&nbsp;unless&nbsp;it's&nbsp;the&nbsp;last&nbsp;node&nbsp;in&nbsp;the&nbsp;path</span><span style="color: #008000"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(i&nbsp;==&nbsp;paths.length&nbsp;-&nbsp;1)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">throw</span>&nbsp;e;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>(i&nbsp;==&nbsp;paths.length&nbsp;-1)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000">//</span><span style="color: #008000">&nbsp;set&nbsp;new&nbsp;watch</span><span style="color: #008000"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exists(currentPath,&nbsp;watcher,&nbsp;retryOnConnLoss);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff">else</span>&nbsp;<span style="color: #0000ff">if</span>&nbsp;(i&nbsp;==&nbsp;paths.length&nbsp;-&nbsp;1)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000">//</span><span style="color: #008000">&nbsp;TODO:&nbsp;version&nbsp;?&nbsp;for&nbsp;now,&nbsp;don't&nbsp;worry&nbsp;about&nbsp;race</span><span style="color: #008000"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setData(currentPath,&nbsp;data,&nbsp;-1,&nbsp;retryOnConnLoss);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000">//</span><span style="color: #008000">&nbsp;set&nbsp;new&nbsp;watch</span><span style="color: #008000"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exists(currentPath,&nbsp;watcher,&nbsp;retryOnConnLoss);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}</div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div></div> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt">8）&nbsp;<span style="font-family: 宋体">删除指定</span>Znode</p> <div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div> <div>&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;<span style="color: #0000ff">void</span>&nbsp;delete(<span style="color: #0000ff">final</span>&nbsp;String&nbsp;path,&nbsp;<span style="color: #0000ff">final</span>&nbsp;<span style="color: #0000ff">int</span>&nbsp;version,&nbsp;<span style="color: #0000ff">boolean</span>&nbsp;retryOnConnLoss)&nbsp;<span style="color: #0000ff">throws</span>&nbsp;InterruptedException,&nbsp;KeeperException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(retryOnConnLoss)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zkCmdExecutor.retryOperation(<span style="color: #0000ff">new</span>&nbsp;ZkOperation()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;Stat&nbsp;execute()&nbsp;<span style="color: #0000ff">throws</span>&nbsp;KeeperException,&nbsp;InterruptedException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keeper.delete(path,&nbsp;version);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">return</span>&nbsp;<span style="color: #0000ff">null</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff">else</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;keeper.delete(path,&nbsp;version);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;}</div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div></div> <p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: 宋体;">我们再回过头来看看</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt;">ConnectionManager</span><span style="font-family: 宋体; color: black; font-size: 10pt;'Courier New';'Courier New';'Courier New';">类是如何响应两端的连接状态信息的变化的，它最重要的方法是</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt;">process</span><span style="font-family: 宋体; color: black; font-size: 10pt;'Courier New';'Courier New';'Courier New';">方法，当它被触发回调时，会从</span>WatchedEvent<span style="font-family: 宋体;">参数中得到事件的各种状态信息，比如连接成功，会话过期（此时需要进行重连），连接断开等。</span></p> <div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div> <div>&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;<span style="color: #0000ff">synchronized</span>&nbsp;<span style="color: #0000ff">void</span>&nbsp;process(WatchedEvent&nbsp;event)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(log.isInfoEnabled())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info("Watcher&nbsp;"&nbsp;+&nbsp;<span style="color: #0000ff">this</span>&nbsp;+&nbsp;"&nbsp;name:"&nbsp;+&nbsp;name&nbsp;+&nbsp;"&nbsp;got&nbsp;event&nbsp;"&nbsp;+&nbsp;event&nbsp;+&nbsp;"&nbsp;path:"&nbsp;+&nbsp;event.getPath()&nbsp;+&nbsp;"&nbsp;type:"&nbsp;+&nbsp;event.getType());<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;state&nbsp;=&nbsp;event.getState();<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(state&nbsp;==&nbsp;KeeperState.SyncConnected)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connected&nbsp;=&nbsp;<span style="color: #0000ff">true</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;clientConnected.countDown();<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff">else</span>&nbsp;<span style="color: #0000ff">if</span>&nbsp;(state&nbsp;==&nbsp;KeeperState.Expired)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connected&nbsp;=&nbsp;<span style="color: #0000ff">false</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info("Attempting&nbsp;to&nbsp;reconnect&nbsp;to&nbsp;recover&nbsp;relationship&nbsp;with&nbsp;ZooKeeper...");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000">//</span><span style="color: #008000">尝试重新连接zk服务器</span><span style="color: #008000"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">try</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connectionStrategy.reconnect(zkServerAddress,&nbsp;zkClientTimeout,&nbsp;<span style="color: #0000ff">this</span>,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">new</span>&nbsp;ZkClientConnectionStrategy.ZkUpdate()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;<span style="color: #0000ff">void</span>&nbsp;update(SolrZooKeeper&nbsp;keeper)&nbsp;<span style="color: #0000ff">throws</span>&nbsp;InterruptedException,&nbsp;TimeoutException,&nbsp;IOException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">synchronized</span>&nbsp;(connectionStrategy)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;waitForConnected(SolrZkClient.DEFAULT_CLIENT_CONNECT_TIMEOUT);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;client.updateKeeper(keeper);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(onReconnect&nbsp;!=&nbsp;<span style="color: #0000ff">null</span>)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;onReconnect.command();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">synchronized</span>&nbsp;(ConnectionManager.<span style="color: #0000ff">this</span>)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConnectionManager.<span style="color: #0000ff">this</span>.connected&nbsp;=&nbsp;<span style="color: #0000ff">true</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff">catch</span>&nbsp;(Exception&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SolrException.log(log,&nbsp;"",&nbsp;e);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info("Connected:"&nbsp;+&nbsp;connected);<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff">else</span>&nbsp;<span style="color: #0000ff">if</span>&nbsp;(state&nbsp;==&nbsp;KeeperState.Disconnected)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connected&nbsp;=&nbsp;<span style="color: #0000ff">false</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff">else</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connected&nbsp;=&nbsp;<span style="color: #0000ff">false</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;notifyAll();<br />&nbsp;&nbsp;}</div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div></div> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt">&nbsp;</p> <p>&nbsp;</p></div></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/382219.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2012-07-04 18:41 <a href="http://www.blogjava.net/wangxinsh55/archive/2012/07/04/382219.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Phinecos(洞庭散人) 专注于开源技术的研究与应用 深入剖析SolrCloud（一） </title><link>http://www.blogjava.net/wangxinsh55/archive/2012/07/04/382217.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Wed, 04 Jul 2012 10:40:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2012/07/04/382217.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/382217.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2012/07/04/382217.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/382217.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/382217.html</trackback:ping><description><![CDATA[<div>http://www.cnblogs.com/phinecos/archive/2012/02/10/2345634.html</div><br /><br /><div>&nbsp;&nbsp;&nbsp; <span style="font-family: 'Verdana','sans-serif'; color: black; font-size: 10pt"><a href="http://wiki.apache.org/solr/SolrCloud"><span style="color: #075db3">SolrCloud</span></a></span><span style="font-family: 宋体; color: black; font-size: 10pt">是基于</span><span style="font-family: 'Verdana','sans-serif'; color: black; font-size: 10pt">Solr</span><span style="font-family: 宋体; color: black; font-size: 10pt">和</span><span style="font-family: 'Verdana','sans-serif'; color: black; font-size: 10pt">Zookeeper</span><span style="font-family: 宋体; color: black; font-size: 10pt">的分布式搜索方案，是正在开发中的</span><span style="font-family: 'Verdana','sans-serif'; color: black; font-size: 10pt">Solr4.0</span><span style="font-family: 宋体; color: black; font-size: 10pt">的核心组件之一，它的主要思想是使用</span><span style="font-family: 'Verdana','sans-serif'; color: black; font-size: 10pt">Zookeeper</span><span style="font-family: 宋体; color: black; font-size: 10pt">作为集群的配置信息中心。它有几个特色功能：</span><span style="font-family: 'Verdana','sans-serif'; color: black; font-size: 10pt">1</span><span style="font-family: 宋体; color: black; font-size: 10pt">）集中式的配置信息</span><span style="font-family: 'Verdana','sans-serif'; color: black; font-size: 10pt"> 2</span><span style="font-family: 宋体; color: black; font-size: 10pt">）自动容错</span><span style="font-family: 'Verdana','sans-serif'; color: black; font-size: 10pt"> 3</span><span style="font-family: 宋体; color: black; font-size: 10pt">）近实时搜索</span><span style="font-family: 'Verdana','sans-serif'; color: black; font-size: 10pt"> 4</span><span style="font-family: 宋体; color: black; font-size: 10pt">）查询时自动负载均衡</span>&nbsp; <p><img alt="" src="http://images.cnblogs.com/cnblogs_com/phinecos/20120210/2shard4serverFull.jpg" border="0" height="633" width="800" />&nbsp;</p> <p style="text-indent: 21pt"><span style="font-family: 宋体">基本可以用上面这幅图来概述，这是一个拥有</span>4<span style="font-family: 宋体">个</span>Solr<span style="font-family: 宋体">节点的集群，索引分布在两个</span>Shard<span style="font-family: 宋体">里面，每个</span>Shard<span style="font-family: 宋体">包含两个</span>Solr<span style="font-family: 宋体">节点，一个是</span>Leader<span style="font-family: 宋体">节点，一个是</span>Replica<span style="font-family: 宋体">节点，此外集群中有一个负责维护集群状态信息的</span>Overseer<span style="font-family: 宋体">节点，它是一个总控制器。集群的所有状态信息都放在</span>Zookeeper<span style="font-family: 宋体">集群中统一维护。从图中还可以看到，任何一个节点都可以接收索引更新的请求，然后再将这个请求转发到文档所应该属于的那个</span>Shard<span style="font-family: 宋体">的</span>Leader<span style="font-family: 宋体">节点，</span>Leader<span style="font-family: 宋体">节点更新结束完成，最后将版本号和文档转发给同属于一个</span>Shard<span style="font-family: 宋体">的</span>replicas<span style="font-family: 宋体">节点。</span></p> <p style="text-indent: 21pt"><span style="font-family: 宋体">下面我们来看一个简单的</span>SolrCloud<span style="font-family: 宋体">集群的配置过程。</span></p> <p style="text-indent: 21pt"><span style="font-family: 宋体">首先去</span><a href="https://builds.apache.org/job/Solr-trunk/lastSuccessfulBuild/artifact/artifacts/%E4%B8%8B%E8%BD%BDSolr4.0">https://builds.apache.org/job/Solr-trunk/lastSuccessfulBuild/artifact/artifacts/<span style="font-family: 宋体">下载Solr4.0</span></a><span style="font-family: 宋体">的源码和二进制包，注意</span>Solr4.0<span style="font-family: 宋体">现在还在开发中，因此这里是</span>Nightly Build<span style="font-family: 宋体">版本。</span></p> <p style="text-indent: 21pt"><span style="font-family: 宋体">示例</span>1<span style="font-family: 宋体">，简单的包含</span>2<span style="font-family: 宋体">个</span>Shard<span style="font-family: 宋体">的集群</span></p> <p><img alt="" src="http://images.cnblogs.com/cnblogs_com/phinecos/20120210/2shard2server.jpg" border="0" height="120" width="275" /></p> <p style="text-indent: 21pt"><span style="font-family: 宋体">这个示例中，我们把一个</span>collection<span style="font-family: 宋体">的索引数据分布到两个</span>shard<span style="font-family: 宋体">上去，步骤如下：</span></p> <p style="text-indent: 21pt"><span style="font-family: 宋体">为了弄</span>2<span style="font-family: 宋体">个</span>solr<span style="font-family: 宋体">服务器，我们拷贝一份</span>example<span style="font-family: 宋体">目录</span></p> <div> <div>cp&nbsp;-r&nbsp;example&nbsp;example2</div></div> <p style="text-indent: 21pt;"><span style="font-family: 宋体;">然后启动第一个</span>solr<span style="font-family: 宋体;">服务器，并初始化一个新的</span>solr<span style="font-family: 宋体;">集群，</span></p> <div> <div>cd&nbsp;example<br />java&nbsp;-Dbootstrap_confdir=./solr/conf&nbsp;-Dcollection.configName=myconf&nbsp;-DzkRun&nbsp;-DnumShards=2&nbsp;-jar&nbsp;start.jar</div></div> <p style="text-indent: 21pt;"><span style="font-family: Courier; color: black">-DzkRun</span><span style="font-family: 宋体; color: black">参数是启动一个嵌入式的</span><span style="font-family: Courier; color: black">Zookeeper</span><span style="font-family: 宋体; color: black">服务器，它会作为</span><span style="font-family: Courier; color: black">solr</span><span style="font-family: 宋体; color: black">服务器的一部分，</span><span style="font-family: Courier; color: black">-Dbootstrap_confdir</span><span style="font-family: 宋体; color: black">参数是上传本地的配置文件上传到</span><span style="font-family: Courier; color: black">zookeeper</span><span style="font-family: 宋体; color: black">中去，作为整个集群共用的配置文件，</span><span style="font-family: Courier; color: black">-DnumShards</span><span style="font-family: 宋体; color: black">指定了集群的逻辑分组数目。</span></p> <p style="text-indent: 21pt"><span style="font-family: 宋体; color: black">然后启动第二个</span><span style="font-family: Courier; color: black">solr</span><span style="font-family: 宋体; color: black">服务器，并将其引向集群所在位置</span></p> <div> <div>cd&nbsp;example2<br />java&nbsp;-Djetty.port=7574&nbsp;-DzkHost=localhost:9983&nbsp;-jar&nbsp;start.jar</div></div> <p style="text-indent: 21pt;"><span style="font-family: 'Courier New'; color: black; font-size: 10pt">-DzkHost=localhost:9983</span><span style="font-family: 宋体; color: black; font-size: 10pt;'Courier New';'Courier New';'Courier New'">就是指明了</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt">Zookeeper</span><span style="font-family: 宋体; color: black; font-size: 10pt;'Courier New';'Courier New';'Courier New'">集群所在位置</span></p> <p style="text-indent: 21pt;"><span style="font-family: 宋体; color: black;">我们可以打开</span><span style="font-family: 'Arial','sans-serif'; color: black"><a href="http://localhost:8983/solr/collection1/admin/zookeeper.jsp"><span style="border-bottom: windowtext 1pt; border-left: windowtext 1pt; padding-bottom: 0cm; padding-left: 0cm; padding-right: 0cm; color: #4477ff; border-top: windowtext 1pt; border-right: windowtext 1pt; text-decoration: none; padding-top: 0cm; text-underline: none;">http://localhost:8983/solr/collection1/admin/zookeeper.jsp</span></a></span>&nbsp;<span style="font-family: 宋体; color: black;">或者</span><span style="font-family: 'Arial','sans-serif'; color: black"><a href="http://localhost:8983/solr/#/cloud"><span style="border-bottom: windowtext 1pt; border-left: windowtext 1pt; padding-bottom: 0cm; padding-left: 0cm; padding-right: 0cm; color: #4477ff; border-top: windowtext 1pt; border-right: windowtext 1pt; text-decoration: none; padding-top: 0cm; text-underline: none;">http://localhost:8983/solr/#/cloud</span></a></span><span style="font-family: 宋体; color: black;">看看目前集群的状态，</span></p> <p style="text-indent: 21pt;"><img style="width: 911px; height: 431px" alt="" src="http://images.cnblogs.com/cnblogs_com/phinecos/20120210/2node.jpg" border="0" height="431" width="911" /></p> <p style="text-indent: 21pt;"><span style="font-family: 宋体; font-size: 10.5pt">现在，我们可以试试索引一些文档，</span></p> <div> <div>cd&nbsp;exampledocs<br />java&nbsp;-Durl=http://localhost:8983/solr/collection1/update&nbsp;-jar&nbsp;post.jar&nbsp;ipod_video.xml<br />java&nbsp;-Durl=http://localhost:8983/solr/collection1/update&nbsp;-jar&nbsp;post.jar&nbsp;monitor.xml<br />java&nbsp;-Durl=http://localhost:8983/solr/collection1/update&nbsp;-jar&nbsp;post.jar&nbsp;mem.xml</div></div> <p style="text-indent: 21pt;"><span style="font-family: 'Calibri','sans-serif'; font-size: 10.5pt"><span style="font-family: 宋体;">最后，来试试分布式搜索吧</span>:</span></p> <p style="text-indent: 21pt"><a href="http://localhost:8983/solr/collection1/select?q">http://localhost:8983/solr/collection1/select?q</a></p> <p style="text-indent: 21pt">Zookeeper<span style="font-family: 宋体">维护的集群状态数据是存放在</span>solr/zoo_data<span style="font-family: 宋体">目录下的。</span></p> <p style="text-indent: 21pt"><span style="font-family: 宋体">现在我们来剖析下这样一个简单的集群构建的基本流程：</span></p> <p style="text-indent: 21pt"><span style="font-family: 宋体">先从第一台</span>solr<span style="font-family: 宋体">服务器说起：</span></p> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt">1)<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: 宋体">它首先启动一个嵌入式的</span>Zookeeper<span style="font-family: 宋体">服务器，作为集群状态信息的管理者，</span></p> <p style="text-indent: 21pt">2<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">将自己这个节点注册到</span>/node_states/<span style="font-family: 宋体">目录下</span></p> <p style="text-indent: 21pt">3<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">同时将自己注册到</span>/live_nodes/<span style="font-family: 宋体">目录下</span></p> <p style="text-indent: 21pt">4<span style="font-family: 宋体">）创建</span>/overseer_elect/leader<span style="font-family: 宋体">，为后续</span>Overseer<span style="font-family: 宋体">节点的选举做准备，新建一个</span>Overseer<span style="font-family: 宋体">，</span></p> <p style="text-indent: 21pt">5) <span style="font-family: 宋体">更新</span>/clusterstate.json<span style="font-family: 宋体">目录下</span>json<span style="font-family: 宋体">格式的集群状态信息</span></p> <p style="text-indent: 21pt">6) <span style="font-family: 宋体">本机从</span>Zookeeper<span style="font-family: 宋体">中更新集群状态信息，维持与</span>Zookeeper<span style="font-family: 宋体">上的集群信息一致</span></p> <p style="text-indent: 21pt">7<span style="font-family: 宋体">）上传本地配置文件到</span>Zookeeper<span style="font-family: 宋体">中，供集群中其他</span>solr<span style="font-family: 宋体">节点使用</span></p> <p style="text-indent: 21pt">8) <span style="font-family: 宋体">启动本地的</span>Solr<span style="font-family: 宋体">服务器，</span></p> <p style="text-indent: 21pt">9) Solr<span style="font-family: 宋体">启动完成后，</span>Overseer<span style="font-family: 宋体">会得知</span>shard<span style="font-family: 宋体">中有第一个节点进来，更新</span>shard<span style="font-family: 宋体">状态信息，并将本机所在节点设置为</span>shard1<span style="font-family: 宋体">的</span>leader<span style="font-family: 宋体">节点，并向整个集群发布最新的集群状态信息。</span></p> <p style="text-indent: 21pt">10<span style="font-family: 宋体">）本机从</span>Zookeeper<span style="font-family: 宋体">中再次更新集群状态信息，第一台</span>solr<span style="font-family: 宋体">服务器启动完毕。</span></p> <p style="text-indent: 21pt"><span style="font-family: 宋体">然后来看第二台</span>solr<span style="font-family: 宋体">服务器的启动过程：</span></p> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt">1）&nbsp;<span style="font-family: 宋体">本机连接到集群所在的</span>Zookeeper<span style="font-family: 宋体">，</span></p> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt">2）&nbsp;<span style="font-family: 宋体">将自己这个节点注册到</span>/node_states/<span style="font-family: 宋体">目录下</span></p> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt">3）&nbsp;&nbsp;<span style="font-family: 宋体">同时将自己注册到</span>/live_nodes/<span style="font-family: 宋体">目录下</span></p> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt">4）&nbsp;<span style="font-family: 宋体">本机从</span>Zookeeper<span style="font-family: 宋体">中更新集群状态信息，维持与</span>Zookeeper<span style="font-family: 宋体">上的集群信息一致</span></p> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt">5）&nbsp;<span style="font-family: 宋体">从集群中保存的配置文件加载</span>Solr<span style="font-family: 宋体">所需要的配置信息</span></p> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt">6）&nbsp;<span style="font-family: 宋体">启动本地</span>solr<span style="font-family: 宋体">服务器，</span></p> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt">7）&nbsp;solr<span style="font-family: 宋体">启动完成后，将本节点注册为集群中的</span>shard<span style="font-family: 宋体">，并将本机设置为</span>shard2<span style="font-family: 宋体">的</span>Leader<span style="font-family: 宋体">节点，</span></p> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt">8）&nbsp;<span style="font-family: 宋体">本机从</span>Zookeeper<span style="font-family: 宋体">中再次更新集群状态信息，第二台</span>solr<span style="font-family: 宋体">服务器启动完毕。</span></p> <p style="margin: 0cm 0cm 0pt 21pt"><span style="font-family: 宋体">示例</span>2<span style="font-family: 宋体">，包含</span>2<span style="font-family: 宋体">个</span>shard<span style="font-family: 宋体">的集群，每个</span>shard<span style="font-family: 宋体">中有</span>replica<span style="font-family: 宋体">节点</span></p> <p style="text-indent: 21pt"><img alt="" src="http://images.cnblogs.com/cnblogs_com/phinecos/20120210/2shard4server.jpg" border="0" height="264" width="300" /></p> <p style="margin: 0cm 0cm 0pt 21pt"><span style="font-family: 宋体;">如图所示，集群包含</span>2<span style="font-family: 宋体;">个</span>shard<span style="font-family: 宋体;">，每个</span>shard<span style="font-family: 宋体;">中有两个</span>solr<span style="font-family: 宋体;">节点，一个是</span>leader<span style="font-family: 宋体;">，一个是</span>replica<span style="font-family: 宋体;">节点，</span></p> <div> <div>cp&nbsp;-r&nbsp;example&nbsp;exampleB<br />cp&nbsp;-r&nbsp;example2&nbsp;example2B<br />cd&nbsp;exampleB<br />java&nbsp;-Djetty.port=8900&nbsp;-DzkHost=localhost:9983&nbsp;-jar&nbsp;start.jar<br />cd&nbsp;example2B<br />java&nbsp;-Djetty.port=7500&nbsp;-DzkHost=localhost:9983&nbsp;-jar&nbsp;start.jar</div></div> <p style="text-indent: 21pt;"><span style="font-family: 宋体; color: black;">我们可以打开</span><span style="border-bottom: windowtext 1pt; border-left: windowtext 1pt; padding-bottom: 0cm; padding-left: 0cm; padding-right: 0cm; font-family: 'Arial','sans-serif'; color: black; border-top: windowtext 1pt; border-right: windowtext 1pt; padding-top: 0cm;"><a href="http://localhost:8983/solr/collection1/admin/zookeeper.jsp">http://localhost:8983/solr/collection1/admin/zookeeper.jsp</a></span> &nbsp;<span style="font-family: 宋体; color: black;">看看包含</span><span style="font-family: 'Arial','sans-serif'; color: black">4</span><span style="font-family: 宋体; color: black;">个节点的集群的状态，</span></p>  <p style="text-indent: 21pt;"><span style="font-family: 'Calibri','sans-serif'; font-size: 10.5pt">&nbsp;</span></p> <p style="text-indent: 21pt;"><img style="width: 899px; height: 495px" alt="" src="http://images.cnblogs.com/cnblogs_com/phinecos/20120210/4node.jpg" border="0" height="495" width="899" /></p> <p style="text-indent: 21pt;">&nbsp;</p> <p style="text-indent: 21pt; margin: 0cm 0cm 0pt 21pt"><span style="font-family: 宋体">这个集群现在就具备容错性了，你可以试着干掉一个</span>Solr<span style="font-family: 宋体">服务器，然后再发送查询请求。背后的实质是集群的</span>ov erseer<span style="font-family: 宋体">会监测各个</span>shard<span style="font-family: 宋体">的</span>leader<span style="font-family: 宋体">节点，如果</span>leader<span style="font-family: 宋体">节点挂了，则会启动自动的容错机制，会从同一个</span>shard<span style="font-family: 宋体">中的其他</span>replica<span style="font-family: 宋体">节点集中重新选举出一个</span>leader<span style="font-family: 宋体">节点，甚至如果</span>overseer<span style="font-family: 宋体">节点自己也挂了，同样会自动在其他节点上启用新的</span>overseer<span style="font-family: 宋体">节点，这样就确保了集群的高可用性。</span></p> <p style="text-indent: 21pt; margin: 0cm 0cm 0pt 21pt"><span style="font-family: 宋体">示例</span>3 <span style="font-family: 宋体">包含</span>2<span style="font-family: 宋体">个</span>shard<span style="font-family: 宋体">的集群，带</span>shard<span style="font-family: 宋体">备份和</span>zookeeper<span style="font-family: 宋体">集群机制</span></p> <p style="text-indent: 21pt;"><img alt="" src="http://images.cnblogs.com/cnblogs_com/phinecos/20120210/2shard4server2.jpg" border="0" height="246" width="300" /></p> <p style="text-indent: 21pt;">&nbsp;</p> <p style="text-indent: 21pt; margin: 0cm 0cm 0pt 21pt"><span style="font-family: 宋体">上一个示例中存在的问题是：尽管</span>solr<span style="font-family: 宋体">服务器可以容忍挂掉，但集群中只有一个</span>zookeeper<span style="font-family: 宋体">服务器来维护集群的状态信息，单点的存在即是不稳定的根源。如果这个</span>zookeeper<span style="font-family: 宋体">服务器挂了，那么分布式查询还是可以工作的，因为每个</span>solr<span style="font-family: 宋体">服务器都会在内存中维护最近一次由</span>zookeeper<span style="font-family: 宋体">维护的集群状态信息，但新的节点无法加入集群，集群的状态变化也不可知了。因此，为了解决这个问题，需要对</span>Zookeeper<span style="font-family: 宋体">服务器也设置一个集群，让其也具备高可用性和容错性。</span></p> <p style="text-indent: 21pt; margin: 0cm 0cm 0pt 21pt"><span style="font-family: 宋体">有两种方式可选，一种是提供一个外部独立的</span>Zookeeper<span style="font-family: 宋体">集群，另一种是每个</span>solr<span style="font-family: 宋体">服务器都启动一个内嵌的</span>Zookeeper<span style="font-family: 宋体">服务器，再将这些</span>Zookeeper<span style="font-family: 宋体">服务器组成一个集群。</span>&nbsp;<span style="font-family: 宋体">我们这里用后一种做示例：</span></p> <div> <div>cd&nbsp;example<br />java&nbsp;-Dbootstrap_confdir=./solr/conf&nbsp;-Dcollection.configName=myconf&nbsp;-DzkRun&nbsp;-DzkHost=localhost:9983,localhost:8574,localhost:9900&nbsp;-DnumShards=2&nbsp;-jar&nbsp;start.jar<br />cd&nbsp;example2<br />java&nbsp;-Djetty.port=7574&nbsp;-DzkRun&nbsp;-DzkHost=localhost:9983,localhost:8574,localhost:9900&nbsp;-jar&nbsp;start.jar<br />cd&nbsp;exampleB<br />java&nbsp;-Djetty.port=8900&nbsp;-DzkRun&nbsp;-DzkHost=localhost:9983,localhost:8574,localhost:9900&nbsp;-jar&nbsp;start.jar<br />cd&nbsp;example2B<br />java&nbsp;-Djetty.port=7500&nbsp;-DzkHost=localhost:9983,localhost:8574,localhost:9900&nbsp;-jar&nbsp;start.jar</div></div> <p style="text-indent: 21pt;"><span style="font-family: 宋体; color: black;">我们可以打开</span><span style="border-bottom: windowtext 1pt; border-left: windowtext 1pt; padding-bottom: 0cm; padding-left: 0cm; padding-right: 0cm; font-family: 'Arial','sans-serif'; color: black; border-top: windowtext 1pt; border-right: windowtext 1pt; padding-top: 0cm;"><a href="http://localhost:8983/solr/collection1/admin/zookeeper.jsp">http://localhost:8983/solr/collection1/admin/zookeeper.jsp</a></span> &nbsp;<span style="font-family: 宋体; color: black;">看看包含</span><span style="font-family: 'Arial','sans-serif'; color: black">4</span><span style="font-family: 宋体; color: black;">个节点的集群的状态，可以发现其实和上一个没有任何区别。</span></p>  <p style="text-indent: 21pt"><span style="font-family: 宋体; color: black">后续的文章将从实现层面对</span><span style="font-family: 'Arial','sans-serif'; color: black">SolrCloud</span><span style="font-family: 宋体; color: black">这个分布式搜索解决方案进行进一步的深入剖析。</span></p></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/382217.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2012-07-04 18:40 <a href="http://www.blogjava.net/wangxinsh55/archive/2012/07/04/382217.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入剖析SolrCloud（二）</title><link>http://www.blogjava.net/wangxinsh55/archive/2012/07/04/382218.html</link><dc:creator>SIMONE</dc:creator><author>SIMONE</author><pubDate>Wed, 04 Jul 2012 10:40:00 GMT</pubDate><guid>http://www.blogjava.net/wangxinsh55/archive/2012/07/04/382218.html</guid><wfw:comment>http://www.blogjava.net/wangxinsh55/comments/382218.html</wfw:comment><comments>http://www.blogjava.net/wangxinsh55/archive/2012/07/04/382218.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/wangxinsh55/comments/commentRss/382218.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/wangxinsh55/services/trackbacks/382218.html</trackback:ping><description><![CDATA[<div>http://www.cnblogs.com/phinecos/archive/2012/02/15/2353007.html</div><br /><div>&nbsp; <a href="http://www.cnblogs.com/phinecos/archive/2012/02/10/2345634.html"><span style="font-family: 宋体">上一篇</span></a><span style="font-family: 宋体">介绍了</span>SolrCloud<span style="font-family: 宋体">的基本概念，从这一篇开始我将深入到其实现代码中进行剖析。</span> <p><span style="white-space:pre">	</span>SolrCloud<span style="font-family: 宋体">最重要的一点就是引入了</span>ZooKeeper<span style="font-family: 宋体">来统一管理各种配置和状态信息。</span><a href="http://zookeeper.apache.org/">zookeeper</a><span style="font-family: 宋体">是一个开源分布式的服务</span>,<span style="font-family: 宋体">它提供了分布式协作</span>,<span style="font-family: 宋体">分布式同步</span>,<span style="font-family: 宋体">配置管理等功能</span>. <span style="font-family: 宋体">其实现的功能与</span>google<span style="font-family: 宋体">的</span><a href="http://www.cnblogs.com/phinecos/admin/research.google.com/archive/chubby-osdi06.pdf">chubby</a><span style="font-family: 宋体">基本一致</span>.zookeeper<span style="font-family: 宋体">的官方网站已经写了一篇非常经典的概述性文章</span>,<span style="font-family: 宋体">请大家参阅</span>:<a href="http://hadoop.apache.org/zookeeper/docs/r3.3.2/zookeeperOver.html">ZooKeeper: A Distributed Coordination Service for Distributed Applications</a>.</p> <p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://www.cnblogs.com/phinecos/archive/2012/02/10/2345634.html"><span style="font-family: 宋体">上一篇</span></a><span style="font-family: 宋体">的示例中是在启动每个</span>solr<span style="font-family: 宋体">服务器前，内嵌启动了一个</span>Zookeeper<span style="font-family: 宋体">服务器，再将这几台</span>Zookeeper<span style="font-family: 宋体">服务器组成一个集群，确保</span>Solr<span style="font-family: 宋体">集群信息的高可用性和容错性。</span></p><p><span style="font-family: 宋体">&nbsp;&nbsp; &nbsp; &nbsp;构建一个可用的</span>Zookeeper<span style="font-family: 宋体">集群，这就是</span>SolrCloud<span style="font-family: 宋体">要做的第一件工作。</span><span style="font-family: 宋体">下面来看下</span>SolrCloud<span style="font-family: 宋体">是如何实现这一功能的：</span></p> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt">1）&nbsp;<span style="font-family: 宋体">首先在</span>web.xml<span style="font-family: 宋体">中配置了一个</span>filter</p> <div> <div><span style="color: #0000ff">&lt;</span><span style="color: #800000">filter</span><span style="color: #0000ff">&gt;</span><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">&lt;</span><span style="color: #800000">filter-name</span><span style="color: #0000ff">&gt;</span>SolrRequestFilter<span style="color: #0000ff">&lt;/</span><span style="color: #800000">filter-name</span><span style="color: #0000ff">&gt;</span><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">&lt;</span><span style="color: #800000">filter-class</span><span style="color: #0000ff">&gt;</span>org.apache.solr.servlet.SolrDispatchFilter<span style="color: #0000ff">&lt;/</span><span style="color: #800000">filter-class</span><span style="color: #0000ff">&gt;</span><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">&lt;/</span><span style="color: #800000">filter</span><span style="color: #0000ff">&gt;</span></div></div> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt"><span>&nbsp;&nbsp; </span><span style="font-family: 宋体;">在</span>web<span style="font-family: 宋体;">容器启动时会去加载并初始化</span>SolrDispatchFilter<span style="font-family: 宋体;">这个</span>filter,<span style="font-family: 宋体;">它的</span>init<span style="font-family: 宋体;">方法会被调用，这个方法中做的最主要的事情是初始化一个</span>Solr<span style="font-family: 宋体;">核容器。</span></p> <div> <div>&nbsp;&nbsp;CoreContainer.Initializer&nbsp;init&nbsp;=&nbsp;createInitializer();<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000">//</span><span style="color: #008000">&nbsp;web.xml&nbsp;configuration</span><span style="color: #008000"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">this</span>.pathPrefix&nbsp;=&nbsp;config.getInitParameter(&nbsp;"path-prefix"&nbsp;);<br /><span style="color: #0000ff">this</span>.cores&nbsp;=&nbsp;init.initialize();</div></div> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt">&nbsp;2)&nbsp;<span style="font-family: 宋体">初始化</span>Solr<span style="font-family: 宋体">核容器时，首先找到</span>solr<span style="font-family: 宋体">的根目录，这个目录下最重要的是</span>solr.xml<span style="font-family: 宋体">这个配置文件，这个配置文件用于初始化容器中加载的各个</span>solr<span style="font-family: 宋体">核，如果没有提供</span>solr.xml<span style="font-family: 宋体">，则会启用默认的配置信息：</span> </p> <div> <div>&nbsp;&nbsp;<span style="color: #0000ff">private</span>&nbsp;<span style="color: #0000ff">static</span>&nbsp;<span style="color: #0000ff">final</span>&nbsp;String&nbsp;DEF_SOLR_XML&nbsp;="&lt;?xml&nbsp;version=\"1.0\"&nbsp;encoding=\"UTF-8\"&nbsp;?&gt;\n"&nbsp;+<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"&lt;solr&nbsp;persistent=\"false\"&gt;\n"&nbsp;+<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"&nbsp;&nbsp;&lt;cores&nbsp;adminPath=\"/admin/cores\"&nbsp;defaultCoreName=\""&nbsp;+&nbsp;DEFAULT_DEFAULT_CORE_NAME&nbsp;+&nbsp;"\"&gt;\n"&nbsp;+<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"&nbsp;&nbsp;&nbsp;&nbsp;&lt;core&nbsp;name=\""+&nbsp;DEFAULT_DEFAULT_CORE_NAME&nbsp;+&nbsp;"\"&nbsp;shard=\"${shard:}\"&nbsp;instanceDir=\".\"&nbsp;/&gt;\n"&nbsp;+<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"&nbsp;&nbsp;&lt;/cores&gt;\n"&nbsp;+<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"&lt;/solr&gt;";</div></div> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt">&nbsp;&nbsp;3）&nbsp;<span style="font-family: 宋体">初始化过程的其中一步就是初始化</span>Zookeeper<span style="font-family: 宋体">服务器，你可以选择单机的</span>Zookeeper<span style="font-family: 宋体">服务器，也可以构建</span>Zookeeper<span style="font-family: 宋体">集群，下面以集群为例进行代码分析。</span></p> <div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div> <div>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(zkRun&nbsp;!=&nbsp;<span style="color: #0000ff">null</span>)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zkServer&nbsp;=&nbsp;<span style="color: #0000ff">new</span>&nbsp;SolrZkServer(zkRun,&nbsp;zookeeperHost,&nbsp;solrHome,&nbsp;hostPort);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zkServer.parseConfig();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zkServer.start();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000">//</span><span style="color: #008000">&nbsp;set&nbsp;client&nbsp;from&nbsp;server&nbsp;config&nbsp;if&nbsp;not&nbsp;already&nbsp;set</span><span style="color: #008000"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(zookeeperHost&nbsp;==&nbsp;<span style="color: #0000ff">null</span>)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zookeeperHost&nbsp;=&nbsp;zkServer.getClientString();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div></div> <p><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SolrZkServer</span><span style="font-family: 宋体;">类就是伴随</span>solr<span style="font-family: 宋体;">启动的内嵌的</span>Zookeeper<span style="font-family: 宋体;">服务器，首先来看</span>parseConfig<span style="font-family: 宋体;">方法，它负责解析</span>zoo.cfg<span style="font-family: 宋体;">文件，读取</span>Zookeeper<span style="font-family: 宋体;">启动时所需要的配置信息，这些配置信息由</span>SolrZkServerProps<span style="font-family: 宋体;">类表示，</span></p> <p style="text-indent: 21pt;"><span style="font-family: 宋体;">首先设置</span>Zookeeper<span style="font-family: 宋体;">存储数据的目录</span></p> <div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div> <div>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(zkProps&nbsp;==&nbsp;<span style="color: #0000ff">null</span>)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zkProps&nbsp;=&nbsp;<span style="color: #0000ff">new</span>&nbsp;SolrZkServerProps();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000">//</span><span style="color: #008000">&nbsp;set&nbsp;default&nbsp;data&nbsp;dir<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;TODO:&nbsp;use&nbsp;something&nbsp;based&nbsp;on&nbsp;IP+port???&nbsp;&nbsp;support&nbsp;ensemble&nbsp;all&nbsp;from&nbsp;same&nbsp;solr&nbsp;home?</span><span style="color: #008000"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zkProps.setDataDir(solrHome&nbsp;+&nbsp;'/'&nbsp;+&nbsp;"zoo_data");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zkProps.zkRun&nbsp;=&nbsp;zkRun;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zkProps.solrPort&nbsp;=&nbsp;solrPort;<br />}</div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div></div> <p style="text-indent: 21pt;"><span style="font-family: 宋体; color: black; font-size: 10pt;'Courier New';'Courier New';'Courier New';">然后读取</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt;">zoo.cfg</span><span style="font-family: 宋体; color: black; font-size: 10pt;'Courier New';'Courier New';'Courier New';">配置文件中的信息，为启动</span><span style="font-family: 'Courier New'; color: black; font-size: 10pt;">zookeeper</span><span style="font-family: 宋体; color: black; font-size: 10pt;'Courier New';'Courier New';'Courier New';">服务器提供完整的配置信息，</span></p> <div> <div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;props&nbsp;=&nbsp;SolrZkServerProps.getProperties(solrHome&nbsp;+&nbsp;'/'&nbsp;+&nbsp;"zoo.cfg");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SolrZkServerProps.injectServers(props,&nbsp;zkRun,&nbsp;zkHost);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zkProps.parseProperties(props);</div></div> <p><span style="font-family: 'Courier New'; color: black; font-size: 10pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: 宋体; color: black; font-size: 10pt">下面是一个示例配置文件：</span></p> <div> <div>tickTime=2000<br />dataDir=/var/zookeeper/<br />clientPort=2181<br />initLimit=5<br />syncLimit=2<br />server.1=zoo1:2888:3888<br />server.2=zoo2:2888:3888<br />server.3=zoo3:2888:3888</div></div> <p style="text-indent: 21pt"><span style="font-family: 宋体; color: #333333">注意，</span><span style="font-family: 'Tahoma','sans-serif'; color: #333333">server.x</span><span style="font-family: 宋体; color: #333333">这些行就指明了</span><span style="font-family: 'Tahoma','sans-serif'; color: #333333">zookeeper</span><span style="font-family: 宋体; color: #333333">集群所包含的机器名称，每台</span><span style="font-family: 'Tahoma','sans-serif'; color: #333333">Zookeeper</span><span style="font-family: 宋体; color: #333333">服务器会使用</span><span style="font-family: 'Tahoma','sans-serif'; color: #333333">3</span><span style="font-family: 宋体; color: #333333">个端口来进行工作，其中第一个端口（端口</span><span style="font-family: 'Tahoma','sans-serif'; color: #333333">1</span><span style="font-family: 宋体; color: #333333">）用来做运行期间</span><span style="font-family: 'Tahoma','sans-serif'; color: #333333">server</span><span style="font-family: 宋体; color: #333333">间的通信，第二个端口（端口</span><span style="font-family: 'Tahoma','sans-serif'; color: #333333">2</span><span style="font-family: 宋体; color: #333333">）用来做</span><span style="font-family: 'Tahoma','sans-serif'; color: #333333">leader election</span><span style="font-family: 宋体; color: #333333">，另外还有一个端口（端口</span><span style="font-family: 'Tahoma','sans-serif'; color: #333333">0</span><span style="font-family: 宋体; color: #333333">）负责接收客户端请求。那么一台机器怎样确定自己是谁呢？这是通过</span><span style="font-family: 'Tahoma','sans-serif'; color: #333333">dataDir</span><span style="font-family: 宋体; color: #333333">目录下的</span><span style="font-family: 'Tahoma','sans-serif'; color: #333333">myid</span><span style="font-family: 宋体; color: #333333">文本文件确定。</span><span style="font-family: 'Tahoma','sans-serif'; color: #333333">myid</span><span style="font-family: 宋体; color: #333333">文件只包含一个数字，内容就是所在</span><span style="font-family: 'Tahoma','sans-serif'; color: #333333">Server</span><span style="font-family: 宋体; color: #333333">的</span><span style="font-family: 'Tahoma','sans-serif'; color: #333333">ID</span><span style="font-family: 宋体; color: #333333">：</span><span style="font-family: 'Tahoma','sans-serif'; color: #333333">QuorumPeerConfig.myid</span><span style="font-family: 宋体; color: #333333">。</span></p> <p style="text-indent: -18pt; margin: 0cm 0cm 0pt 39pt"><span style="font-family: 'Tahoma','sans-serif'; color: #333333">1） </span><span style="font-family: 宋体; color: #333333">准备好集群所需要的配置信息后，就可以启动</span><span style="font-family: 'Tahoma','sans-serif'; color: #333333">Zookeeper</span><span style="font-family: 宋体; color: #333333">集群了。启动时是生成一个</span><span style="font-family: 'Tahoma','sans-serif'; color: #333333">Zookeeper</span><span style="font-family: 宋体; color: #333333">服务器线程，根据配置信息来决定是单机还是集群模式，如果是单机模式，则生成</span>ZooKeeperServerMain<span style="font-family: 宋体">对象并启动，如果是集群模式，则使用</span>QuorumPeerMain<span style="font-family: 宋体">对象启动。最后将服务器线程设置为</span>Daemon<span style="font-family: 宋体">模式，就完成了</span>Zookeeper<span style="font-family: 宋体">服务器的启动工作了。</span></p> <div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div> <div>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;<span style="color: #0000ff">void</span>&nbsp;start()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zkThread&nbsp;=&nbsp;<span style="color: #0000ff">new</span>&nbsp;Thread()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">public</span>&nbsp;<span style="color: #0000ff">void</span>&nbsp;run()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">try</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(zkProps.getServers().size()&nbsp;&gt;&nbsp;1)&nbsp;{<span style="color: #008000">//</span><span style="color: #008000">zk集群</span><span style="color: #008000"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;QuorumPeerMain&nbsp;zkServer&nbsp;=&nbsp;<span style="color: #0000ff">new</span>&nbsp;QuorumPeerMain();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zkServer.runFromConfig(zkProps);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(logger.isInfoEnabled())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info("启动zk服务器集群成功");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff">else</span>&nbsp;{<span style="color: #008000">//</span><span style="color: #008000">单机zk</span><span style="color: #008000"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ServerConfig&nbsp;sc&nbsp;=&nbsp;<span style="color: #0000ff">new</span>&nbsp;ServerConfig();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sc.readFrom(zkProps);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ZooKeeperServerMain&nbsp;zkServer&nbsp;=&nbsp;<span style="color: #0000ff">new</span>&nbsp;ZooKeeperServerMain();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zkServer.runFromConfig(sc);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(logger.isInfoEnabled())&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info("启动单机zk服务器成功");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info("ZooKeeper&nbsp;Server&nbsp;exited.");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff">catch</span>&nbsp;(Throwable&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.error("ZooKeeper&nbsp;Server&nbsp;ERROR",&nbsp;e);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">throw</span>&nbsp;<span style="color: #0000ff">new</span>&nbsp;SolrException(SolrException.ErrorCode.SERVER_ERROR,&nbsp;e);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">if</span>&nbsp;(zkProps.getServers().size()&nbsp;&gt;&nbsp;1)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info("STARTING&nbsp;EMBEDDED&nbsp;ENSEMBLE&nbsp;ZOOKEEPER&nbsp;SERVER&nbsp;at&nbsp;port&nbsp;"&nbsp;+&nbsp;zkProps.getClientPortAddress().getPort());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff">else</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info("STARTING&nbsp;EMBEDDED&nbsp;STANDALONE&nbsp;ZOOKEEPER&nbsp;SERVER&nbsp;at&nbsp;port&nbsp;"&nbsp;+&nbsp;zkProps.getClientPortAddress().getPort());&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zkThread.setDaemon(<span style="color: #0000ff">true</span>);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;zkThread.start();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">try</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(500);&nbsp;<span style="color: #008000">//</span><span style="color: #008000">&nbsp;pause&nbsp;for&nbsp;ZooKeeper&nbsp;to&nbsp;start</span><span style="color: #008000"><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000ff">catch</span>&nbsp;(Exception&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.error("STARTING&nbsp;ZOOKEEPER",&nbsp;e);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}</div><div><a title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码" /></a></div></div> <p style="text-indent: 21pt"><span style="font-family: 宋体">为了验证集群是否启动成功，可以使用</span>Zookeeper<span style="font-family: 宋体">提供的命令行工具进行验证，进入</span>bin<span style="font-family: 宋体">目录下，运行：</span></p> <div> <div>zkCli.cmd&nbsp;&#8211;server&nbsp;zookeeper服务器地址1:端口</div></div> <p><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp;&nbsp;这是连接到集群中</span>1<span style="font-family: 宋体">台</span>Zookeeper<span style="font-family: 宋体">服务器，然后创建一个</span>ZNode,<span style="font-family: 宋体">往其中加入一些数据，你再连接到集群中其他的服务器上，查看数据是否一致，即可知道</span>Zookeeper<span style="font-family: 宋体">集群是否已经构建成功。</span></p></div><img src ="http://www.blogjava.net/wangxinsh55/aggbug/382218.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/wangxinsh55/" target="_blank">SIMONE</a> 2012-07-04 18:40 <a href="http://www.blogjava.net/wangxinsh55/archive/2012/07/04/382218.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>