Redis源碼閱讀【1-簡單動態字符串】
Redis源碼閱讀【2-跳躍表】
Redis源碼閱讀【3-Redis編譯與GDB調試】
Redis源碼閱讀【4-壓縮列表】
Redis源碼閱讀【5-字典】
Redis源碼閱讀【6-整數集合】
Redis源碼閱讀【7-quicklist】
Redis源碼閱讀【8-命令處理生命週期-1】
Redis源碼閱讀【8-命令處理生命週期-2】
Redis源碼閱讀【8-命令處理生命週期-3】
Redis源碼閱讀【8-命令處理生命週期-4】
Redis源碼閱讀【番外篇-Redis的多線程】
建議搭配源碼閱讀:源碼地址
文章目錄
1、介紹
本章主要是爲了介紹Redis的編譯方式,以及使用GDB對Redis進行調試的方法,爲後面講解源碼打下基礎,同時也介紹GDB這個C語言代碼調試利器的部分使用
2、Redis編譯
Redis編譯應該是一個必須掌握的技能,畢竟很多時候我們並不一定會直接使用Redis編譯好的包類型,可能會更具當前操作系統的情況,調整部分源碼編譯後再使用,例如Redis5當前的版本是不支持Windows的,如果大家想要使用Windows版本的Redis最好去官網下載Redis3以及之前的版本去自行編譯使用,此外當大家希望能在Redis中加入一些日誌或者其它東西的時候,一樣需要修改源碼進行編譯,那麼下面就介紹一下官方的推薦的編譯步驟(很簡單的)
2.1、獲取源碼
自行編譯的第一步當然就算獲取源碼,Redis獲取源碼的方式最直接的就是github,這裏我貼出Redis的github地址:https://github.com/antirez/redis,或者你可以通過github搜索Redis:
當然github上面的是最新版本的代碼,並非穩定版本代碼,許多新版本的特性會先在github中放出,讓大家下載調試體驗,當然線上穩定版本還是建議去官網下載Stable版本,地址:https://redis.io/download
2.2、目錄介紹
其中這個antirez/redis就是Redis在github上面官方的地址了。下載好後源碼,我們可以隨便導入到一個IDE裏面查看,這裏我使用的是Clion
項目結構如上圖所示:
目錄/文件 | 說明 |
---|---|
deps | Hiredis 模塊(輕量級訪問redis的客戶端),linenoise模塊(命令行編輯輔助,能實現自動補全) ,字典的定義實現,sds的定義實現,redis封裝的malloc,Lua等 |
src | 核心源碼,大多功能都在這塊實現,其中Redis自行實現了網絡框架在這個目錄中(ae_開頭的文件),Redis並未使用libevent作爲網絡模塊 |
tests | 測試模塊,用來測試Redis的代碼,大多測試用例和腳本都在這裏面 |
utils | Redis的工具實現 |
redis.conf | Redis官方源碼默認提供的配置文件 |
Makefile | Redis C語言編譯使用的Makefile,當然你也可以使用Cmake進行管理,當然Cmake支持的不是很好 |
2.3、編譯前的準備
在編譯前,我們需要進行一些準備工作,我們本人是在Ubuntu-18上面進行編譯的,Linux環境是推薦環境,Redis5目前只適配了Linux,並沒有適配Windows,那麼在Linux上進行編譯本身我們也需要準備和更新一些內庫,這裏我當且認爲你已經按照好了Ubuntu
1、更新Ubuntu到最新版本
sudo apt update
更新系統自帶內庫等等
2、下載編譯必備內庫,內包含一些C/C++必備的庫
sudo apt install build-essential
sudo apt install gcc-c++
3、除此外可能會使用到的內庫
apt-get install libqt4-* libqml*
4、如果出現has no member named(這個問題是由於官方升級了gcc導致的)
升級到 5.3及以上版本
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
//這裏退出xhell會恢復gcc版本
scl enable devtoolset-9 bash
//永久替換
echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile
5、安裝測試工具tcl
sudo apt install tcl
2.4、開始編譯
一切準備好後,準備開始編譯,進入到源碼目錄底下,項目的根目錄
直接編譯
make #直接編譯
make MALLOC=libc # 指定使用 libc對 malloc 編譯
make MALLOC=jemalloc # 指定使用 jemalloc 編譯但是要先安裝jemalloc依賴
當然你也可以編譯成32位版本
make 32bit
執行後結果如下:
這裏會提示你需要使用 make test 來執行內部的自測用例(test文件夾裏面),來判斷本次編譯是否完全成功
執行 make test
sudo apt install tcl # 需要先安裝tcl
make test
過程如下:
當出現這句化的時候證明自測已經成功
All tests passed withour errors!
這個時候進入項目根目錄底下的src目錄中你會發現幾個已經編譯好的二進制文件,是可以直接運行的
這兩個就是服務端和客戶端的運行入口了,其中默認的配置文件在外層根目錄(redis.conf)
運行 ./redis-server 或者 ./redis-server …/redis.conf
./redis-server
結果如下
這個時候Redis服務端已經運行起來了。我們再打開一個終端,運行下面的指令:
root@zengshilin-virtual-machine:/home/test/redis-5.0.7/src# ./redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> set test hello
OK
127.0.0.1:6379> get test
"hello"
到這裏我們的Redis已經完全編譯成功了
3、GDB調試
GDB是unix/linux的常用調試工具,其中GDB支持man手冊查閱,在Liunx這種經常沒有可視化界面的操作系統底下,GDB是一種經常使用的調試工具,那麼這裏我也推薦大家使用GDB來調試已經編譯好的Redis代碼,其中Redis官網對GDB的介紹如下:http://redis.io/topics/debugging
可見官方也是推薦GDB來調試Redis
3.1、安裝GDB
在Ubuntu底下安裝GDB使用這條指令即可
sudo apt-get install gdb
3.2、GDB調試編譯好的Redis
3.2.1、GDB模式啓動
進入到剛剛編譯好的Redis目錄src底下,輸入指令:
gdb redis-server
結果如下:
此時剛剛編譯好的redis-server已經進入到gdb的調試模式下,但是當前還未運行,然後我們啓動以下redis服務端,使用 r 或者 r …/redis.conf
(gdb) r ../redis.conf
可以看到當前的Redis在GDB調試模式下啓動了,這個使用我們再開一個新的窗口運行redis-cli查看效果如下:
127.0.0.1:6379> set test hello
OK
127.0.0.1:6379> get test
"hello"
127.0.0.1:6379> keys *
1) "test"
127.0.0.1:6379>
可見服務端當前也是可用狀態的
3.2.2、在Redis源碼上打斷點
GDB個其它調試一樣,可以打斷點在目標代碼上面,同時也支持單步調試等操作,我們在服務斷t_string.c文件上面的set命令打上斷點看看是否生效,代碼位置如圖所示:
我們將斷點打在setCommand上面,在gdb模式下執行:
(gdb) b setCommand
Breakpoint 1 at 0x609c0: file t_string.c, line 96.
斷點已經打好,這時候我們在gdb模式下啓動Redis
(gdb) r ../redis.conf
然後我們打開一個新終端,運行 redis-cli 輸入以下命令
127.0.0.1:6379> set test hello
可以看到服務斷那邊已經執行到斷點的位置
這時我們查看以下redis的運行棧
瞭解計算機操作系統的同學應該都知道,程序調用是基於棧的,所以這裏打印出當前線程運行所經歷的調用棧
我們通過以下指令來嘗試GDB調試:
(gdb) n # 單步執行
102 for (j = 3; j < c->argc; j++) {
(gdb) n
100 int flags = OBJ_SET_NO_FLAGS;
(gdb) n
99 int unit = UNIT_SECONDS;
(gdb) n
98 robj *expire = NULL;
(gdb) n
138 c->argv[2] = tryObjectEncoding(c->argv[2]);
(gdb) s # 進入函數內部
tryObjectEncoding (o=0x7ffff6c0e0c0) at object.c:431
431 robj *tryObjectEncoding(robj *o) {
(gdb) p *o # p 是 print的意思 打印當前變量
$1 = {type = 0, encoding = 8, lru = 454090, refcount = 1, ptr = 0x7ffff6c0e0d3}
(gdb) p o->type # 打印變量的成員屬性
$2 = 0
(gdb)
以上就算GDB調試的大致用法,也介紹大家可以多去官網看看gdb的其它使用技巧:http://www.gnu.org/software/gdb/
4、結束
這篇文章我們介紹了Redis在linux低下使用源碼編譯的過程,以及如何使用GDB調試工具來斷點調試已經編譯好的Redis,後續文章我也會不時使用GDB的方式來調試Redis的代碼運行過程,以便更好的理解Redis的源碼執行過程。