[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方法??梢钥吹絟andleRequest上有@Override注解。說明這個方法是實現或者復寫了父類或者接口的方法。到這里我已經腦補出了結構,這是一個類似處理器一樣的邏輯,需要實現的功能類實現了接口中規定好的方法,然后將功能類注冊到一個處理器管理的區域由中心決定什么時候來調用處理器處理請求。

我們可以看一下這個類的UML圖。


uml.png

非常明顯的邏輯,RestHandler規定了處理器必須要實現的方法,AbstractComponent抽取了關于日志處理的邏輯。在這一點上是值得我學習的,將所有日志處理抽出來而不是散落在程序當中。

這次我們斷點下在handleRequest中然后再次發送請求。bingo


我終于捕獲了我自己發出的請求。
那么將剛才所做的事情都套用到同包的其他類中就可以找到所有API的具體邏輯,這就在如果有修改API需求的時候可以發揮用處了。在這個最簡單的API中實現邏輯就是簡單的返回預先加載好的字符串,但無論在哪個API類中都會在handleRequest中實現它的邏輯。

小結

本次分析我抱著如果我需要修改執行邏輯的時候我應該去哪里改的目的來尋找,解決了一部分問題也發現了很多新問題,主要的難點有以下一些問題:

  • ES幾乎沒有借助多少外部依賴,它僅用netty就實現了一個內部的web框架來管理請求的轉發,給一開始的尋找切入口帶來了困難。
  • 我在尋找我自己的請求到底去哪的時候其實沒有文章中描述的這么輕松。。
  • ES本身內部的注釋也不多,有時候很難理解作者的意思

基本的需求滿足后我現在希望關注在ES做為一個優秀的開源軟件,它的結構是如何設計的,如何解耦以及如何讓代碼優雅。下一篇我希望繼續來分析ES源碼中的一些“概念”。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,885評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,312評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,993評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,667評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,410評論 6 411
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,778評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,775評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,955評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,521評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,266評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,468評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,998評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,696評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,095評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,385評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,193評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,431評論 2 378

推薦閱讀更多精彩內容