[1]elasticsearch2.X源码分析——CAT请求Request流转的过程

elasticsearch是什么不再赘述。本文希望通过对ES源代码进行一些简单的分析,目的在于打通整个结构,了解整个运行方式,以及如果我需要对源代码进行简单的调整和修改我需要从哪里入手,抛砖引玉。本文选择了elasticsearch2.3.5的版本来进行分析调试,适用于2.x的版本。

环境准备

这次分析调试过程会将elasticsearch的源码check到本地后通过IDEA来分析,具体步骤可以通过搜索引擎获得,我默认了你做好了我以下提及的准备。

  • IDEA 用来启动和调试es工程
  • JDK1.8 这个版本的es可以用1.7或1.8编译
  • elasticsearch2.3.5源代码
    完成环境准备后的效果如下图所示

分析思路

我们分析的目的并不是无意义的闲读,或者我认为没有明确的需求和产出的阅读只是在浪费我的时间。虽然我的时间也不值钱。
下面这张图是我在阅读之前的思考,虽然我并不是在阅读之际就直接将它画出来,但这个逻辑指导我做这一次的阅读。



这些逻辑是可以在还没有开始阅读工作之前就需要想到的,在长期对es做二次开发工作后,我们可以很简单的猜测出它会具有图中所提到的功能点,那么接下来的工作就是带着预先设定的猜测去寻找对应的实现。那么最容易做到也是最简单的事情就是,发出一次最简单的请求,然后去跟踪这个请求所流转的过程。es既然本身提供restful接口,从大层面来看,它也是一个web程序,这就方便了我们寻找切入口。

分析过程

首先在IDEA中把ES以DEBUG启动模式启动,本篇重点关注请求流转的过程,即使我知道有在启动准备中有很多工作。不过我还是希望先满足自己的好奇心,我希望知道我提交给es一个请求后它是怎么走过它的生命周期最终落地形成结果返回给我的。
ES的API可以大致分为以下几类

  • 文档API(Document APIs): 提供对文档的增删改查操作
  • 搜索API(Search APIs): 提供对文档进行某个字段的查询
  • 索引API(Indices APIs): 提供对索引进行操作
  • 查看API(cat APIs): 按照更直观的形式返回数据,更适用于控制台请求展示
  • 集群API(Cluster APIs): 对集群进行查看和操作的API
    我选择使用cat APIs来做本次DEBUG,因为我不需要其他额外的参数,而是可以简单的使用curl或者在浏览器输入url来发起我所需要的请求。
    我首先在浏览器输入了http://localhost:9200/_cat
    浏览器给我以下回显

=^.^=
/_cat/allocation
/_cat/shards
/_cat/shards/{index}
/_cat/master
/_cat/nodes
/_cat/indices
/_cat/indices/{index}
/_cat/segments
/_cat/segments/{index}
/_cat/count
/_cat/count/{index}
/_cat/recovery
/_cat/recovery/{index}
/_cat/health
/_cat/pending_tasks
/_cat/aliases
/_cat/aliases/{alias}
/_cat/thread_pool
/_cat/plugins
/_cat/fielddata
/_cat/fielddata/{fields}
/_cat/nodeattrs
/_cat/repositories
/_cat/snapshots/{repository}

以上你可以看到所有cat的API都罗列展示出来。那么我们的目的就是跟踪这一个请求,它在哪里被转发最后被执行,都是我们所关心的。
首先我们需要寻找到一个可以下断点的突破点。这一点比较需要经验,首先ES是一个优秀的开源程序,那么我有足够的理由相信,它会在命名规范上做的很出色,所以我的第一个想法肯定是通过观察工程目录结构来寻找我第一个BreakPoint的位置。


目录.png

其实仔细观察目录结构,通过rest包名可以猜到这里大概会放有和restful服务相关的逻辑,点开包目录很清楚的可以看到我们所熟悉的各类API的位置,其中也包括catAPI。再点开cat包目录,好的,我们已经找到相关的类了。

其实我觉得源代码阅读这种事情切入点都是靠猜出来的 ——鲁迅

可是还是很懵,到底是哪个呢?
仔细观察可以发现,cat包下的类,和cat命令的功能是一一对应的。
比如/_cat/indices其实很明显的可以看得出来是RestIndicesAction,点进去我们也可以看到在构造函数中注册的路径

    @Inject
    public RestIndicesAction(Settings settings, RestController controller, Client client, IndexNameExpressionResolver indexNameExpressionResolver) {
        super(settings, controller, client);
        this.indexNameExpressionResolver = indexNameExpressionResolver;
        controller.registerHandler(GET, "/_cat/indices", this);
        controller.registerHandler(GET, "/_cat/indices/{index}", this);
    }

同理你完全可以试试多点几个类,就可以惊喜的看到这个路径就这么直白的写死在代码中。同理,我很容易猜到,我刚才访问的API对应执行的逻辑应该是会放在RestCatAction中。如以下

public class RestCatAction extends BaseRestHandler {

    private static final String CAT = "=^.^=";
    private static final String CAT_NL = CAT + "\n";
    private final String HELP;

    @Inject
    public RestCatAction(Settings settings, RestController controller, Set<AbstractCatAction> catActions, Client client) {
        super(settings, controller, client);
        controller.registerHandler(GET, "/_cat", this);
        StringBuilder sb = new StringBuilder();
        sb.append(CAT_NL);
        for (AbstractCatAction catAction : catActions) {
            catAction.documentation(sb);
        }
        HELP = sb.toString();
    }

    @Override
    public void handleRequest(final RestRequest request, final RestChannel channel, final Client client) {
        channel.sendResponse(new BytesRestResponse(RestStatus.OK, HELP));
    }
}

你甚至还能看到作者卖萌的表情。

有一个小tips是@Inject注解,这是谷歌的一个轻量级IOC框架提供的注解,我不了解,平时也是使用spring,但是这里其实无需深究它,可以大概的理解成在执行这个构造函数的时候会将所需要的变量注入到参数当中。

那我们把断点下在了这个构造函数当中,然后我刷新了浏览器页面,也就是重新发送了一遍请求。

很遗憾断点没有截获这一次请求。

再思考了一下,既然是构造函数,那么是不是在程序启动的过程中就已经执行过了?很好,那么我REDEBUG了ES。这次没有辜负我的期望,断点准确的截住了代码。


也就是说这个功能API列表其实在程序启动的时候就已经加载完毕,存储在了HELP变量中。这其实可以理解,当程序启动的时候就已经可以知道所有API的路径,也可以看到构造函数中的循环是在循环请求所有API路径并拼接到HELP变量中。

但是还是没解决我们的问题,到底是在哪里执行请求的呢。

眼光瞄向了handleRequest方法。可以看到handleRequest上有@Override注解。说明这个方法是实现或者复写了父类或者接口的方法。到这里我已经脑补出了结构,这是一个类似处理器一样的逻辑,需要实现的功能类实现了接口中规定好的方法,然后将功能类注册到一个处理器管理的区域由中心决定什么时候来调用处理器处理请求。

我们可以看一下这个类的UML图。


uml.png

非常明显的逻辑,RestHandler规定了处理器必须要实现的方法,AbstractComponent抽取了关于日志处理的逻辑。在这一点上是值得我学习的,将所有日志处理抽出来而不是散落在程序当中。

这次我们断点下在handleRequest中然后再次发送请求。bingo


我终于捕获了我自己发出的请求。
那么将刚才所做的事情都套用到同包的其他类中就可以找到所有API的具体逻辑,这就在如果有修改API需求的时候可以发挥用处了。在这个最简单的API中实现逻辑就是简单的返回预先加载好的字符串,但无论在哪个API类中都会在handleRequest中实现它的逻辑。

小结

本次分析我抱着如果我需要修改执行逻辑的时候我应该去哪里改的目的来寻找,解决了一部分问题也发现了很多新问题,主要的难点有以下一些问题:

  • ES几乎没有借助多少外部依赖,它仅用netty就实现了一个内部的web框架来管理请求的转发,给一开始的寻找切入口带来了困难。
  • 我在寻找我自己的请求到底去哪的时候其实没有文章中描述的这么轻松。。
  • ES本身内部的注释也不多,有时候很难理解作者的意思

基本的需求满足后我现在希望关注在ES做为一个优秀的开源软件,它的结构是如何设计的,如何解耦以及如何让代码优雅。下一篇我希望继续来分析ES源码中的一些“概念”。

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

推荐阅读更多精彩内容