Solr分布式索引过程源码解析

来源:互联网 发布:macbt下载软件 编辑:程序博客网 时间:2024/06/07 18:26

基于solr4.4

Solr分布式索引过程解析
单个节点的索引过程,以前写的blog http://blog.csdn.net/yangbutao/article/details/9851681 已经做了简单的分析
对于分布式索引,请求处理过程最终会在节点上建立本地索引,多了请求在node间分发的过程。
区别于单个节点的索引的索引处理processor Director2UpdateProcessor,分布式索引请求处理的请求处理是DistributedUpdateProcessor
DistributedUpdateProcessor.processAdd/commit
       -----SolrCmdDistributor.distribAdd/commit
在SolrCmdDistributor做索引的分发处理

1、对于索引的add操作:
void processAdd(AddUpdateCommand cmd){
//获取需要分发的nodes列表
       nodes = setupRequest(inthash)
        if (!forwardToLeader) {
 //当前节点是属于该id hash到的shard的leader节点或者replica节点
         dropCmd = versionAdd(cmd);
       }
     if (nodes != null) {
       //如果nodes列表不为空,比如当前节点是属于该id hash到的shard的leader节点或者当前节点是不属于该shard的节点
       //对于distribAdd,先flush当前节点pending的deletes,再根据当前的adds缓存中节点->add doc数量是否超过阀值,来决定是否向节点发送http add请求
      cmdDistrib.distribAdd(cmd, nodes, params);
    }
}

//获取需要转发的node列表
List<Node> setupRequest(String id, SolrInputDocument doc) {
   Slice slice = coll.getRouter().getTargetSlice(id, doc, req.getParams(), coll);
   String shardId = slice.getName();
    Replica leaderReplica = zkController.getZkStateReader().getLeaderRetry(
            collection, shardId);
     //当前节点是否是属于id hash到的shard的leader节点
    isLeader = leaderReplica.getName().equals(
            req.getCore().getCoreDescriptor().getCloudDescriptor()
                .getCoreNodeName());
    if (DistribPhase.FROMLEADER == phase && !isSubShardLeader) {
          // we are coming from the leader, just go local - add no urls
   //从id shard到的shard的leader节点转发过来的,不需要再转发
          forwardToLeader = false;
        } else if (isLeader || isSubShardLeader) {
          // that means I want to forward onto my replicas...
   //当前是id shard到的shard的leader节点,需要转发给其下的replicas节点
          // so get the replicas...
          forwardToLeader = false;
           ...............
         for (ZkCoreNodeProps props : replicaProps) {
                nodes.add(new StdNode(props));
              }
          }
        } else {
          // I need to forward onto the leader...
   //当前不是id shard到的shard的leader节点,所以需要转发给该leader节点
          nodes = new ArrayList<Node>(1);
          nodes.add(new RetryNode(new ZkCoreNodeProps(leaderReplica), zkController.getZkStateReader(), collection, shardId));
          forwardToLeader = true;
        }

   }
基本的逻辑是
对于分布式索引的add操作,首先调用setupRequest返回要分发的node列表
首先根据id做hash操作后的值和集群的shard的数据范围做比较,定位到某个shard上,
若请求所在的Node和该shard的leader不是一个节点(无论是请求在replica节点,还是不属于该shard的leader节点),请求都会转发到该shard的leader上;
后该shard的leader除了做本地化的索引操作外,还通过http方式,依次连接到该shard的replica节点上,做processAdd操作
该shard的replica节点接收到请求后,做本地化的索引添加操作。
举个例子:集群中有两个shard,分别为shard1和shard2,shard1包括node1(leader)、node2(replica),shard2包括node3(leader)、node4(replica);
客户端addDoc,doc id落到shard2的range区域;
如果请求是发到node1或者node2上或者node4上的,那么node2把请求转发给了node3,node3做本地化的索引操作,并转发给node4做本地化索引操作。

2、对于索引的commit操作processCommit:
访问任意一个节点
   列出该集群中所有得节点nodes,依次对每个节点进行distribCommit;
   distribCommit首先submit当前node上的pending的adds、deletes,后通过submit发送commit请求到集群中所有得nodes(commit_end_point=true&commit=true&softCommit=false)
   每个节点再做本地化的commit操作
   COMMIT_END_POINT=true
    if (!zkEnabled || req.getParams().getBool(COMMIT_END_POINT, false) || singleLeader) {
      doLocalCommit(cmd);
    }
    }


关于分布式环境下的如何Sharding分区,以及每个sharding的区间设置,sharding的拆分等在后面的章节做分析