posts - 495,comments - 227,trackbacks - 0
          http://www.cnblogs.com/phinecos/archive/2012/02/15/2353007.html

            上一篇介紹了SolrCloud的基本概念,從這一篇開始我將深入到其實(shí)現(xiàn)代碼中進(jìn)行剖析。

          SolrCloud最重要的一點(diǎn)就是引入了ZooKeeper來統(tǒng)一管理各種配置和狀態(tài)信息。zookeeper是一個(gè)開源分布式的服務(wù),它提供了分布式協(xié)作,分布式同步,配置管理等功能. 其實(shí)現(xiàn)的功能與googlechubby基本一致.zookeeper的官方網(wǎng)站已經(jīng)寫了一篇非常經(jīng)典的概述性文章,請大家參閱:ZooKeeper: A Distributed Coordination Service for Distributed Applications.

                  上一篇的示例中是在啟動(dòng)每個(gè)solr服務(wù)器前,內(nèi)嵌啟動(dòng)了一個(gè)Zookeeper服務(wù)器,再將這幾臺Zookeeper服務(wù)器組成一個(gè)集群,確保Solr集群信息的高可用性和容錯(cuò)性。

                構(gòu)建一個(gè)可用的Zookeeper集群,這就是SolrCloud要做的第一件工作。下面來看下SolrCloud是如何實(shí)現(xiàn)這一功能的:

          1) 首先在web.xml中配置了一個(gè)filter

          <filter>
              <filter-name>SolrRequestFilter</filter-name>
              <filter-class>org.apache.solr.servlet.SolrDispatchFilter</filter-class>
                </filter>

             web容器啟動(dòng)時(shí)會去加載并初始化SolrDispatchFilter這個(gè)filter,它的init方法會被調(diào)用,這個(gè)方法中做的最主要的事情是初始化一個(gè)Solr核容器。

            CoreContainer.Initializer init = createInitializer();
              // web.xml configuration
              this.pathPrefix = config.getInitParameter( "path-prefix" );
          this.cores = init.initialize();

           2) 初始化Solr核容器時(shí),首先找到solr的根目錄,這個(gè)目錄下最重要的是solr.xml這個(gè)配置文件,這個(gè)配置文件用于初始化容器中加載的各個(gè)solr核,如果沒有提供solr.xml,則會啟用默認(rèn)的配置信息:

            private static final String DEF_SOLR_XML ="<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
                    "<solr persistent=\"false\">\n" +
                    "  <cores adminPath=\"/admin/cores\" defaultCoreName=\"" + DEFAULT_DEFAULT_CORE_NAME + "\">\n" +
                    "    <core name=\""+ DEFAULT_DEFAULT_CORE_NAME + "\" shard=\"${shard:}\" instanceDir=\".\" />\n" +
                    "  </cores>\n" +
                    "</solr>";

            3) 初始化過程的其中一步就是初始化Zookeeper服務(wù)器,你可以選擇單機(jī)的Zookeeper服務(wù)器,也可以構(gòu)建Zookeeper集群,下面以集群為例進(jìn)行代碼分析。

          復(fù)制代碼
              if (zkRun != null) {
                zkServer = new SolrZkServer(zkRun, zookeeperHost, solrHome, hostPort);
                zkServer.parseConfig();
                zkServer.start();
                
                // set client from server config if not already set
                if (zookeeperHost == null) {
                  zookeeperHost = zkServer.getClientString();
                }
          }
          復(fù)制代碼

                   SolrZkServer類就是伴隨solr啟動(dòng)的內(nèi)嵌的Zookeeper服務(wù)器,首先來看parseConfig方法,它負(fù)責(zé)解析zoo.cfg文件,讀取Zookeeper啟動(dòng)時(shí)所需要的配置信息,這些配置信息由SolrZkServerProps類表示,

          首先設(shè)置Zookeeper存儲數(shù)據(jù)的目錄

          復(fù)制代碼
              if (zkProps == null) {
                zkProps = new SolrZkServerProps();
                // set default data dir
                
          // TODO: use something based on IP+port???  support ensemble all from same solr home?
                zkProps.setDataDir(solrHome + '/' + "zoo_data");
                zkProps.zkRun = zkRun;
                zkProps.solrPort = solrPort;
          }
          復(fù)制代碼

          然后讀取zoo.cfg配置文件中的信息,為啟動(dòng)zookeeper服務(wù)器提供完整的配置信息,

                props = SolrZkServerProps.getProperties(solrHome + '/' + "zoo.cfg");
                SolrZkServerProps.injectServers(props, zkRun, zkHost);
                zkProps.parseProperties(props);

              下面是一個(gè)示例配置文件:

          tickTime=2000
          dataDir=/var/zookeeper/
          clientPort=2181
          initLimit=5
          syncLimit=2
          server.1=zoo1:2888:3888
          server.2=zoo2:2888:3888
          server.3=zoo3:2888:3888

          注意,server.x這些行就指明了zookeeper集群所包含的機(jī)器名稱,每臺Zookeeper服務(wù)器會使用3個(gè)端口來進(jìn)行工作,其中第一個(gè)端口(端口1)用來做運(yùn)行期間server間的通信,第二個(gè)端口(端口2)用來做leader election,另外還有一個(gè)端口(端口0)負(fù)責(zé)接收客戶端請求。那么一臺機(jī)器怎樣確定自己是誰呢?這是通過dataDir目錄下的myid文本文件確定。myid文件只包含一個(gè)數(shù)字,內(nèi)容就是所在ServerIDQuorumPeerConfig.myid

          1) 準(zhǔn)備好集群所需要的配置信息后,就可以啟動(dòng)Zookeeper集群了。啟動(dòng)時(shí)是生成一個(gè)Zookeeper服務(wù)器線程,根據(jù)配置信息來決定是單機(jī)還是集群模式,如果是單機(jī)模式,則生成ZooKeeperServerMain對象并啟動(dòng),如果是集群模式,則使用QuorumPeerMain對象啟動(dòng)。最后將服務(wù)器線程設(shè)置為Daemon模式,就完成了Zookeeper服務(wù)器的啟動(dòng)工作了。

          復(fù)制代碼
              public void start() {
                  zkThread = new Thread() {
                      @Override
                      public void run() {
                          try {
                              if (zkProps.getServers().size() > 1) {//zk集群
                                  QuorumPeerMain zkServer = new QuorumPeerMain();
                                  zkServer.runFromConfig(zkProps);
                                  if (logger.isInfoEnabled()) {
                                      logger.info("啟動(dòng)zk服務(wù)器集群成功");
                                  }
                              } else {//單機(jī)zk
                                  ServerConfig sc = new ServerConfig();
                                  sc.readFrom(zkProps);
                                  ZooKeeperServerMain zkServer = new ZooKeeperServerMain();
                                  zkServer.runFromConfig(sc);
                                  if (logger.isInfoEnabled()) {
                                      logger.info("啟動(dòng)單機(jī)zk服務(wù)器成功");
                                  }
                              }
                              logger.info("ZooKeeper Server exited.");
                          } catch (Throwable e) {
                              logger.error("ZooKeeper Server ERROR", e);
                              throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);                    
                          }
                      }
                  };
                  if (zkProps.getServers().size() > 1) {
                      logger.info("STARTING EMBEDDED ENSEMBLE ZOOKEEPER SERVER at port " + zkProps.getClientPortAddress().getPort());
                  } else {
                      logger.info("STARTING EMBEDDED STANDALONE ZOOKEEPER SERVER at port " + zkProps.getClientPortAddress().getPort());            
                  }
                  
                  zkThread.setDaemon(true);
                  zkThread.start();
                  try {
                      Thread.sleep(500); // pause for ZooKeeper to start
                  } catch (Exception e) {
                      logger.error("STARTING ZOOKEEPER", e);
                  }
              }
          復(fù)制代碼

          為了驗(yàn)證集群是否啟動(dòng)成功,可以使用Zookeeper提供的命令行工具進(jìn)行驗(yàn)證,進(jìn)入bin目錄下,運(yùn)行:

          zkCli.cmd –server zookeeper服務(wù)器地址1:端口

              這是連接到集群中1Zookeeper服務(wù)器,然后創(chuàng)建一個(gè)ZNode,往其中加入一些數(shù)據(jù),你再連接到集群中其他的服務(wù)器上,查看數(shù)據(jù)是否一致,即可知道Zookeeper集群是否已經(jīng)構(gòu)建成功。

          posted on 2012-07-04 18:40 SIMONE 閱讀(3491) 評論(0)  編輯  收藏 所屬分類: solr
          主站蜘蛛池模板: 昭觉县| 苏州市| 新民市| 梁山县| 淮南市| 天柱县| 连江县| 赤水市| 安岳县| 玛沁县| 白河县| 玛纳斯县| 绍兴市| 东宁县| 偏关县| 蓬莱市| 佳木斯市| 山西省| 大连市| 当雄县| 封开县| 阜新市| 巴楚县| 神农架林区| 兴仁县| 嘉定区| 从江县| 清徐县| 筠连县| 花莲县| 九台市| 垫江县| 东乡族自治县| 沾益县| 永寿县| 兴海县| 靖边县| 冀州市| 读书| 白城市| 平定县|