Redis Lua腳本調試


Redis的

 

從版本3.2開始,Redis包含一個完整的Lua調試器,可以用來使編寫復雜Redis腳本的任務更加簡單。

由於Redis 3.2仍處於測試階段,請unstable從Github 下載Redis 分支並編譯它以測試調試器。您可以使用Redis unstable來調試稍后在穩定版本的Redis中運行的腳本,因此調試器已經可用於實際術語。

Redis Lua調試器,代號LDB,具有以下重要功能:

  • 它使用服務器 - 客戶端模型,因此它是一個遠程調試器。Redis服務器充當調試服務器,而默認客戶端則是redis-cli但是,可以通過遵循服務器實現的簡單協議來開發其他客戶端。
  • 默認情況下,每個新的調試會話都是分叉會話。這意味着在調試Redis Lua腳本時,服務器不會阻塞並可用於開發或者為了並行執行多個調試會話。這也意味着在腳本調試會話結束后回滾更改,因此可以使用與上一個調試會話完全相同的Redis數據集再次重新啟動新的調試會話。
  • 可以根據需要使用備用同步(非分叉)調試模型,以便可以保留對數據集的更改。在此模式下,服務器會阻止調試會話處於活動狀態。
  • 支持逐步執行。
  • 支持靜態和動態斷點。
  • 支持將調試腳本記錄到調試器控制台中。
  • 檢查Lua變量。
  • 跟蹤由腳本執行的Redis命令。
  • Redis和Lua值的漂亮印刷。
  • 無限循環和長執行檢測,模擬斷點。

快速開始

開始使用Lua調試器的一個簡單方法是觀看此視頻介紹:

重要說明:請確保使用Redis生產服務器避免調試Lua腳本。請改用開發服務器。另請注意,使用同步調試模式(這不是默認設置)會導致Redis服務器阻塞調試會話持續的所有時間。

要使用redis-cli以下步驟啟動新的調試會話

  1. 使用首選編輯器在某個文件中創建腳本。假設您正在編輯位於的Redis Lua腳本/tmp/script.lua
  2. 啟動調試會話:

    ./redis-cli --ldb --eval /tmp/script.lua

請注意,通過--eval選項,redis-cli您可以將鍵名和參數傳遞給腳本,並以逗號分隔,如下例所示:

./redis-cli --ldb --eval /tmp/script.lua mykey somekey , arg1 arg2

您將進入一個redis-cli不再接受其正常命令的特殊模式,而是打印一個幫助屏幕並將未修改的調試命令直接傳遞給Redis。

唯一沒有傳遞給Redis調試器的命令是:

  • quit - 這將終止調試會話。這就像刪除所有斷點並使用continuedebugging命令一樣。此外,命令將退出redis-cli
  • restart- 調試會話將從頭開始重新啟動,從文件重新加載新版本的腳本因此,正常的調試周期包括在調試之后修改腳本,並調用restart以便在新腳本更改時再次開始調試。
  • help - 此命令傳遞給Redis Lua調試器,該調試器將打印如下命令列表:
lua debugger> help
Redis Lua debugger help:
[h]elp               Show this help.
[s]tep               Run current line and stop again.
[n]ext               Alias for step.
[c]continue          Run till next breakpoint.
[l]list              List source code around current line.
[l]list [line]       List source code around [line].
                     line = 0 means: current position.
[l]list [line] [ctx] In this form [ctx] specifies how many lines
                     to show before/after [line].
[w]hole              List all source code. Alias for 'list 1 1000000'.
[p]rint              Show all the local variables.
[p]rint <var>        Show the value of the specified variable.
                     Can also show global vars KEYS and ARGV.
[b]reak              Show all breakpoints.
[b]reak <line>       Add a breakpoint to the specified line.
[b]reak -<line>      Remove breakpoint from the specified line.
[b]reak 0            Remove all breakpoints.
[t]race              Show a backtrace.
[e]eval <code>       Execute some Lua code (in a different callframe).
[r]edis <cmd>        Execute a Redis command.
[m]axlen [len]       Trim logged Redis replies and Lua var dumps to len.
                     Specifying zero as <len> means unlimited.
[a]abort             Stop the execution of the script. In sync
                     mode dataset changes will be retained.

Debugger functions you can call from Lua scripts:
redis.debug()        Produce logs in the debugger console.
redis.breakpoint()   Stop execution as if there was a breakpoint in the
                     next line of code.

請注意,啟動調試器時,它將以步進模式啟動它將停止在腳本的第一行,它在執行之前實際執行某些操作。

從這一點開始,您通常會調用step以執行該行並轉到下一行。在您執行步驟時,Redis將顯示服務器執行的所有命令,如以下示例所示:

* Stopped at 1, stop reason = step over
-> 1   redis.call('ping')
lua debugger> step
<redis> ping
<reply> "+PONG"
* Stopped at 2, stop reason = step over

<redis><reply>線示出通過僅執行的行執行的命令,以及來自服務器的答復。請注意,這僅在步進模式下發生。如果您使用continue以執行腳本直到下一個斷點,則不會將命令轉儲到屏幕上以防止輸出過多。

終止調試會話

當腳本自然終止時,調試會話結束並 redis-cli以正常的非調試模式返回。您可以像往常一樣使用該restart命令重新啟動會話

停止調試會話的另一種方法是redis-cli 通過按下手動中斷Ctrl+C請注意,也無論如何打破之間的連接redis-cliredis-server將中斷調試會話。

關閉服務器時,所有分叉的調試會話都將終止。

縮寫調試命令

調試可能是一個非常重復的任務。因此,每個Redis調試器命令都以不同的字符開頭,您可以使用單個初始字符來引用該命令。

因此,例如,step您可以輸入而不是鍵入s

斷點

如在線幫助中所述,添加和刪除斷點很簡單。只需使用b 1 2 3 4在第1,2,3,4行添加b 0斷點。該命令將刪除所有斷點。可以使用as參數刪除選定的斷點,即我們要刪除的斷點所在的行,但前綴為減號。例如b -3,從第3行中刪除斷點。

請注意,將斷點添加到Lua從不執行的行(如聲明局部變量或注釋)將不起作用。斷點將被添加,但由於腳本的這部分將永遠不會被執行,程序將永遠不會停止。

動態斷點

使用該breakpoint命令可以將斷點添加到特定行中。但是,有時我們只想在發生特殊情況時才停止執行程序。為此,您可以使用redis.breakpoint()Lua腳本中的 函數。調用時,它會模擬下一行中將要執行的斷點。

if counter > 10 then redis.breakpoint() end

此功能在調試時非常有用,因此我們可以避免多次手動繼續執行腳本,直到遇到給定條件。

同步模式

如前所述,但默認LDB使用分叉會話來回滾腳本在調試時所操作的所有數據更改。在調試期間,確定性通常是一件好事,因此可以啟動連續的調試會話,而無需將數據庫內容重置為其原始狀態。

但是,為了跟蹤某些錯誤,您可能希望保留每個調試會話對密鑰空間執行的更改。當這是一個好主意,你應該使用一個特殊的選項,啟動調試器ldb-sync-moderedis-cli

./redis-cli --ldb-sync-mode --eval /tmp/script.lua

請注意,在此模式下在調試會話期間無法訪問Redis服務器,因此請小心使用。

在此特殊模式下,該abort命令可以使操作中的更改中途停止腳本到數據集。請注意,與正常結束調試會話相比,這是不同的。如果你只是中斷redis-cli腳本將完全執行,然后會話終止。相反,abort您可以在中間中斷腳本執行,並在需要時啟動新的調試會話。

從腳本記錄

redis.debug()命令是一個功能強大的調試工具,可以在Redis Lua腳本中調用,以便將內容記錄到調試控制台中:

lua debugger> list
-> 1   local a = {1,2,3}
   2   local b = false
   3   redis.debug(a,b)
lua debugger> continue
<debug> line 3: {1; 2; 3}, false

如果腳本在調試會話之外執行,redis.debug()則根本不起作用。請注意,該函數接受多個參數,這些參數由輸出中的逗號和空格分隔。

正確顯示表和嵌套表,以便為程序員調試腳本使值易於觀察。

使用print檢查程序狀態eval

雖然redis.debug()可以使用函數直接從Lua腳本中打印值,但通常在步進或停止到斷點時觀察程序的局部變量很有用。

print命令就是這樣,並在調用幀中執行查找,從當前的一個回到之前的一個,直到頂層。這意味着即使我們進入Lua腳本中的嵌套函數,我們仍然可以使用print foo查看foo調用函數的上下文中的值。在沒有變量名稱的情況下調用時,print將打印所有變量及其各自的值。

eval命令在當前調用幀的上下文之外執行小塊Lua腳本(使用當前Lua內部結構無法在當前調用幀的上下文中進行評估)。但是,您可以使用此命令來測試Lua函數。

lua debugger> e redis.sha1hex('foo')
<retval> "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"

調試客戶端

LDB使用客戶端 - 服務器模型,其中Redis服務器充當使用RESP進行通信的調試服務器雖然redis-cli是默認的調試客戶端,但只要滿足以下條件之一,任何客戶端都可用於調試:

  1. 客戶端提供本機接口,用於設置調試模式和控制調試會話。
  2. 客戶端提供了一個通過RESP發送任意命令的接口。
  3. 客戶端允許將原始消息發送到Redis服務器。

例如,Redis的插件用於ZeroBrane工作室使用LDB集成Redis的-盧阿以下Lua代碼是插件如何實現的簡化示例:

local redis = require 'redis'

-- add LDB's Continue command
redis.commands['ldbcontinue'] = redis.command('C')

-- script to be debugged
local script = [[
  local x, y = tonumber(ARGV[1]), tonumber(ARGV[2])
  local result = x * y
  return result
]]

local client = redis.connect('127.0.0.1', 6379)
client:script("DEBUG", "YES")
print(unpack(client:eval(script, 0, 6, 9)))
client:ldbcontinue()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM