elasticsearch 源码index操作
这里介绍es的文档索引操作。index操作的入口是TransportIndexAction。对应的RequestHandler是父类中的OperationTransportHandler。调用OperationTransportHandler中的messageReceived方法,进而调用doExecute方法。doExecute主要逻辑:判断请求的index是否需要自动创建,若是request中指定了自动创建则调用createIndexAction来创建索引,并在创建成功后执行innerExecute方法,否则直接执行innerExecute方法。在此方法中调用了以下方法:
@Override
protected void doExecute(Request request, ActionListener<Response> listener) {
new AsyncShardOperationAction(request, listener).start();
}
在AsyncShardOperationAction构造方法中,获取request的replicationType属性,replicationType有三种,SYNC、ASYNC、DEFAULT。同步复制,异步复制,默认复制,当request的replicationType等于DEFAULT时,使用配置文件中的复制类型,默认是sync。也就是说实际上复制类型是两种。SYNC/ASYNC。
再来看start方法
1.调用checkGlobalBlock(clusterState, request)方法去检测cluster是否是write block。若是集群不允许写,则在timeout时间内会调用retry方法使用PrioritizedEsThreadPoolExecutor再去调用start方法或者集群状态改变时调用到此方法,若允许写则向下执行,超过timeout时间则返回响应信息
2.检查request的index并替换别名为索引,若是索引不存在则抛出索引不存在异常,上游catch到异常,并返回响应,不存在异常则向下执行。
3.调用checkRequestBlock(clusterState, request)来判断index是否write block,执行逻辑与步骤1相似。
4.调用shardIt = shards(clusterState, request);根据请求中的索引,文档id,routing,type,找到对应的IndexShardRoutingTable(分片路由信息,包含主和副),进而得到ShardIterator也就是shardIt,确定shardId的主要逻辑如下:
private int shardId(ClusterState clusterState, String index, String type, @Nullable String id, @Nullable String routing) {
//取余 得到对应的shardId
if (routing == null) { // 没有指定 路由
if (!useType) { //是否type 参与分片
return Math.abs(hash(id) % indexMetaData(clusterState, index).numberOfShards());
} else {
return Math.abs(hash(type, id) % indexMetaData(clusterState, index).numberOfShards());
}
}
//指定路由
return Math.abs(hash(routing) % indexMetaData(clusterState, index).numberOfShards());
}
5.若是shardIt的size为0,可能分片正在恢复或者ShardIterator初始化,调用retry,同步骤1类似。若是size不为0,则迭代shardIt,找到主分片,若是迭代玩没有主分片,则调用retry,同步骤1,若找到主分片执行6
6.判断主分片是否active,和主分片所在节点是否存在,若存在执行7,否则retry,同步骤1.
7.检查一致性,写一致性WriteConsistencyLevel有3中level,ONE/QUORUM/ALL,默认为QUORUM。根据一致性level计算所需写入分片的数量。若是shardIt中活跃的主分片和副本分片总数小于一致性的要求数量,则retry,同步骤1,否则向下执行。
8.判断当前执行节点是否是主分片节点,若是则交由INDEX线程池去执行,performOnPrimary方法。否则的话转发请求到主分片所在节点,从OperationTransportHandler处开始执行上边整个逻辑到调用performOnPrimary方法。
9.在主分片所在节点上调用performOnPrimary方法,在这个方法内部主要执行以下逻辑
1)调用shardOperationOnPrimary方法,先验证mapping中是否有_routing必须执行的配置,若是有request中必须有routing。然后根据index和shardId得到IndexShard对象,IndexShard是索引分片对象负责与分片操作和与lucene交互。索引有两种OPType,INDEX/CREATE,INDEX类型的若是有相同的文档则替代,CREATE若有相同的文档,不去替代,返回响应。最终通过Lucene中的IndexWriter的api索引文档,若是request中有refresh,则调用indexShard.refresh来refresh。
2)调用performReplicas,计算需要负责的数目。若是为ReplicationType.ASYNC,则直接返回响应,然后迭代所有其他副本分片,判断当前分片所在节点是否是本地节点,是的话调用shardOperationOnReplica来写入副本中,否则的话发送一个action为transportReplicaAction的请求,handler为ReplicaOperationTransportHandler,副本所在节点调用messageReceived方法中的shardOperationOnReplica方法来写入副本。shardOperationOnReplica方法的执行逻辑与shardOperationOnPrimary相似。
3)当所有副本返回成功,至此则索引成功,返回响应
shardOperationOnPrimary方法和shardOperationOnReplica方法中含有很多细节的部分,在源码笔记中记录。此处不在细介绍。
注
1.源码阅读笔记