您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“Nebula Graph源碼分析”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
對(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è)完整的 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)行分析
剛開始,可以拿到一個(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ù):
啟動(dòng)后通過
nebula.service status all
查看當(dāng)前的服務(wù)狀態(tài)
然后 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,如下所示:
經(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)入ExecutionPlan
的
execute
函數(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ù)。
繼續(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)行。方法如下:
通過對(duì)應(yīng)目錄下的 CMakeLists.txt 文件找到對(duì)應(yīng)的模塊名
在 build 目錄下 make 模塊名,在 build/bin/test 目錄下生成對(duì)應(yīng)的二進(jìn)制程序
gdb 跟蹤調(diào)試該程序
“Nebula Graph源碼分析”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(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)容。