前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从Elasticsearch的插件实现机制见:如何在Java中实现一个插件化系统

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

原创
作者头像
franyang
修改2020-06-23 19:06:52
4.5K0
修改2020-06-23 19:06:52
举报
文章被收录于专栏:腾讯云Elasticsearch Service

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

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

  • 构建插件后生成压缩包,通过elasticsearch-plugin命令安装,其实际动作只是将插件包解压到plugins目录
代码语言:txt
复制
  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
    image-20200623164833926
  • IngestService构造函数中,调用接口的getProcessors方法获取了一个map对象,key为processor的类型名,value为创建该processor的工厂对象
image-20200623170115996
image-20200623170115996
  • 而当你在ingest pipeline中指定了某一类型名时(比如下述使用的processor type是user_agent),ES就能从map中获取工厂类并创建指定的processor对象
image-20200623170745469
image-20200623170745469

5. 总结

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

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

6. 参考:

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. ES 中的 插件是什么?
  • 2. 为什么使用插件,有什么好处?
  • 3. 与动态库有什么区别?
  • 4. ES是如何实现插件机制的?
    • 4.1 如何实现一个插件
      • 4.2 当实现完一个插件后,ES是如何使用的?
      • 5. 总结
      • 6. 参考:
      相关产品与服务
      Elasticsearch Service
      腾讯云 Elasticsearch Service(ES)是云端全托管海量数据检索分析服务,拥有高性能自研内核,集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群,也支持免运维、自动弹性、按需使用的 Serverless 模式。使用 ES 您可以高效构建信息检索、日志分析、运维监控等服务,它独特的向量检索还可助您构建基于语义、图像的AI深度应用。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档