1 前言
承接上篇 ElasticSearch源码走读——环境搭建,我们使用方案1,在IDEA中搭建了ES 7.10的代码阅读环境。
打开项目工程,一级目录如下:
初看这个,是让人眼花缭乱的,每个蓝框都被gradle识别解析为子模块,你如果再展开一级目录,下面的子模块还有很多很多。但实际上里面的绝大多数模块都是我们可能一辈子都不会碰到的。
其实,任何一个成熟的开源项目都有这个特点,因为它大而全、面面俱到。而我们的时间、精力、能力,都有限,以有限的时间,追逐这几乎没有边界的“浩瀚海洋”,是读开源项目的一大难点!因此,我们必须要 抓重点,抓重点,抓重点 !不要走偏,否则会很容易遭受挫败感,然后半途而废。
- 首先,所有带
gradle
、build
、dev
、distribution
、license
字眼的所有东西,排除。毕竟我们不是来学gradle项目构建的。 - 然后,
docs
目录对应的是官网文档。比如,docs/reference/cat/indices.asciidoc
文件的内容,其实对应的就是官网文档里cat-indices.html的页面。这是Elasic公司的人开发新功能时才去编辑的,我们有官网文档好好的UI界面不看,看这个干嘛,对吧;类似地,rest-api-spec
目录下是ElasticSearch的Rest API结构,例如rest-api-spec/src/main/resources/rest-api-spec/api/cat.indices.json
就展示了GET _cat/indices
接口的详细参数和用法。这个算是有点用吧,可以和官网文档API部分结合着看,但还是以官网文档为主。 - 接着,和测试有关的东西,包括
qa
(场景测试)、benchmarks
(性能测试)、test
等等以后遇到了实际需要时再看,这里先忽略。 x-pack
是商业化功能,可以理解为一些增强功能。建议不要一上来就看,因为这些功能大都是锦上添花的feature,而不是ES核心功能。client
是Java开发者使用ES时用的rest-client
和rest-high-level-client
,如果想看,完全可以在业务项目中看jar包,对吧,
- 排除了上述,就剩下
server
、libs
、modules
、plugins
了。
2 server
server就是我们读ES源码时,最主要的目录了。它就对应着我们上一篇 ElasticSearch源码走读——环境搭建 里引入的elasticsearch
jar包内容。
我们看看结构:
server/src/test
、server/src/internalClusterTest
都是单测,后面我们debug时,可能会用到。他们至少比上一节qa
、test
、benchmark
那几个有用多了。主包里,org.apache.lucene
其实是和Lucene
库同名的包。我读源码时基本没涉及到这块,感觉也不是很核心的地方。我们知道ES构建索引底层使用的是Lucene
,这里的包是对原生Lucene
的一些扩展和增强。而真正原生Lucene
的东西,才是我们后面会看的。至于java11
、joda.time.format
,也都是没什么用的。- 说白了,我们又做了次排除法,可以发现真正有用的就剩
org.elasticsearch
(后面我就简称o.e
了)一个包了!展开子一级目录如下:
|-- action # 客户端对ES的操作,在rest层之后,下一层就转换成了action。假如你使用过ES,对这里的子包名肯定会不陌生:bulk、delete、get、index、search...
|-- bootstrap # 支持进程启动,不算重要。
|-- cli # 一些命令行工具,也包括进程启动。不算重要。
|-- client # 不是用户访问client,而是集群内部节点间的actions/operations的调用者。比较重要。
|-- cluster # 管理集群状态、元数据、路由等等,重要。
|-- common # 一些工具类。内容很多,很多也写的很抽象,不建议一上来就看,后面具体用到某方面时再细看。
|-- discovery # 集群内节点发现,包括一些选主相关的操作。
|-- env # 环境信息。在进程启动时会看到这部分代码。不算重要。
|-- gateway # 这名字起的也挺抽象。和集群元数据发布有关,比较重要。
|-- http # 对http操作的一些封装,个人感觉不会有很多机会和它打交道。
|-- index # 和数据写入流程强相关,非常重要。
|-- indices # 同上,但更偏一些宏观层面的操作,也非常重要。
|-- ingest # 对应ES里的ingest操作,是写入过程中可能会经历的一个环节。我目前没怎么打交道。
|-- monitor # 这是对ES进程、重要信息的监控功能模块。
|-- node # 封装了节点的角色、状态,内容不多。
|-- persistent # ES里执行的任务都是task,其中有少量种类的task要求是进程重启还能恢复继续执行的,因此需要持久化。这个包就是围绕这个功能的,不算核心。
|-- plugins # ES支持自定义开发插件。如何提供支持插件的功能呢?在这里。主要仅仅是提供一些接口。没有很多实质性的内容。
|-- repositories # ES支持数据快照等,可以扩展各种远程存储的类型。远程存储的“仓库”,抽象为repository,这里提供了接口。
|-- rest # 客户端的RESTful请求发送来后,首先就是这里在接收处理。这里包括了各种api的定义。阅读某个功能的源码时,可以从这里找到入口,层层往下找。因此比较重要,需要了解下。
|-- script # ES支持在查询里写自定义脚本,这里提供支持。
|-- search # 查询核心模块,不用说,非常重要。
|-- snapshots # 快照功能。
|-- tasks # ES的各种执行任务,不管是同步或异步,都封装为task对象。
|-- threadpools # ES里各种任务,都是又线程池执行的。这个模块对jdk的线程池进行了一定的封装。
|-- transport # 节点间通信模块。其实是比较重要的一个基础模块,对tcp封装,定义了ES内的通信协议规则。
|-- usage # 查看使用方式的功能,不重要
|-- watcher # 监听文件变化的工具模块,不重要
|-- # 在主包下还有些杂类,可能是作者也不知道该放什么包了,就干脆放根目录了。包括一些通用Exception。不过其中有个Version类,会在很多地方被用到,用于做版本兼容性识别。
以上就是server的总览了,ES的主功能,就包含在这其中了。我们的源码走读系列,后面95%都会在这里面的重点模块间穿梭。
3 libs
- 说是libs,实际上也不是现成的第三方jar包,里面还是若干个gradle子项目。包括
core
、x-content
、cli
、geo
、grok
、nio
、ssl
等。这里面的代码,后续也就core
和x-content
可能会涉及到。都是从较底层支持上一节server的偏工具类的东西。理论上,把他们放在server里作为一个util也是可以的。最后,在ES执行环境里,他们和server是放在同一个lib路径(作为classpath)的。 - 这里面,唯一值得提一嘴的是
x-content
。我们通过rest api返回的结果,除了table形式(_cat/xxxx
接口)外,其它的半结构化类型,在ES里被称作“x-content
”,它包含了4种类型可选择:json
、yaml
、smile
、cbor
,默认是json
。
4 modules & plugins
- 实际上,这2个目录下的东西,都是一个个的plugin,就是ES的插件。ES官方就写了这些插件,我们也可以仿照他们,实现一些特定的接口,来自己开发插件。
- 虽然单独又拎出来了modules目录,但其下面的东西,实质上也是插件,看代码,也是继承Plugin抽象类,实现相关接口而已。只是,我理解这些“插件”相对更重要,是server能运行起来所不可缺少的东西。比如,其中的
transport-netty4
就是上文o.e.transport包底层所调用的模块。此外,还有reindex、analysis、ingest等。
5 总结
- 本文带着过了一遍,开源ElasticSearch项目的总体目录框架。看完之后,结合平时使用ES的各种功能,应该可以有个大致朦胧的感觉了。
- 另外,想看一个功能对应的代码,大致在哪里,我们有个比较通用的找法:先在
o.e.rest
里,找到这个功能的api uri规则,然后顺着可以找到o.e.action
包,action模块下面可以找到内部通信的uri,再找对应的service,大致就能找到对应的功能模块了。 - 任何比较成熟的开源项目,都是“大而全”的,想阅读主体功能代码,就一定要有取舍,否则以有涯追无涯,殆矣。