我的编程空间,编程开发者的网络收藏夹
学习永远不晚

elasticsearch源码index action实现方式是什么

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

elasticsearch源码index action实现方式是什么

本篇内容主要讲解“elasticsearch源码index action实现方式是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“elasticsearch源码index action实现方式是什么”吧!

action的作用

上一篇从结构上分析了action的,本篇将以index action为例仔分析一下action的实现方式。

再概括一下action的作用:对于每种功能(如index)action都会包括两个基本的类*action(IndexAction)和Transport*action(TransportIndexAction),前者类中会有一个实例(IndexAction INSTANCE = new IndexAction())这个实例用于client绑定对应的TransportAction(registerAction(IndexAction.INSTANCE, TransportIndexAction.class)),绑定过程发送在ActionModuel中。

另外在Action类中还会定义一个action的名字(String NAME = "indices:data/write/index")这个名字用于TransportService绑定对于的handle,用于处理NettyTransport接收到的信息。TransportAction的是最终的逻辑处理者,当接收到请求时,会首先判断本节点能否处理,如果能够处理则调用相关的方法处理得到结果返回,否则将通过NettyTransport转发该请求到对应的node进行处理。所有的Transport的结构都是这种类型。

TransportAction的类图

首先看一下TransportAction的类图,所的Transport*action都继承自于它。

elasticsearch源码index action实现方式是什么

它主要由两个方法execute和doExecute,execute方法有两种实现,第一种实现需要自行添加actionListener。最终的逻辑都在doExecute方法中,这个方法在各个功能模块中实现。以下是TransportIndexAction的继承关系:

elasticsearch源码index action实现方式是什么

实现上由于功能划分的原因,TransportIndexAction直接继承自TranspShardReplicationOperationAction,这个抽象类中的方法是所有需要操作shard副本的功能action的父,因此它的实现还包括delete,bulk等功能action。它实现了多个内部类,这些内部类用来辅助完成相关的功能。这里主要说一下OperationTransportHandler,ReplicaOperationTransportHandler及AsyncShardOperationAction三个子类。

OperationTransportHandler的代码

如下所示:

class OperationTransportHandler extends BaseTransportRequestHandler<Request> {//继承自BaseTransportRequestHanlder………………        @Override        public void messageReceived(final Request request, final TransportChannel channel) throws Exception {            // no need to have a threaded listener since we just send back a response            request.listenerThreaded(false);            // if we have a local operation, execute it on a thread since we don't spawn            request.operationThreaded(true);      //调用Transport的execute方法,通过channel返回结果            execute(request, new ActionListener<Response>() {                @Override                public void onResponse(Response result) {                    try {                        channel.sendResponse(result);                    } catch (Throwable e) {                        onFailure(e);                    }                }                @Override                public void onFailure(Throwable e) {                    try {                        channel.sendResponse(e);                    } catch (Throwable e1) {                        logger.warn("Failed to send response for " + actionName, e1);                    }                }            });        }

看过NettyTransport请求发送和处理的同学一定对这个代码不陌生,这就是elasticsearch节点间处理信息的典型模式。当请求通过NettyTransport发送到本节点时会根据请求的action名称找到对应的handler,使用对应的handler来处理该请求。这个handler就对应着“indices:data/write/index”,可以看到它调用execute方法来处理。它的注册时在TransportShardReplicationOperationAction构造函数中完成的。

知道了OperationTransportHandler,ReplicaOperationTransportHandler就好理解了它的实现方式跟前者完全一样,对应的action名称加了一个“[r]”,它的作用是处理需要在副本上进行的操作,代码如下所示:

class ReplicaOperationTransportHandler extends BaseTransportRequestHandler<ReplicaOperationRequest> {……………………        @Override        public void messageReceived(final ReplicaOperationRequest request, final TransportChannel channel) throws Exception {            try {                shardOperationOnReplica(request);            } catch (Throwable t) {                failReplicaIfNeeded(request.shardId.getIndex(), request.shardId.id(), t);                throw t;            }            channel.sendResponse(TransportResponse.Empty.INSTANCE);        }    }

可以看到代码结构非常像,只是调用了副本操作的方法shardOperationOnReplica,这个方法在这TransportShardReplicationOperationAction中是抽象的,它的实现在各个子类中,例如deleteaction中实现了对于delete请求如何在副本上处理。

分析完这两个handle是不是对于action的处理过程有了一定的眉目了呢?但是这才是冰山一角,这两个Handler是用来接收来自其它节点的请求,如果请求的正好是本节点该如何处理呢?这些逻辑都在AsyncShardOperationAction类中。首先看一下它的内部结构:

elasticsearch源码index action实现方式是什么

因为TransportShardReplicationOperationAction的所有子类都是对索引的修改,会引起数据不一致,因此它的操作流程都是现在primaryShard上操作然后是Replicashard上操作。代码如下所示:

protected void doStart() throws ElasticsearchException {            try {          //检查是否有阻塞                ClusterBlockException blockException = checkGlobalBlock(observer.observedState());                if (blockException != null) {                    if (blockException.retryable()) {                        logger.trace("cluster is blocked ({}), scheduling a retry", blockException.getMessage());                        retry(blockException);                        return;                    } else {                        throw blockException;                    }                }          //检测是否是创建索引                if (resolveIndex()) {                    internalRequest.concreteIndex(observer.observedState().metaData().concreteSingleIndex(internalRequest.request().index(), internalRequest.request().indicesOptions()));                } else {                    internalRequest.concreteIndex(internalRequest.request().index());                }                // check if we need to execute, and if not, return                if (!resolveRequest(observer.observedState(), internalRequest, listener)) {                    return;                }          //再次检测是否有阻塞                blockException = checkRequestBlock(observer.observedState(), internalRequest);                if (blockException != null) {                    if (blockException.retryable()) {                        logger.trace("cluster is blocked ({}), scheduling a retry", blockException.getMessage());                        retry(blockException);                        return;                    } else {                        throw blockException;                    }                }                shardIt = shards(observer.observedState(), internalRequest);            } catch (Throwable e) {                listener.onFailure(e);                return;            }        //查找primaryShard            boolean foundPrimary = false;            ShardRouting shardX;            while ((shardX = shardIt.nextOrNull()) != null) {                final ShardRouting shard = shardX;                // we only deal with primary shardIt here...                if (!shard.primary()) {                    continue;                }                if (!shard.active() || !observer.observedState().nodes().nodeExists(shard.currentNodeId())) {                    logger.trace("primary shard [{}] is not yet active or we do not know the node it is assigned to [{}], scheduling a retry.", shard.shardId(), shard.currentNodeId());                    retryBecauseUnavailable(shardIt.shardId(), "Primary shard is not active or isn't assigned to a known node.");                    return;                }                if (!primaryOperationStarted.compareAndSet(false, true)) {                    return;                }                foundPrimary = true;          //primaryShard就在本地,直接进行相关操作                if (shard.currentNodeId().equals(observer.observedState().nodes().localNodeId())) {                    try {                        if (internalRequest.request().operationThreaded()) {                            internalRequest.request().beforeLocalFork();                            threadPool.executor(executor).execute(new Runnable() {                                @Override                                public void run() {                                    try {                                        performOnPrimary(shard.id(), shard);                                    } catch (Throwable t) {                                        listener.onFailure(t);                                    }                                }                            });                        } else {                            performOnPrimary(shard.id(), shard);                        }                    } catch (Throwable t) {                        listener.onFailure(t);                    }                } else {//primaryShard在其它节点上,将请求通过truansport发送到对应的节点。                    DiscoveryNode node = observer.observedState().nodes().get(shard.currentNodeId());                    transportService.sendRequest(node, actionName, internalRequest.request(), transportOptions, new BaseTransportResponseHandler<Response>() {                        @Override                        public Response newInstance() {                            return newResponseInstance();                        }                        @Override                        public String executor() {                            return ThreadPool.Names.SAME;                        }                        @Override                        public void handleResponse(Response response) {                            listener.onResponse(response);                        }                        @Override                        public void handleException(TransportException exp) {                            // if we got disconnected from the node, or the node / shard is not in the right state (being closed)                            if (exp.unwrapCause() instanceof ConnectTransportException || exp.unwrapCause() instanceof NodeClosedException ||                                    retryPrimaryException(exp)) {                                primaryOperationStarted.set(false);                                internalRequest.request().setCanHaveDuplicates();                                // we already marked it as started when we executed it (removed the listener) so pass false                                // to re-add to the cluster listener                                logger.trace("received an error from node the primary was assigned to ({}), scheduling a retry", exp.getMessage());                                retry(exp);                            } else {                                listener.onFailure(exp);                            }                        }                    });                }                break;            }            ………………        }

这就是对应请求的处理过程。

primary操作的方法

void performOnPrimary(int primaryShardId, final ShardRouting shard) {           ……                PrimaryResponse<Response, ReplicaRequest> response = shardOperationOnPrimary(clusterState, new PrimaryOperationRequest(primaryShardId, internalRequest.concreteIndex(), internalRequest.request()));                performReplicas(response);            …………        }

以上就是performOnPrimary方法的部分代码,首先调用外部类的shardOperationOnPrimary方法,该方法实现在各个子类中,在TransportIndexAction中的实现如下所示:

@Override    protected PrimaryResponse<IndexResponse, IndexRequest> shardOperationOnPrimary(ClusterState clusterState, PrimaryOperationRequest shardRequest) throws Throwable {        final IndexRequest request = shardRequest.request;        // 查看是否需要routing        IndexMetaData indexMetaData = clusterState.metaData().index(shardRequest.shardId.getIndex());        MappingMetaData mappingMd = indexMetaData.mappingOrDefault(request.type());        if (mappingMd != null && mappingMd.routing().required()) {            if (request.routing() == null) {                throw new RoutingMissingException(shardRequest.shardId.getIndex(), request.type(), request.id());            }        }      //调用indexserice执行对应的index操作        IndexService indexService = indicesService.indexServiceSafe(shardRequest.shardId.getIndex());        IndexShard indexShard = indexService.shardSafe(shardRequest.shardId.id());        SourceToParse sourceToParse = SourceToParse.source(SourceToParse.Origin.PRIMARY, request.source()).type(request.type()).id(request.id())                .routing(request.routing()).parent(request.parent()).timestamp(request.timestamp()).ttl(request.ttl());        long version;        boolean created;        try {            Engine.IndexingOperation op;            if (request.opType() == IndexRequest.OpType.INDEX) {                Engine.Index index = indexShard.prepareIndex(sourceToParse, request.version(), request.versionType(), Engine.Operation.Origin.PRIMARY, request.canHaveDuplicates());                if (index.parsedDoc().mappingsModified()) {                    mappingUpdatedAction.updateMappingOnMaster(shardRequest.shardId.getIndex(), index.docMapper(), indexService.indexUUID());                }                indexShard.index(index);                version = index.version();                op = index;                created = index.created();            } else {                Engine.Create create = indexShard.prepareCreate(sourceToParse,                        request.version(), request.versionType(), Engine.Operation.Origin.PRIMARY, request.canHaveDuplicates(), request.autoGeneratedId());                if (create.parsedDoc().mappingsModified()) {                    mappingUpdatedAction.updateMappingOnMaster(shardRequest.shardId.getIndex(), create.docMapper(), indexService.indexUUID());                }                indexShard.create(create);                version = create.version();                op = create;                created = true;            }            if (request.refresh()) {                try {                    indexShard.refresh("refresh_flag_index");                } catch (Throwable e) {                    // ignore                }            }            // update the version on the request, so it will be used for the replicas            request.version(version);            request.versionType(request.versionType().versionTypeForReplicationAndRecovery());            assert request.versionType().validateVersionForWrites(request.version());            IndexResponse response = new IndexResponse(shardRequest.shardId.getIndex(), request.type(), request.id(), version, created);            return new PrimaryResponse<>(shardRequest.request, response, op);        } catch (WriteFailureException e) {            if (e.getMappingTypeToUpdate() != null) {                DocumentMapper docMapper = indexService.mapperService().documentMapper(e.getMappingTypeToUpdate());                if (docMapper != null) {                    mappingUpdatedAction.updateMappingOnMaster(indexService.index().name(), docMapper, indexService.indexUUID());                }            }            throw e.getCause();        }    }

上面的代码就是index的执行过程,这一过程涉及到index的底层操作,这里就不展开,只是说明它在action中是如何实现的,后面会有详细说明。接下来看在副本上的操作。副本可能有多个,因此首先调用了performReplicas方法,在这个方法中首先开始监听集群的状态,然后便利所有的副本进行处理,如果是异步则加入一个listener,否则同步执行返回结果。最后调用performReplica,在该方法中调用外部类的抽象方法shardOperationOnReplica。 这一过程比较简单,这里就不再贴代码,有兴趣可以参考相关源码。

到此,相信大家对“elasticsearch源码index action实现方式是什么”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

elasticsearch源码index action实现方式是什么

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

elasticsearch源码index action实现方式是什么

本篇内容主要讲解“elasticsearch源码index action实现方式是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“elasticsearch源码index action实现方式
2023-06-30

开源纯C#表达式编译器的实现方法是什么

这篇文章主要讲解了“开源纯C#表达式编译器的实现方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“开源纯C#表达式编译器的实现方法是什么”吧!一、 引子 监控画面的主要功能之一就是
2023-06-19

分布式锁redis实现方式是什么

分布式锁的Redis实现方式有两种:基于SETNX命令和基于RedLock算法。1. 基于SETNX命令:使用Redis的SETNX命令来实现分布式锁。该命令用于设置一个键的值,但只有在该键不存在时才会设置成功。通过使用SETNX命令,可以
2023-09-12

Java泛型实现方式是什么

这篇文章主要讲解了“Java泛型实现方式是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java泛型实现方式是什么”吧!Java 泛型实现方式Java 采用**类型擦除(Type era
2023-06-16

Python实现单例模式的方式是什么

本篇内容介绍了“Python实现单例模式的方式是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!单例模式(Singleton Patter
2023-07-04

Java泛型的实现方式是什么

本篇内容主要讲解“Java泛型的实现方式是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java泛型的实现方式是什么”吧!Java 泛型实现方式Java 采用**类型擦除(Type eras
2023-06-16

BUILDER模式的实现方法是什么

本篇内容主要讲解“BUILDER模式的实现方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“BUILDER模式的实现方法是什么”吧!效果它将构造代码和表示代码分开Builder模式将构建对
2023-06-19

php优惠券的实现方式是什么

PHP优惠券实现方式PHP优惠券实现有四种方法:手动输入、静态代码生成器、数据库驱动和电子商务平台集成。选择最合适的取决于业务需求、技术能力、时间和成本。最佳实践:设置明确的规则和限制使用安全可靠的代码生成提供清晰的条款和条件跟踪和分析使用情况定期审查和更新系统
php优惠券的实现方式是什么
2024-04-25

java零拷贝的实现方式是什么

本篇内容主要讲解“java零拷贝的实现方式是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“java零拷贝的实现方式是什么”吧!1.什么是零拷贝零拷贝字面上的意思包括两个,“零”和“拷贝”:“
2023-06-29

java实现多线程的方式是什么

今天小编给大家分享一下java实现多线程的方式是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。实现多线程的方式:1、继承
2023-07-04

多维数组的实现方式是什么?

在 python 中,多维数组可通过嵌套列表实现,使用索引访问元素。该结构允许数据更复杂地存储和组织,适用于诸如计算矩阵乘法等实战案例。多维数组的实现概述多维数组是一种数据结构,它是由数组元素组成的数组。这允许你存储和组织数据的方式比一
多维数组的实现方式是什么?
2024-05-23

php优惠券的实现方式是什么

php优惠券的实现方式:1、创建一个前端文件,并判断优惠券是否存在或者停用;2、创建一个PHP示例文件;3、通过“public function doCoupon($params){...}”等方法处理优惠券领取情况即可。
2017-12-07

java虚拟线程的实现方式是什么

Java虚拟线程:高性能并发编程的变革Java19引入虚拟线程,提供轻量级并发编程模型。虚拟线程由虚拟机管理,消除了内核上下文切换,带来显著性能提升。它们基于绿线程、协程和执行上下文,并通过调度程序管理,在固定大小的线程池中执行。虚拟线程具有高性能、可扩展性、资源效率和可移植性,可用作ForkJoinPool和CompletableFutureAPI。需要注意的是,它们无法执行阻塞操作,需要并发保护,并且调试可能更复杂。
java虚拟线程的实现方式是什么
2024-04-12

android依赖注入的实现方式是什么

Android中依赖注入的实现方式有以下几种:1. 构造函数注入:通过在类的构造函数中传入依赖对象的实例来实现注入。这种方式最为简单直接,但是对于依赖对象多的情况下,构造函数会变得很长。2. Setter方法注入:通过提供一个公开的Sett
2023-10-09

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录