溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Nebula Graph源碼分析

發(fā)布時(shí)間:2021-11-12 11:49:09 來源:億速云 閱讀:192 作者:iii 欄目:數(shù)據(jù)庫

本篇內(nèi)容介紹了“Nebula Graph源碼分析”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

導(dǎo)讀

對(duì)于一些剛開始接觸 Nebula Graph 開源庫的小伙伴來說,剛開始可能和我一樣,想要提高自己,看看大神們的代碼然后試著能夠做點(diǎn)什么,或許能夠修復(fù)一個(gè)看起來并不是那么困難的 Bug。但是面對(duì)如此多的代碼,我裂開了,不知道如何下手。最后硬著頭皮,再看了一遍又一遍代碼,跑了一個(gè)又一個(gè)用例之后終于有點(diǎn)眉目了。

下面就分享下個(gè)人學(xué)習(xí) Nebula Graph 開源代碼的過程,也希望剛接觸 Nebula Graph 的小伙伴能夠少走彎路,快速入門。另外 Nebula Graph 本身也用到了一些開源庫,詳情可以見附錄。

在本文中,我們將通過數(shù)據(jù)流快速學(xué)習(xí) Nebula Graph,以用戶在客戶端輸入一條 nGQL 語句 SHOW SPACES 為例,使用 GDB 追蹤語句輸入時(shí) Nebula Graph 是怎么調(diào)用和運(yùn)行的。

整體架構(gòu)

Nebula Graph源碼分析

一個(gè)完整的 Nebula Graph 包含三個(gè)服務(wù),即 Query Service,Storage Service 和 Meta Service。每個(gè)服務(wù)都有其各自的可執(zhí)行二進(jìn)制文件。

Query Service 主要負(fù)責(zé)

  • 客戶端連接的管理

  • 解析來自客戶端的 nGQL 語句為抽象語法樹 AST,并將抽象樹 AST 解析成一系列執(zhí)行動(dòng)作。

  • 對(duì)執(zhí)行動(dòng)作進(jìn)行優(yōu)化

  • 執(zhí)行優(yōu)化后的執(zhí)行計(jì)劃

Storage Service 主要負(fù)責(zé)

  • 數(shù)據(jù)的分布式存儲(chǔ)

Meta Service 主要負(fù)責(zé)

  • 圖 schema 的增刪查改

  • 集群的管理

  • 用戶鑒權(quán)

這次,我們主要對(duì) Query Service 進(jìn)行分析

目錄結(jié)構(gòu)

剛開始,可以拿到一個(gè) source 包,解壓,可以先看看代碼的層級(jí)關(guān)系,不同的包主要功能是干什么的 下面只列出 src 目錄:

|--src
    |--client // 客戶端代碼
    |--common // 提供一些常用的基礎(chǔ)組件
    |--console
    |--daemons
    |--dataman
    |--graph // 包含了Query Service的大部分代碼                         
    |--interface // 主要是一些 meta、storage 和 graph 的通訊接口定義     
    |--jni
    |--kvstore
    |--meta // 元數(shù)據(jù)管理相關(guān) 
    |--parser // 主要負(fù)責(zé)詞法和語法分析       
    |--storage // 存儲(chǔ)層相關(guān)
    |--tools
    |--webservice

代碼跟蹤

通過 scripts 目錄下的腳本啟動(dòng) metad 和 storaged 這兩個(gè)服務(wù):

Nebula Graph源碼分析

啟動(dòng)后通過 nebula.service status all 查看當(dāng)前的服務(wù)狀態(tài)

Nebula Graph源碼分析

然后 gdb 運(yùn)行 bin 目錄下的 nebula-graphd 二進(jìn)制程序

gdb> set args --flagfile  /home/mingquan.ji/1.0/nebula-install/etc/nebula-graphd.conf   //設(shè)置函數(shù)入?yún)?
gdb> set follow-fork-mode child   // 由于是守護(hù)進(jìn)程,所以在 fork 子進(jìn)程后 gdb 繼續(xù)跟蹤子進(jìn)程
gdb> b main         // 在 mian 入口打斷點(diǎn)

在 gdb 中輸入 run 開始運(yùn)行 nebula-graphd 程序,然后通過 next 可以一步一步運(yùn)行,直到遇到 gServer->serve();  // Blocking wait until shut down via gServer->stop(),此時(shí) nebula-graphd 的所有線程阻塞,等待客戶端連接,這時(shí)需要找到客戶端發(fā)起請(qǐng)求后由哪個(gè)函數(shù)處理。

由于 Nebula Graph 使用 FBThrift 來定義生成不同服務(wù)的通訊代碼,在 src/interface/graph.thrift 文件中可以看到 GraphService 接口的定義如下:

service GraphService {
    AuthResponse authenticate(1: string username, 2: string password)
    oneway void signout(1: i64 sessionId)
    ExecutionResponse execute(1: i64 sessionId, 2: string stmt)
}

gServer->serve() 之前有

auto interface = std::make_shared<GraphService>();
status = interface->init(ioThreadPool);
gServer->setInterface(std::move(interface));
gServer->setAddress(localIP, FLAGS_port);

可以知道是由 GraphService 對(duì)象來處理客戶端的連接和請(qǐng)求,因此可以在 GraphService.cpp:``future_execute 處打斷點(diǎn),以便跟蹤后續(xù)處理流程。

此時(shí)重新打開一個(gè)終端進(jìn)入 nebula 安裝目錄,通過 ./nebule -u=root -p=nebula 來連接 nebula 服務(wù),再在客戶端輸入 SHOW SPACES ,此時(shí)客戶端沒有反應(yīng),是因?yàn)榉?wù)端還在阻塞調(diào)試中,回到服務(wù)端輸入 continue,如下所示:

Nebula Graph源碼分析

經(jīng)過 session 驗(yàn)證后,進(jìn)入 executionEngine->execute() 中,step 進(jìn)入函數(shù)內(nèi)部

auto plan = new ExecutionPlan(std::move(ectx));
plan->execute();

繼續(xù) step 進(jìn)入ExecutionPlanexecute 函數(shù)內(nèi)部,然后執(zhí)行到

auto result = GQLParser().parse(rctx->query());

parse 這塊主要使用 flex & bison,用于詞法分析和語法解析構(gòu)造對(duì)象到抽象語法樹,其詞法文件是 src/parser/scanner.lex,語法文件是 src/parser/parser.yy,其詞法分析類似于正則表達(dá)式,語法分析舉例如下:

go_sentence
    : KW_GO step_clause from_clause over_clause where_clause yield_clause {
        auto go = new GoSentence();
        go->setStepClause($2);
        go->setFromClause($3);
        go->setOverClause($4);
        go->setWhereClause($5);
        if ($6 == nullptr) {
            auto *cols = new YieldColumns();
            for (auto e : $4->edges()) {
                if (e->isOverAll()) {
                    continue;
                }
                auto *edge  = new std::string(*e->edge());
                auto *expr  = new EdgeDstIdExpression(edge);
                auto *col   = new YieldColumn(expr);
                cols->addColumn(col);
            }
            $6 = new YieldClause(cols);
        }
        go->setYieldClause($6);
        $$ = go;
    }

其在匹配到對(duì)應(yīng)到 go 語句時(shí),就構(gòu)造對(duì)應(yīng)的節(jié)點(diǎn),然后由 bison 處理,最后生成一個(gè)抽象的語法樹。

詞法語法分析后開始執(zhí)行模塊,繼續(xù) gdb,進(jìn)入 excute 函數(shù),一直 step 直到進(jìn)入ShowExecutor::execute 函數(shù)。

Nebula Graph源碼分析

繼續(xù) next 直到 showSpaces(),step 進(jìn)入此函數(shù)

auto future = ectx()->getMetaClient()->listSpaces();
auto *runner = ectx()->rctx()->runner();
'''
'''
std::move(future).via(runner).thenValue(cb).thenError(error);

此時(shí) Query Service 通過 metaClient 和 Meta Service 通信拿到 spaces 數(shù)據(jù),之后通過回調(diào)函數(shù) cb 回傳拿到的數(shù)據(jù),至此 nGQL 語句 SHOW SPACES; 已經(jīng)執(zhí)行完畢,而其他復(fù)雜的語句也可以以此類推。

  • 如果是正在運(yùn)行的服務(wù),可以先查出該服務(wù)的進(jìn)程 ID,然后通過 gdb attach PID 來調(diào)試該進(jìn)程;

  • 如果不想啟動(dòng)服務(wù)端和客戶端進(jìn)行調(diào)試,在 src 目錄下的每個(gè)文件夾下都有一個(gè) test 目錄,里面都是對(duì)對(duì)應(yīng)模塊或者功能進(jìn)行的單元測(cè)試,可以直接編譯對(duì)應(yīng)的單元模塊,然后跟蹤運(yùn)行。方法如下:

    1. 通過對(duì)應(yīng)目錄下的 CMakeLists.txt 文件找到對(duì)應(yīng)的模塊名

    2. 在 build 目錄下 make 模塊名,在 build/bin/test 目錄下生成對(duì)應(yīng)的二進(jìn)制程序

    3. gdb 跟蹤調(diào)試該程序

“Nebula Graph源碼分析”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI