专栏首页腾讯云Elasticsearch Service从Elasticsearch的插件实现机制见:如何在Java中实现一个插件化系统
原创

从Elasticsearch的插件实现机制见:如何在Java中实现一个插件化系统

1. ES 中的 插件是什么?

  • 可拔插式的,允许动态的为ES扩展一些自定义的功能
  • 有多种插件形式,包括:预处理插件(Ingest plugin)、集群发现插件(discovery plugin)、分词插件(analysis plugin)等

2. 为什么使用插件,有什么好处?

  • 可扩展性:允许动态对应用进行扩展以引入新的特性,比如在ES中:增加一个自定义的预处理插件,或是增加一个针对特定云环境下集群发现插件等
  • 并行开发:因为特性能被实现成分离的组件,所以它们可以被并行地开发。比如,在一个组件需要适应不同环境、不同处理逻辑的情况下,提供插件让用户自己开发也是一个不错的选择。拿ES预处理插件(Ingest plugin)为例,其Ingest-csv插件就是由社区开发并被广泛使用的
  • 明确的开发方向:由于插件框架为插件编写者提供了定义良好的接口和文档,因此开发人员具有明确的开发方向,比如:要实现的哪些接口,接口的功能是什么。这比直接修改源码增加接口实现类的方式更加容易,因为不需要知道更多细节
  • 除此之外,个人认为ES插件还有额外的好处是:允许安装或卸载插件,使得程序在运行时只保留所需要的功能,避免的程序的臃肿和不必要的代码依赖

3. 与动态库有什么区别?

  • 动态库。C语言中提供了dlopen、dlsym等函数允许在程序运行时加载动态库并执行,使得其能动态的新增或变更程序的功能,因此也就可以被用来实现插件化的程序。更具体的例子是,go语言对这些函数进行封装后提供了plugin库
  • ES插件:通过 ClassLoader 库实现,能在运行时加载字节码文件并执行。虽然在Java中提供了System.loadLibrary函数,其也能通过JNI的方式封装C中dlopen, dlsym等函数支持在运行时访问动态库,但ES并没有选择这种方式。

4. ES是如何实现插件机制的?

4.1 如何实现一个插件

  • 插件继承关系
    • image-20200623112727325
    • Plugin:所有插件的抽象基类
    • IngestPlugin, AnalysisPlugin:特定类型插件的接口
    • IngestUserAgentPlugin、AnalysisICUPlugin: 特定插件的实现类
  • 对于特定类型的插件,需要实现特定的接口。比如:Ingest插件需要实现IngestPlugin接口的getProcessors方法,Analysis插件需要实现AnalysisPlugin接口的getCharFilters、getTokenFilters等方法
    • image-20200623113851342
  • (可选)重写Plugins抽象类中的方法,但这步并不是必须的。重写的情况比如: 某个插件需要修改集群的设置、使用client请求集群等,那么你就需要实现createComponents接口并将一些ES的内部对象的引用设置到插件对象中作为成员。具体的例子可以参考实现了createComponents方法的插件,比如:CommonAnalysisPlugin、PainlessPlugin、Ccr等
  • 在插件的构建文件(build.gradle)中定义插件信息:
    • image-20200623124647051
    • 其中,classname指明了ES要去加载的插件类,插件构建后将生成plugin-descriptor.properties 文件并包含这些信息。
  • 更详细开发流程可以参考:《Writing Your Own Ingest Processor for Elasticsearch》

4.2 当实现完一个插件后,ES是如何使用的?

  • 构建插件后生成压缩包,通过elasticsearch-plugin命令安装,其实际动作只是将插件包解压到plugins目录
  bin/elasticsearch-plugin install file:///ingest-fingerprint/build/distributions/ingest-fingerprint-7.6.2.0.zip
  • 目录结构如下,包含:插件jar包和描述文件plugins └── ingest-fingerprint ├── ingest-fingerprint-7.6.2.0.jar ├── plugin-descriptor.properties └── plugin-security.policy
  • 启动节点时会加载plugins目录下的所有插件(见PluginsService 构造函数)
    • readFromProperties:读取plugin-descriptor.properties中插件信息,生成PluginInfo对象
    • loadBundle:使用ClassLoader加载class文件中的插件类
    • loadPlugin:利用反射机制获取构造函数,并实例化插件Plugin对象保存在数组中
  • 现在进程已经有了所有插件抽象类Plugin对象构成的列表,那么ES是如何使用指定的插件呢?以IngestPlugin为例:
  • 在节点构造函数初始化时,会过滤出IngestPlugin插件对象,用其初始化IngestService
    image-20200623164833926
  • IngestService构造函数中,调用接口的getProcessors方法获取了一个map对象,key为processor的类型名,value为创建该processor的工厂对象
image-20200623170115996
  • 而当你在ingest pipeline中指定了某一类型名时(比如下述使用的processor type是user_agent),ES就能从map中获取工厂类并创建指定的processor对象
image-20200623170745469

5. 总结

  • 本文首先介绍了什么是ES插件以及使用插件的好处,包括:可扩展性、并行开发、明确的开发方向、避免的程序的臃肿和不必要的代码依赖等。
  • 然后通过对比插件和动态库,可以看出,动态库可以作为一些主流语言实现插件系统的底层库,而且Go语言甚至提供了基于动态库封装的官方插件库;而在Java中,除了用JNI+动态库实现插件的方式外,还能通过ClassLoader实现插件,而ES正是通过这种方式实现的。
  • 最后,深入到源码分析了ES插件系统的基本结构。除了能对ES有更深入的了解外,这也能对”如何实现插件系统“在工程上有一定的借鉴意义。

此外,笔者还对Java的流行插件框架PF4J进行的简单的了解,发现其实现方式和ES比较相似:都是由ClassLoader实现,感兴趣的读者可以自行了解。

6. 参考:

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 在ES API中求值表达式?ES 脚本介绍

    如何在查询时转换字段的值?如何对文档执行复杂的更新操作?如何在ingest processor中指定执行条件?

    franyang
  • ES-Hadoop 实践

    在大数据背景下,适用于不同场景下的框架、系统层出不穷,在批量数据计算上hadoop鲜有敌手,而在实时搜索领域es则是独孤求败,那如何能让数据同时结合两者优势呢?...

    franyang
  • ES 脚本实现

    在我的上篇文章ES 脚本介绍中介绍了ES 脚本的基本概念和使用,而本文将对其内部实现做一个分析。

    franyang
  • IntelliJ IDEA 18 周岁,吐血推进珍藏已久的必装插件

    IntelliJ IDEA是目前最好最强最智能的Java IDE,前几天,他刚刚年满18岁。

    用户1655470
  • cordova学习四 插件集成

    4.1插件添加          插件集成命令在项目的根目录比如myapp则是在../myapp这个目录下 一般集成插件都是在github也可以是下载好的 ...

    cfs
  • scheduling-framework功能介绍

    scheduling framework 是Kubernetes Scheduler的一种新的可插入架构,可简化调度程序的自定义, 它向现有的调度程序中添加了一...

    有点技术
  • 萌妹子语音陪你写代码,一个神奇的 VSCode 插件

    最近在 GitHub 发现了一个有趣的 VSCode 插件:Rainbow Fart。在你写代码的时候,可根据关键字播放接近代码含义的语音。

    Enjoy233
  • 推荐个软件:uTools

    更多的内容可以去看一下差评的推文或者官方文档,我这篇文章主要放一下刚用起来就觉得挺不错的一些功能

    yichen
  • 【Chromium中文文档】插件架构

    背景 在阅读这个文档前,你应当熟悉Chromium的多进程架构。 概述 插件是浏览器不稳定的主要来源。插件也会在渲染器没有实际运行时,让进程沙箱化。因为进程是第...

    梦里茶
  • IOS 越狱插件介绍与一点经验

    总体来说,如果你的系统是13.5的话(尚未升级到13.5.1),实际上整个流程比Android的Root还要简单。因为Iphone是我的主力机,为了避免不必要的...

    xuing

扫码关注云+社区

领取腾讯云代金券