手把手教你用gdb調試mongod

2020-09-22 hooting

MongoDB作為一款NoSQL資料庫,常應用在遊戲開發領域。 作為一個後端程序,進行CRUD操作是家常便飯,但如果不看源碼,便不會知道MongoDB底層是如何實現的,對自己寫的CRUD代碼,心裡就沒譜,不確定哪一行代碼就把MongoDB給壓垮了。遇到問題,不知道為啥MongoDB支撐不住,也就無從說起該怎樣哪裡優化。

開源MongoDB有上萬個文件,代碼量百萬行。閱讀MongoDB的源碼是一項具有挑戰的任務。一般的,我們可以從簡單的、自己感興趣的模塊開始閱讀。例如,先理解MongoDB在執行一條find命令時,是如何找到我們想要的結果。

本文,介紹如何編譯MongoDB源碼、如何用GDB調試MongoDB。

編譯安裝MongoDB

因為線上使用的是3.4.24版本,所以本文也採用該版本作為例子。

首先下載MongoDB源碼

wget https://fastdl.mongodb.org/src/mongodb-src-r3.4.24.tar.gz

解壓縮

tar -zxvf mongodb-src-r3.4.24.tar.gz

在解壓的目錄中,docs/building.md介紹了如何編譯安裝MongoDB。

首先是安裝依賴庫

apt-get install aptitudeaptitude install scons build-essentialaptitude install libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev

然後是通過scons命令進行MongoDB的編譯安裝。

scons core install --disable-warnings-as-errors

參數core,說明想要安裝的包括mongod,mongos, mongo。加入參數--disable-warnings-as-errors是為了忽略編譯過程的warning。

為了GDB能夠調試MongoDB,需要在編譯MongoDB時,加入-g參數。不然在調試時,會收到No symbol table is loaded的報錯。通過查看SConstruct文件,已經加了-ggdb參數,所以我們就不需要做修改,直接執行scons就可以。



編譯安裝後,會在build/install/bin目錄下,生成可執行文件:mongo,mongod,mongos,mongoperf

啟用GDB調試

首先啟動mongod。在build/install/bin目錄下,執行 ./mongod啟動mongod。

啟動後,可以用ps -ef | grep mongod查看mongod的進程號,然後用ps -p 進程號 -T查看mongod創建的線程信息。

啟動mongo。在build/install/bin目錄下,執行./mongo啟動mongo,使之直接連接mongod。

啟動後,再次用ps -p 進程號 -T查看mongod創建的線程信息。這時,會發現多了一個conn1線程。這個線程,是mongod為一個客戶端創建的。



在build/install/bin目錄下,啟動GDB,attach到mongod進程

gdb ./mongod 進程號

mongod是多線程,我們這裡只關心處理客戶端請求的線程。所以,先要切到相應的線程中。

使用info threads命令, 顯示當前可調試的所有線程,每個線程會有一個GDB為其分配的ID,後面操作線程的時候會用到這個ID。 前面有*的是當前調試的線程



可以看到,處理客戶端連接的線程,在GDB的編號是21,用thread 21切換到對應的線程中。

我們以find命令為例,介紹如何用GDB進行斷點調試。

斷點調試的第一步,就是加斷點。這就需要找到find的入口在哪裡,即在哪個文件的哪一行。 我們一般可以先快速過一遍mongod的源碼結構。在src/mongo/db/commands發現了大量以命令命名的文件。通過簡單分析我們有理由相信,find_cmd.cpp的run函數,就是find的入口。



確定了行號之後,就可以用gdb命令加斷點了:

b src/mongo/db/commands/find_cmd.cpp:230

加好斷點後,我們在啟動的mongo進程中,觸發find命令。

觸發命令後,我們在gdb會話中,輸入c告訴gdb繼續執行,直到遇到我們設置的斷點。



現在gdb已經定在了我們設置的斷點中,下面可以利用gdb的其他命令,如命令s,n等,跟蹤學習mongo的find命令實現了。

如果不幸的,我們沒法通過源碼發現find命令的入口,則只能藉助gdb使用更暴力一些的辦法。 在前文介紹的步驟中,當gdb關聯到客戶端的線程後,直接執行bt命令,看看現在的調用棧。



可以看到,線程在等待客戶端數據,對應的文件是sock.cpp:692。



通過閱讀源碼,我們直接在sock.cpp:697加斷點,客戶端發起find請求,然後一步步調試,就能進入find的入口。


docker編譯調試mongod

編譯安裝mongod在不同的環境,會遇到各種奇葩的問題。我們為了用GDB調試mongod,可能會花大量時間在解決環境配置上。為了解決煩惱的環境問題,這裡提供一個dockerfile,用docker可以完美的解決環境問題。

FROM debian:9RUN apt-get install -y wgetRUN apt-get install -y vimRUN apt-get install -y make# 在Docker Debian容器中安裝ps,top等命令RUN apt-get install -y procpsRUN apt-get install -y gccRUN apt-get install -y g++

相關焦點

  • 伺服器調製、調試和測試 - gdb調試
    Linux程式設計師必然都使用過gdb調試器來調試程序。這裡我們要討論如何使用gdb來調試多進程和多線程程序,因為這是後臺程序調試不可避免而又比較困難的部分。用gdb調試多進程程序如果一個進程通過fork系統調用創建子進程,gdb會繼續調試原來的進程,子進程則正常運行。那麼該如何調試紫禁城呢?常用的方法有如下兩種。單獨調試子進程子進程本質上說也是一個進程,因此我們可以用通用的gdb調試方法來調試它。
  • gdb工具對mysql進行源碼調試
    目前有很多文章描述如何源碼調試MySQL,主要過程是通過源碼編譯一個Debug版的MySQL出來,然後使用gdb工具進行調試。本文介紹一種更加簡便的調試MySQL的方法。一、下載MySQL Linux Generic版本MySQL Linux Genric版本,解壓即可使用,它的二進位文件mysqld本身包含符號表等調試信息,省去了我們自己編譯MySQL Debug版本的煩惱。
  • 使用gdbgui在瀏覽器中遠程多語言調試
    大多數人都喜歡IDE給你帶來的便利的可視化調試體驗,少數人則喜歡GDB式命令行的高效調試,那麼有沒有什麼方法能把兩者結合起來呢?在本文中,蟲蟲要給大家介紹一個這樣的工具gdbgui,是gdb的一個Web可視化擴展,可以讓我們通過Web在線可視化的調試。
  • 在Linux上利用core dump和GDB調試segfault
    今天蟲蟲再給大家介紹下利用core dump文件和gdb做應用程式調試和追蹤的方法。段錯誤(segfault)"段錯誤"是程序試圖操作不允許訪問或試圖訪問的不允許內存的情況。但是valgrind給出的東西有限,要深入探究還得利用得core dump文件,下面我們就對其進一步探究:如何獲得core dump我們前面說了core dump是程序發生異常時候,其內存使用副本的轉存文件,當你需要調試程具體序出錯時的信息時候,它非常有用。當程序發生段錯誤時,Linux內核有時會向磁碟寫入一個core dump文件。
  • 一文入門Linux下gdb調試(二)
    該文件也是二進位文件,可以使用gdb、elfdump、objdump或者windows下的windebug、solaris下的mdb進行打開分析裡面的具體內容。基於core文件的快照功能,我們就可以專門調試分析程序崩潰原因了,gdb同時調試一個運行程序和core文件,然後進行gdb調試的步驟,然後查看代碼崩潰瞬間系統信息。
  • 一文入門Linux下gdb調試(二)
    基於core文件的快照功能,我們就可以專門調試分析程序崩潰原因了,gdb同時調試一個運行程序和core文件,然後進行gdb調試的步驟,然後查看代碼崩潰瞬間系統信息。使用如下:gdb ./abort .
  • gdb實用的調試技巧:啟動方式、堆棧信息、單步調試
    對於很多開發者來說,開發過程中難免會遇到各種各樣的bug, 所以,每個開發者應該考慮如何快速高效定位問題原因,而gdb是linux上很實用的調試工具,熟練掌握其調試技巧,將有助於提高解決問題的效率,也是開發者應該掌握的基本技能。
  • gdb實用的調試技巧:啟動方式、堆棧信息、單步調試
    對於很多開發者來說,開發過程中難免會遇到各種各樣的bug, 所以,每個開發者應該考慮的如何快速高效定位問題原因,而gdb是linux上很實用的調試工具,熟練掌握其調試技巧,將有助於提高解決問題的效率,也是開發者應該掌握的基本技能。
  • 一文入門Linux下gdb調試(一)
    本文轉載自【微信公眾號:羽林君,ID:Conscience_Remains】總述在window下我們習慣了IDE的各種調試按鈕,說實話確實挺方便的,但到了Linux下,沒有那麼多的IDE支持我們調試,但是Linux有也有強大的命令行C/C++的調試工具——GDB,GNU提供的開源調試工具。
  • 一文入門Linux下gdb調試(一)
    gdb,GNU提供的開源調試工具。/c++文件編譯通常就是加-o 進行編譯成可執行文件,但是我們如果需要要調試,則需要加一個 -g 用來向編譯器進行表明該程序需要編譯成可以gdb調試的代碼,加上編譯信息,生成的執行文件就會變大,如圖所示。
  • 新技巧GET: 使用gdbserver來調試Linux CMake工程
    關於GdbserverGdbserver是一個運行在Linux上的調試工具,用於調試Linux上運行的應用程式。當目標系統是一個嵌入式系統時,可能因為資源的限制而不能運行全功能版本的gdb,這個時候gdbserver就顯得格外的有用了。
  • Apollo開發者說丨使用GDB調試Apollo項目
    11# 啟動方法3:在Dreamview中啟動Planning模塊,然後使用ps aux | grep planning命令查找12# planning進程ID(PID),假設為35872,則使用attach模式附加到當前planning進程調試13sudo gdb -q bazel-bin/modules/planning/
  • gdbgui:使用瀏覽器和進行GDB遠程DEBUG
    碼農需要開花大量時間調試和維護項目代碼。代碼調試是每個碼農的最基礎技能之一。大多數人都喜歡IDE給你帶來的便利的可視化調試體驗,少數人則喜歡GDB式命令行的高效調試,那麼有沒有什麼方法能把兩者結合起來呢?
  • 乾貨分享丨關於GDB 調試入門,看這篇就夠了
    概述通常用C/C++來開發應用程式,會使用GCC交叉工具編譯鏈來把程序編譯成對應平臺的二進位文件,才能在開發板的Linux平臺上運行。官網:http://www.gnu.org/savannah-checkouts/gnu/gdb/index.htmlGDB能做什麼啟動、暫停、停止程序的運行;調試出現崩潰、有邏輯錯誤的程序時給程序設置斷點;在程序設置的斷點處停止程序運行,查看變量的實際值 、寄存器的值;除了在斷點處可以查看變量之外,還可以在不改變程序源碼的情況下改變一些變量的值
  • VR丨手把手教你用UE4開發VIVE: 區域網聯機(C)
    系列回顧:手把手教你用UE4開發VIVE:基礎教程手把手教你用UE4開發VIVE:拋物線定位移動篇手把手教你用
  • 建立ARM平臺上的交叉調試器gdb和gdbserver
    其中:host指定了運行環境為i386機器,target指定了需要調試的目標機環境(我使用的ARM toolchain是armv5-linux-uclibc-gcc,因此這樣指定,如果是用arm-linux-gcc,則 --target=arm-linux),prefix指定了編譯後的結果存放的位置,也就是安裝目錄。
  • GDB 多線程之旅
    Linux下的多線程調試就比較騷氣了,由於沒有界面的「光環」加持,所以我們必須要藉助強大的輔助工具----GDB,熟練使用GDB調試程序,是一個linux程式設計師必備的技能之一;這裡我就總結和回顧一下linux環境下GDB調試多線程的一個過程~GDB 線程調試命令常用線程調試命令:
  • 程式設計師的術與道:術——gdb基本操作
    gdb同樣是GNU出品的一款功能強大的工具,橫掃linux世界gdb是一款調試工具,其功能之強大,深入使用之後你就會有感受。同gcc一樣,隨著gdb的使用你會有一種掌控一切的感覺。因為gdb更接近於底層,和作業系統的關係是那樣近。其操作的方式是那樣原始、野蠻,換句話說,更難但是學到的東西更多。
  • Linux C/C++ 開發人員要熟練掌握 GDB 調試代碼塊
    一、啟動GDB調試使用 GDB 調試程序一般有三種方式: gdb filename gdb attach pid gdb filename corename1、直接調試目標程序2、附加進程3、調試 core
  • linux下GDB使用方法
    gdb是GNU開源組織發布的一個強大的Linux下的程序調試工具。 一般來說,GDB主要幫助你完成下面四個方面的功能:1、啟動你的程序,可以按照你的自定義的要求隨心所欲的運行程序。2、可讓被調試的程序在你所指定的調置的斷點處停住。