Action这一部分主要是数据(索引)的操作和部分集群信息操作。 所有的请求通过client转发到对应的action上然后再由对应的TransportAction来执行相关请求。如果请求能在本机上执行则在本机上执行,否则使用Transport进行转发到对应的节点。action support部分是对action的抽象,所有的具体action都继承了support action中的某个类。这里将对这些抽象类进行分析。

这一部分总共分为broadcast(广播),master,nodes,replication及single几个部分。broadcast主要针对一些无具体目标主机的操作,如查询index是否存在,所有继承这个类的action都具有这种类似的性质;nodes主要是对节点的操作,如热点线程查询(hotThread)查询节点上的繁忙线程;replication的子类主要是需要或可以在副本上进行的操作,如索引操作,数据不仅要发送到主shard还要发送到各个副本。single则主要是目标明确的单shard操作,如get操作,根据doc的id取doc,doc 的id能够确定它在哪个shard上,因此操作也在此shard上执行。

这些support action的实现可以分为两类,第一类就是实现一个内部类作为异步操作器,子类执行doExecute时,初始化该操作器并启动。另外一种就是直接实现一个方法,子类doExecute方法调用该方法进行。TransportBroadcastOperationAction就属于前者,它实现了内部操作器AsyncBroadcastAction。TransportCountAction继承于它,它doExecute方法如下所示:

 @Override
protected void doExecute(CountRequest request, ActionListener<CountResponse> listener) {
request.nowInMillis = System.currentTimeMillis();
super.doExecute(request, listener);
}

调用父类的doExecute方法,也就是TransportBroadcastOperationAction的方法,它的实现如下所示:

 @Override
protected void doExecute(Request request, ActionListener<Response> listener) {
new AsyncBroadcastAction(request, listener).start();
}

可以看到它初始化了AsyncBroadcastAction并启动。AsyncBroadcastAction只是确定了操作的流程,及操作完成如何返回response,并未涉及到具体的操作逻辑。因为这些逻辑都在每个子action中实现,不同的action需要进行不同的操作。如count需要count每个shard并且返回最后的总数值,而IndexExistAction则需要对比所有索引查看查询的索引是否存在。start方法的代码如下所示:

public void start() {
      //没有shards
if (shardsIts.size() == 0) {
// no shards
try {
listener.onResponse(newResponse(request, new AtomicReferenceArray(0), clusterState));
} catch (Throwable e) {
listener.onFailure(e);
}
return;
}
request.beforeStart();
// count the local operations, and perform the non local ones
int shardIndex = -1;
       //遍历对每个shards进行操作
for (final ShardIterator shardIt : shardsIts) {
shardIndex++;
final ShardRouting shard = shardIt.nextOrNull();
if (shard != null) {
performOperation(shardIt, shard, shardIndex);
} else {
// really, no shards active in this group
onOperation(null, shardIt, shardIndex, new NoShardAvailableActionException(shardIt.shardId()));
}
}
}

start方法就是遍历所有shards,如果shard存在则执行performOperation方法,在这个方法中会区分该请求能否在本机上进行,能执行则调用shardOperation方法得到结果。这个方法在这是抽象的,每个子类都有实现。否则发送到对应的主机上。,如果shard为null则进行onOperation操作,遍历该shard的其它副本看能否找到可以操作的shard。performOperation代码如下所示:

 protected void performOperation(final ShardIterator shardIt, final ShardRouting shard, final int shardIndex) {
if (shard == null) {//shard 为null抛出异常
// no more active shards... (we should not really get here, just safety)
onOperation(null, shardIt, shardIndex, new NoShardAvailableActionException(shardIt.shardId()));
} else {
try {
final ShardRequest shardRequest = newShardRequest(shardIt.size(), shard, request);
if (shard.currentNodeId().equals(nodes.localNodeId())) {//shard在本地执行shardOperation方法,并通过onOperation方法封装结果
threadPool.executor(executor).execute(new Runnable() {
@Override
public void run() {
try {
onOperation(shard, shardIndex, shardOperation(shardRequest));
} catch (Throwable e) {
onOperation(shard, shardIt, shardIndex, e);
}
}
});
} else {//不是本地shard,发送到对应节点。
DiscoveryNode node = nodes.get(shard.currentNodeId());
if (node == null) {
// no node connected, act as failure
onOperation(shard, shardIt, shardIndex, new NoShardAvailableActionException(shardIt.shardId()));
} else {
transportService.sendRequest(node, transportShardAction, shardRequest, new BaseTransportResponseHandler<ShardResponse>() {
@Override
public ShardResponse newInstance() {
return newShardResponse();
} @Override
public String executor() {
return ThreadPool.Names.SAME;
} @Override
public void handleResponse(ShardResponse response) {
onOperation(shard, shardIndex, response);
} @Override
public void handleException(TransportException e) {
onOperation(shard, shardIt, shardIndex, e);
}
});
}
}
} catch (Throwable e) {
onOperation(shard, shardIt, shardIndex, e);
}
}
}

方法shardOperation在countTransportAction的实现如下所示:

    @Override
protected ShardCountResponse shardOperation(ShardCountRequest request) throws ElasticsearchException {
IndexService indexService = indicesService.indexServiceSafe(request.shardId().getIndex());//
IndexShard indexShard = indexService.shardSafe(request.shardId().id());
    //构造查询context
SearchShardTarget shardTarget = new SearchShardTarget(clusterService.localNode().id(), request.shardId().getIndex(), request.shardId().id());
SearchContext context = new DefaultSearchContext(0,
new ShardSearchLocalRequest(request.types(), request.nowInMillis(), request.filteringAliases()),
shardTarget, indexShard.acquireSearcher("count"), indexService, indexShard,
scriptService, cacheRecycler, pageCacheRecycler, bigArrays, threadPool.estimatedTimeInMillisCounter());
SearchContext.setCurrent(context); try {
// TODO: min score should move to be "null" as a value that is not initialized...
if (request.minScore() != -1) {
context.minimumScore(request.minScore());
}
BytesReference source = request.querySource();
if (source != null && source.length() > 0) {
try {
QueryParseContext.setTypes(request.types());
context.parsedQuery(indexService.queryParserService().parseQuery(source));
} finally {
QueryParseContext.removeTypes();
}
}
final boolean hasTerminateAfterCount = request.terminateAfter() != DEFAULT_TERMINATE_AFTER;
boolean terminatedEarly = false;
context.preProcess();
try {
long count;
if (hasTerminateAfterCount) {//调用lucene的封装接口执行查询并返回结果
final Lucene.EarlyTerminatingCollector countCollector =
Lucene.createCountBasedEarlyTerminatingCollector(request.terminateAfter());
terminatedEarly = Lucene.countWithEarlyTermination(context.searcher(), context.query(), countCollector);
count = countCollector.count();
} else {
count = Lucene.count(context.searcher(), context.query());
}
return new ShardCountResponse(request.shardId(), count, terminatedEarly);
} catch (Exception e) {
throw new QueryPhaseExecutionException(context, "failed to execute count", e);
}
} finally {
// this will also release the index searcher
context.close();
SearchContext.removeCurrent();
}
}

可以看到这里是每个action真正的逻辑实现。因为这里涉及到index部分的内容,这里就不详细分析。后面关于index的分析会有涉及。这就是support action中的第一种实现。

第二种就master的相关操作,因此没有实现对应的操作类,而只是实现了一个方法。该方法的作用跟操作器作用相同,唯一的不同是它没有操作器这么多的变量, 而且它不是异步的。master的操作需要实时进行,执行过程中需要阻塞某些操作,保证集群状态一致性。这里就不再说明,请参考TransportMasterNodeOperationAction原码。

总结:本篇概括说了support action,并以countTransportAction为例说明了support Action中的异步操作器实现,最后简单的分析了master的同步操作。因为这里涉及到很多action不可能一一分析,有兴趣可以参考对应的代码。而且这里有以下index部分的内容,所以没有更深入的分析。在后面分析完index的相关功能后,会挑出几个重要的action做详细分析。

action support分析的更多相关文章

  1. yii2 源码分析Action类分析 (六)

    Action类是控制器的基类, <?php namespace yii\base; use Yii; /** * Action是所有控制器动作类的基类,它继承组件类 * * 动作提供了重用动作方 ...

  2. Machine Learning in Action -- Support Vector Machines

    虽然SVM本身算法理论,水比较深,很难懂 但是基本原理却非常直观易懂,就是找到与训练集中支持向量有最大间隔的超平面 形式化的描述: 其中需要满足m个约束条件,m为数据集大小,即数据集中的每个数据点fu ...

  3. elasticsearch index 之 put mapping

    elasticsearch index 之 put mapping   mapping机制使得elasticsearch索引数据变的更加灵活,近乎于no schema.mapping可以在建立索引时设 ...

  4. elasticsearch index 之 create index(-)

    从本篇开始,就进入了Index的核心代码部分.这里首先分析一下索引的创建过程.elasticsearch中的索引是多个分片的集合,它只是逻辑上的索引,并不具备实际的索引功能,所有对数据的操作最终还是由 ...

  5. 利用Wireshark抓取并分析OpenFlow协议报文

    OpenFlow 交换机与控制器交互步骤 1. 利用Mininet仿真平台构建如下图所示的网络拓扑,配置主机h1和h2的IP地址(h1:10.0.0.1,h2:10.0.0.2),测试两台主机之间的网 ...

  6. ElasticSearch使用

    安装之前,请参考https://github.com/richardwilly98/elasticsearch-river-mongodb根据你的MongoDB版本号决定需要的elasticsearc ...

  7. StrutsPrepareAndExecuteFilter(转)

    http://www.iteye.com/topic/829843  一.概述 Struts2的核心是一个Filter,Action可以脱离web容器,那么是什么让http请求和action关联在一起 ...

  8. elasticsearch系列七:ES Java客户端-Elasticsearch Java client(ES Client 简介、Java REST Client、Java Client、Spring Data Elasticsearch)

    一.ES Client 简介 1. ES是一个服务,采用C/S结构 2. 回顾 ES的架构 3. ES支持的客户端连接方式 3.1 REST API ,端口 9200 这种连接方式对应于架构图中的RE ...

  9. Elasticsearch 集群和索引健康状态及常见错误说明

    之前在IDC机房线上环境部署了一套ELK日志集中分析系统, 这里简单总结下ELK中Elasticsearch健康状态相关问题, Elasticsearch的索引状态和集群状态传达着不同的意思. 一.  ...

随机推荐

  1. 洛谷 P2243 电路维修

    P2243 电路维修 题目背景 Elf 是来自Gliese 星球的少女,由于偶然的原因漂流到了地球上.在她无依无靠的时候,善良的运输队员Mark 和James 收留了她.Elf 很感谢Mark和Jam ...

  2. 设计模式实例(Lua)笔记之七(Decorator模式)

    1.描写叙述 就说说"我"上小学的的糗事吧. 我上小学的时候学习成绩非常的差,班级上 40 多个同学,我基本上都是在排名 45 名以后,依照老师给我的定义就是"不是读书的 ...

  3. hdu 5335 Walk Out 搜索+贪心

    Walk Out Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total S ...

  4. 使用Ant打包Android应用具体解释

    计划写个完整的使用Ant打包Android应用的系列文章.三篇文章.首篇具体介绍採用Ant打包Android应用的流程.列出部分定制问题及其解决方法,第二篇介绍我理解的Ant打包的思路与主要的概念和使 ...

  5. Git 时间,将代码托管到GitHub 上

    第一步:在github上创建一个项目,选择所属类型.会自动生成下面的文件. 第二步:使用安卓创建项目 第三步:使用git bash 进入项目目录,通过指令clone到本地 克隆完成后会出现下面的内容 ...

  6. vue 初始化项目模板报错

    E:\xiaogezi.cn\vue>vue init webpack myProject vue-cli · Failed to download repo vuejs-templates/w ...

  7. Windows 10 10586 升级

  8. Servlet基础(一)

    JavaEE:企业级开发技术 <一.基础概念>j2ee:jdk1.1--1.4   ----->>    j2ee1.1   1.2   javaee:jdk--5,6,7   ...

  9. 51nod 1632 B君的连通

    题目: 这题看起来难,其实这么多概率啥的都是唬人的.甚至连快速幂都不用就可以解. 解法:    n个节点,n-1条边,期望会有一半的边被炸毁(因为总体概率就是50%). 即(n-1)/2条边被炸毁,这 ...

  10. 【BZOJ4448】【SCOI2015】情报传递

    这题面错别字真tm多 题意: Description 奈特公司是一个巨大的情报公司,它有着庞大的情报网络.情报网络中共有n名情报员.每名情报员口J-能有若T名(可能没有)下线,除1名大头日外其余n-1 ...