ES源码分析-关于action

2021-01-18 12:24:02 浏览数 (1)

  • ES源码版本 7.10

启动过程中的action

比如我们有个搜索请求:

代码语言:javascript复制
curl -X GET "localhost:9200/blogs/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "content": "elasticsearch"
        }
      },
      "field_value_factor": {
        "field": "likes",
        "factor": 2,
        "modifier": "sqrt",
        "missing": 1
      }
    }
  }
}
'

这个请求ES是如何找到对应的模块去处理呢?答案是ES在启动过程中注册了请求的URL和对应的Action的绑定关系。

RestSearchAction.java

比如上面,RestSearchAction就是对应/{index}/_search这个URL模板的处理Action,ES里有很多继承自BaseRestHandler的Action绑定到不同的Action上。本篇就以/{index}/_search为例来说明。

具体是怎么关联的呢?我们继续分析。

ES在启动的时候要初始化Node类。

Bootstrap.java

在构造函数里会调用ActionModule类,这个类就是ES的Action管理的核心处理类,后面讲搜索过程中的Action部分它也会出现。Node构造函数里会调用ActionModule类的initRestHandlers方法来注册。

ActionModule.java

initRestHandlers这个方法里会调用RestController的registerHandler方法完成注册。

RestController.java

handlers.insertOrUpdate方法内部就不深入了,这里其实是用了字典树的数据结构(Trie),存储path(/{index}/_search)和Handler的对应关系。Trie的核心思想是空间换时间,利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。

所以在请求阶段查找的时候,也同样是根据url path去查找对应的handler。这部分在下个章节会提到。

还有一个TransportAction需要说明下。在ActionModule类的setupActions方法,会将Action和对应的TransportAction注册到actions对象中。这个Action指的是SearchAction(search场景下),如下图所示:

ActionModule.java

其实底层就是放在一个Map里建立一个映射关系。请求的时候去这个Map里找。

请求过程中的action

了解了Action相关的启动加载流程,下面我们来看一个查询的调用链路,顺藤摸瓜,看看一个查询请求是怎么应用到Action的。

首先所有的请求入口都是netty,准确来说对外的请求都是基于netty4封装的HTTP server。然后server分发请求。这部分其实更多的是netty和http相关的通用逻辑,这里不做详细介绍了。HTTP server的分发逻辑最终会调用到RestController类的dispatchRequest方法

RestController.java

tryAllHandlers方法前面这个循环是用来把http请求的头部信息传递到ES底层调用,从而做一些特殊处理。header里的key是ES定义的,value我们可以自己指定。比如X-Opaque-Id这个key,如果我们应用端请求的时候赋值了,可以用来跟踪从http请求到底层个人任务的执行链路。

RestController.java

接着看,比如还是上面那个搜索请求:

代码语言:javascript复制
curl -X GET "localhost:9200/blogs/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "content": "elasticsearch"
        }
      },
      "field_value_factor": {
        "field": "likes",
        "factor": 2,
        "modifier": "sqrt",
        "missing": 1
      }
    }
  }
}
'

RestController.java

这段代码可以根据我的请求的path,这里是

代码语言:javascript复制
/blogs/_search

找到对应

代码语言:javascript复制
/{index}/_search

RestHandler,这个查找就是根据url path去Trie树查找。然后通过dispatchRequest方法分发给找到的Handler处理。这个方法会统一调用到BaseRestHandler这个基类进行处理

BaseRestHandler.java

根据前面的path(/{index}/_search),我们知道上图中找到的这个action必然是RestSearchAction,然后根据这个类重载的prepareRequest方法可以找到accept的执行逻辑。

RestSearchAction.java

这里最终会调用NodeClient类找到action(注意这里的action和上面的action不是一个东西,这里的action是searchAction)对应的TransPortAction,前面在启动章节说过,在ActionModule中会将Action和对应的TransportAction注册到actions对象中。现在就是从actions对象(是个Map)中拿到对应的TransportAction,并并执行其execute()方法。

在NodeClient中会根据传入的Action参数从actions获取在ActionModule中注册的TransportAction,并执行其execute()方法

TransportAction后面的的逻辑,就是具体的ES查询逻辑处理了。这个后面会有专门的系列文章。这里不再详述。

上面的调用链路,可以用一个时序图表示

0 人点赞