Elasticsearch-CCR源码剖析(0)

Elasticsearch-CCR简介

Elasticsearch CCR是 Elastic 提供的跨集群数据同步的能力。官方在 6.7 版本以上提供了此功能。

此功能以 x-pack 插件的形式提供,遵循Elasticsearch自定义的开源协议,为商业付费功能。关于官方的介绍,可以参考 追随领导者:Elasticsearch 中的跨集群复制简介 来查看。

ES-CCR模型简介

Elasticsearch CCR中,设置了 Leader 和 Follower 的角色。Follower 角色通过 Pull 的方式从 Leader 获取更新的变更,主要有如下两个过程:

  • 历史数据全量同步:Follower通过远程构造snapshot方式,从Leader同步全量数据
  • 增量数据:Follower不断检查Leader是否有更新,并以Translog Snapshot的形式同步过来,实现同步更新

ES-CCR周边功能

CCR模块中,主要是完成了 Follower-Leader 的 Pull 模型。除此之外,还提供了其他周边的功能:自动发现前缀匹配、自动更新mapping、查看同步状态等功能。这些功能作为生态的一部分,增强了CCR的易用性、实用性。

Elasticsearch-CCR源码解析

本文基于Elasticsearch 7.10分支,在 6.7 到 7.10 的迭代中,CCR核心代码有部分实现进行了变更,但是核心思路是统一的,读者可根据手头的代码版本,酌情进行适当的思考。

如上文所说,Elasticsearch CCR 除实现了最简单的 Pull 模型外,还实现了提升易用性的监控、自动发现等功能。本文将主要聚焦于 Pull 模型的实现,而暂时忽略周边功能的设计。

最初的起点

从配置获取信息

Elasticsearch CCR 属于 x-pack 的扩展功能,在工程结构上,位于x-pack/plugin/ccr module 下。
在打包后,该 module 的产物是一个 名为 x-pack-ccr-7.10.0 的jar 和zip,其中包含了 es 针对于插件的规范定义文件 plugin-descriptor.properties。CCR模块的插件定义文件具体如下:

# Elasticsearch plugin descriptor file
# This file must exist as 'plugin-descriptor.properties' inside a plugin.
#
### example plugin for "foo"
#
# foo.zip <-- zip file for the plugin, with this structure:
# |____   <arbitrary name1>.jar <-- classes, resources, dependencies
# |____   <arbitrary nameN>.jar <-- any number of jars
# |____   plugin-descriptor.properties <-- example contents below:ssname=foo.bar.BazPlugin
description=Elasticsearch Expanded Pack Plugin - CCR
version=7.10.0-SNAPSHOT
name=x-pack-ccr
classname=org.elasticsearch.xpack.ccr.Ccr
java.version=1.8
elasticsearch.version=7.10.0
### optional elements for plugins:
#
#  'extended.plugins': other plugins this plugin extends through SPI
extended.plugins=x-pack-core
#
# 'has.native.controller': whether or not the plugin has a native controller
has.native.controller=false

以上便是CCR的插件定义,由上面可以看出,该 module 最终以 x-pack-ccr 为名的插件提供服务,入口类是 org.elasticsearch.xpack.ccr.Ccr

探究主类加载过程

本小节中,主要介绍 Ccr 启动时主类都做了什么,并针对于CCR核心链路的加载发现机制进行说明。

Ccr类作为 x-pack-ccr 模块的主入口,遵从 ES 插件开发规范,继承了 Plugin,同时实现了多个扩展Plugin的接口,用来被这些特定场景通过接口加载。

Ccr类中,实现了包括组件注册(CCR监控组件、Licence检测组件等)、Handler注册(注册CCR相关的请求和handler之间的关系)以及Task注册(注册任务用来CCR增量同步)等。

为了聚焦于核心模型的实现,我们首先把关注点放在 Ccr 的 Ccr#getActionsCcr#getPersistentTasksExecutor 方法。其实现具体如下:

@Override
    public List<PersistentTasksExecutor<?>> getPersistentTasksExecutor(ClusterService clusterService,
                                                                       ThreadPool threadPool,
                                                                       Client client,
                                                                       SettingsModule settingsModule,
                                                                       IndexNameExpressionResolver expressionResolver) {
        return Collections.singletonList(new ShardFollowTasksExecutor(client, threadPool, clusterService, settingsModule));
    }

    public List<ActionHandler<? extends ActionRequest, ? extends ActionResponse>> getActions() {
        if (enabled == false) {
            return emptyList();
        }

        return Arrays.asList(
                // internal actions
                new ActionHandler<>(BulkShardOperationsAction.INSTANCE, TransportBulkShardOperationsAction.class),
                new ActionHandler<>(ShardChangesAction.INSTANCE, ShardChangesAction.TransportAction.class),
                new ActionHandler<>(PutInternalCcrRepositoryAction.INSTANCE,
                    PutInternalCcrRepositoryAction.TransportPutInternalRepositoryAction.class),
                new ActionHandler<>(DeleteInternalCcrRepositoryAction.INSTANCE,
                    DeleteInternalCcrRepositoryAction.TransportDeleteInternalRepositoryAction.class),
                new ActionHandler<>(PutCcrRestoreSessionAction.INSTANCE,
                    PutCcrRestoreSessionAction.TransportPutCcrRestoreSessionAction.class),
                new ActionHandler<>(ClearCcrRestoreSessionAction.INSTANCE,
                    ClearCcrRestoreSessionAction.TransportDeleteCcrRestoreSessionAction.class),
                new ActionHandler<>(GetCcrRestoreFileChunkAction.INSTANCE,
                    GetCcrRestoreFileChunkAction.TransportGetCcrRestoreFileChunkAction.class),
                // stats action
                new ActionHandler<>(FollowStatsAction.INSTANCE, TransportFollowStatsAction.class),
                new ActionHandler<>(CcrStatsAction.INSTANCE, TransportCcrStatsAction.class),
                new ActionHandler<>(FollowInfoAction.INSTANCE, TransportFollowInfoAction.class),
                // follow actions
                new ActionHandler<>(PutFollowAction.INSTANCE, TransportPutFollowAction.class),
                new ActionHandler<>(ResumeFollowAction.INSTANCE, TransportResumeFollowAction.class),
                new ActionHandler<>(PauseFollowAction.INSTANCE, TransportPauseFollowAction.class),
                new ActionHandler<>(UnfollowAction.INSTANCE, TransportUnfollowAction.class),
                // auto-follow actions
                new ActionHandler<>(DeleteAutoFollowPatternAction.INSTANCE, TransportDeleteAutoFollowPatternAction.class),
                new ActionHandler<>(PutAutoFollowPatternAction.INSTANCE, TransportPutAutoFollowPatternAction.class),
                new ActionHandler<>(GetAutoFollowPatternAction.INSTANCE, TransportGetAutoFollowPatternAction.class),
                new ActionHandler<>(ActivateAutoFollowPatternAction.INSTANCE, TransportActivateAutoFollowPatternAction.class),
                // forget follower action
                new ActionHandler<>(ForgetFollowerAction.INSTANCE, TransportForgetFollowerAction.class));
    }

上文代码是Ccr类中关于主流程的最核心部分。

其中,getAction 方法的作用是声明了Ccr相关请求和Handler的映射关系,以用来实现相关Action的处理。在Ccr的设计中,所有的 变化 都会被抽象成一种 Action,并后面被Handler进行捕获和处理。如注释中所描述,Ccr相关的Action主要分为以下五类:

  • Internal Action:内部行为,主要包括分片变化进行处理的行为、有需要写数据的行为等,这一部分承载了Ccr内部实现的核心逻辑,属于核心实现;
  • Stats Action:状态行为,该部分主要是提供获取follow ccr的状态的行为;
  • Follow Action:跟随者行为,该部分为follow相关的入口,提供控制follow开启同步、结束同步等操作的行为;
  • Auto-Follow Action:自动跟随行为,该部分同跟随者行为部分,主要提供自动follow等操作的行为;
  • Forget Follower Action:忘记跟随者行为

ShardFollowTasksExecutor方法则是完成了 ShardFollowTasksExecutor 的注册,用来执行 ShardFollowTask。

此外,我们关注 Ccr 的 getInternalRepositoriesgetEngineFactory 方法,其定义如下:

    public Optional<EngineFactory> getEngineFactory(final IndexSettings indexSettings) {
        if (CCR_FOLLOWING_INDEX_SETTING.get(indexSettings.getSettings())) {
            return Optional.of(new FollowingEngineFactory());
        } else {
            return Optional.empty();
        }
    }

    @Override
    public Map<String, Repository.Factory> getInternalRepositories(Environment env, NamedXContentRegistry namedXContentRegistry,
                                                                   ClusterService clusterService, RecoverySettings recoverySettings) {
        Repository.Factory repositoryFactory =
            (metadata) -> new CcrRepository(metadata, client, ccrLicenseChecker, settings, ccrSettings.get(),
                clusterService.getClusterApplierService().threadPool());
        return Collections.singletonMap(CcrRepository.TYPE, repositoryFactory);
    }

getEngineFactory方法的作用是:在indexSettings中存在ccr配置的时候,该方法会被Node类加载,从而在有ccr配置的索引创建被提交的时候,将该索引的Engine设置为 FollowEngine,FollowEngine中的实现有别于默认的InternalEngine,以更好的实现 CCR 的需要,此部分在此不进行深入解析。

同理,getInternalRepositories 方法用于提供CcrRepository用来替代默认Repository实现,该实现中主要提供了从远程集群拉取snapshot的实现。

除以上几个核心方法外,Ccr类中还实现了一些rest handler注册、参数转换等其他方法,这部分在此不详细展开。

提交一个 Follow 请求

在官网的示例中,我们可以通过如下方式来提交一个follow请求:

curl -XPUT "localhost:9200/server-metrics-copy/_ccr/follow?wait_for_active_shards=1&pretty" -H 'Content-Type: application/json' -d'
{
  "remote_cluster" : "leader",
  "leader_index" : "server-metrics"
}
'

首先,要明白这个请求是如何接受的,就需要找到代码里处理该请求的RestHandler。从代码中可以定位到是 RestPutFollowAction 处理了这一个请求,而 RestPutFollowAction 中,是通过提交 PutFollowAction 来实现的,PutFollowAction 在上文中,已经给出了是通过 TransportPutFollowAction 来监听并处理的。所以我们也很清晰的找到,TransportPutFollowAction是 CCR 处理的入口。

小结

Elasticsearch CCR 源码的阅读,需要一些 Elasticsearch 开源设计的基础,本篇作为系列的第一篇,主要是介绍了CCR模块是如何加载并且工作起来的,同时也涉及到了一些框架加载上设计的了解,最后成功的了解到了一个follow请求是如何被接受并执行的。
本文碍于篇幅,仅完成了Ccr主类加载相关的代码解析,并没有进行全量同步/增量同步的分析,有关于 Pull 模型的具体分析,和一个 PutFollowAction 的具体响应流程,将会在后续的文章中一一揭秘。
希望阅读完本文,能让大家对ES插件机制、和插件开发的方式以及整体工作模式,有一个最基本的认识。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,373评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,732评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,163评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,700评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,036评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,425评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,737评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,421评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,141评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,398评论 2 243
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,908评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,276评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,907评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,018评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,772评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,448评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,325评论 2 261

推荐阅读更多精彩内容