深入剖析SolrCloud(二)

   上一篇介绍了SolrCloud的基本概念,从这一篇开始我将深入到其实现代码中进行剖析。

SolrCloud最重要的一点就是引入了ZooKeeper来统一管理各种配置和状态信息。zookeeper是一个开源分布式的服务,它提供了分布式协作,分布式同步,配置管理等功能. 其实现的功能与google的chubby基本一致.zookeeper的官方网站已经写了一篇非常经典的概述性文章,请大家参阅:ZooKeeper: A Distributed Coordination Service for Distributed Applications.
        上一篇的示例中是在启动每个solr服务器前,内嵌启动了一个Zookeeper服务器,再将这几台Zookeeper服务器组成一个集群,确保Solr集群信息的高可用性和容错性。
      构建一个可用的Zookeeper集群,这就是SolrCloud要做的第一件工作。下面来看下SolrCloud是如何实现这一功能的:
1) 首先在web.xml中配置了一个filter
 
  
  
  
  
  1. <filter> 
  2.     <filter-name>SolrRequestFilter</filter-name
  3.     <filter-class>org.apache.solr.servlet.SolrDispatchFilter</filter-class> 
  4.       </filter> 

在web容器启动时会去加载并初始化SolrDispatchFilter这个filter,它的init方法会被调用,这个方法中做的最主要的事情是初始化一个Solr核容器。

 

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

2) 初始化Solr核容器时,首先找到solr的根目录,这个目录下最重要的是solr.xml这个配置文件,这个配置文件用于初始化容器中加载的各个solr核,如果没有提供solr.xml,则会启用默认的配置信息:

 

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

 3) 初始化过程的其中一步就是初始化Zookeeper服务器,你可以选择单机的Zookeeper服务器,也可以构建Zookeeper集群,下面以集群为例进行代码分析。

 

  
  
  
  
  1.     if (zkRun != null) { 
  2.       zkServer = new SolrZkServer(zkRun, zookeeperHost, solrHome, hostPort); 
  3.       zkServer.parseConfig(); 
  4.       zkServer.start(); 
  5.        
  6.       // set client from server config if not already set 
  7.       if (zookeeperHost == null) { 
  8.         zookeeperHost = zkServer.getClientString(); 
  9.       } 

 

 SolrZkServer类就是伴随solr启动的内嵌的Zookeeper服务器,首先来看parseConfig方法,它负责解析zoo.cfg文件,读取Zookeeper启动时所需要的配置信息,这些配置信息由SolrZkServerProps类表示,

首先设置Zookeeper存储数据的目录

 

  
  
  
  
  1. if (zkProps == null) { 
  2.   zkProps = new SolrZkServerProps(); 
  3.   // set default data dir 
  4.   // TODO: use something based on IP+port???  support ensemble all from same solr home? 
  5.   zkProps.setDataDir(solrHome + '/' + "zoo_data"); 
  6.   zkProps.zkRun = zkRun; 
  7.   zkProps.solrPort = solrPort; 

 

然后读取zoo.cfg配置文件中的信息,为启动zookeeper服务器提供完整的配置信息,

 

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

 下面是一个示例配置文件:

 

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

 

注意,server.x这些行就指明了zookeeper集群所包含的机器名称,每台Zookeeper服务器会使用3个端口来进行工作,其中第一个端口(端口1)用来做运行期间server间的通信,第二个端口(端口2)用来做leader election,另外还有一个端口(端口0)负责接收客户端请求。那么一台机器怎样确定自己是谁呢?这是通过dataDir目录下的myid文本文件确定。myid文件只包含一个数字,内容就是所在Server的ID:QuorumPeerConfig.myid。

1) 准备好集群所需要的配置信息后,就可以启动Zookeeper集群了。启动时是生成一个Zookeeper服务器线程,根据配置信息来决定是单机还是集群模式,如果是单机模式,则生成ZooKeeperServerMain对象并启动,如果是集群模式,则使用QuorumPeerMain对象启动。最后将服务器线程设置为Daemon模式,就完成了Zookeeper服务器的启动工作了。

 

  
  
  
  
  1. public void start() { 
  2.     zkThread = new Thread() { 
  3.         @Override 
  4.         public void run() { 
  5.             try { 
  6.                 if (zkProps.getServers().size() > 1) {//zk集群 
  7.                     QuorumPeerMain zkServer = new QuorumPeerMain(); 
  8.                     zkServer.runFromConfig(zkProps); 
  9.                     if (logger.isInfoEnabled()) { 
  10.                         logger.info("启动zk服务器集群成功"); 
  11.                     } 
  12.                 } else {//单机zk 
  13.                     ServerConfig sc = new ServerConfig(); 
  14.                     sc.readFrom(zkProps); 
  15.                     ZooKeeperServerMain zkServer = new ZooKeeperServerMain(); 
  16.                     zkServer.runFromConfig(sc); 
  17.                     if (logger.isInfoEnabled()) { 
  18.                         logger.info("启动单机zk服务器成功"); 
  19.                     } 
  20.                 } 
  21.                 logger.info("ZooKeeper Server exited."); 
  22.             } catch (Throwable e) { 
  23.                 logger.error("ZooKeeper Server ERROR", e); 
  24.                 throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);                     
  25.             } 
  26.         } 
  27.     }; 
  28.     if (zkProps.getServers().size() > 1) { 
  29.         logger.info("STARTING EMBEDDED ENSEMBLE ZOOKEEPER SERVER at port " + zkProps.getClientPortAddress().getPort()); 
  30.     } else { 
  31.         logger.info("STARTING EMBEDDED STANDALONE ZOOKEEPER SERVER at port " + zkProps.getClientPortAddress().getPort());             
  32.     } 
  33.      
  34.     zkThread.setDaemon(true); 
  35.     zkThread.start(); 
  36.     try { 
  37.         Thread.sleep(500); // pause for ZooKeeper to start 
  38.     } catch (Exception e) { 
  39.         logger.error("STARTING ZOOKEEPER", e); 
  40.     } 

 

为了验证集群是否启动成功,可以使用Zookeeper提供的命令行工具进行验证,进入bin目录下,运行:

 

  
  
  
  
  1. zkCli.cmd –server zookeeper服务器地址1:端口 

这是连接到集群中1台Zookeeper服务器,然后创建一个ZNode,往其中加入一些数据,你再连接到集群中其他的服务器上,查看数据是否一致,即可知道Zookeeper集群是否已经构建成功。

你可能感兴趣的:(java,随笔,java语言,solrCloud,休闲)