redis從2.6開始支援lua指令碼,和事務的功能類似,可以通過lua指令碼原子的執行多個redis命令。redis提供了eval和evalsha命令執行lua指令碼。
redis在伺服器內嵌了乙個lua壞境,並進行了一系列的修改,從而確保這個lua壞境可以滿足redis伺服器的需要,通過下列步驟建立並修改lua壞境:
建立乙個基礎lua壞境,通過呼叫lua的c api函式lua_open。
載入多個函式庫到lua壞境中,讓lua指令碼可以使用這些函式來進行資料操作。包括lua核心函式(assert、error、pairs、tostring、pcall等)、**庫(比如table.concat、table.insert等)、字串庫(string.x)、數學庫(math.x)、除錯庫(debug.x)、cjson庫、struct庫、cmsgpack庫。
建立全域性**redis,該**包含了對redis進行操作的函式,比如用於在lua指令碼中執行redis命令的redis.call和redis.pcall函式、用於記錄日誌的redis.log函式。
使用redis自製的隨機函式替換lua原有的***隨機函式,替換後的隨機函式對於相同的seed總會產生相同的隨機數序列。
建立排序輔助函式,lua壞境使用這個輔助函式來對一部分redis命令的結果進行排序,消除命令的不確定性,比如smembers這種命令多次執行可能會產生不同的結果,通過輔助函式來對結果進行排序讓它們每次產生同樣的結果。
建立redis.pcall函式的錯誤報告輔助函式,提供詳細的出錯資訊。
對lua壞境中的全域性變數進行保護,防止使用者在執行lua指令碼的過程中,將額外的變數新增到lua壞境中,不過redis沒有禁止使用者修改已存在的全域性變數,所以使用lua指令碼的時候需要小心,以免錯誤的修改了已存在的全域性變數。
將完成修改的lua壞境儲存到伺服器狀態的lua屬性(redisserver結構的屬性)中,等待執行伺服器傳來的lua指令碼。
redis伺服器建立了兩個用於與lua壞境進行協作的元件,它們分別是負責執行lua指令碼中的redis命令的偽客戶端,以及用於儲存lua指令碼的lua_scripts字典。
偽客戶端負責處理lua指令碼中包含的redis命令,lua指令碼使用redis.call或者redis.pcall函式執行乙個redis命令,需要以下步驟:
lua壞境將redis.call或者redis.pcall函式想要執行的命令傳給偽客戶端。
偽客戶端將指令碼想要執行的命令傳給命令執行器。
命令執行器執行偽客戶端傳給它的命令,並將命令的執行結果返回給客戶端。
偽客戶端接收命令執行器返回的命令結果,並將這個命令結果返回給lua壞境。
lua壞境在接收到命令結果之後,將該結果返回給redis.call或者redis.pcall。
接收到結果的redis.call或redis.pcall函式將命令結果作為函式返回值返回給指令碼的呼叫者。
作為乙個屬性存放在redisserver結構中,字典的鍵為lua指令碼的sha1校驗和,而字典的值時sha1校驗和對應的lua指令碼,redis伺服器會將所有被eval命令執行過的lua指令碼,以及所有被script load命令載入過的lua指令碼都儲存到lua_scripts字典裡面。
eval命令實現分為三個步驟:
1、根據客戶端給定的lua指令碼,在lua壞境中定義乙個lua函式,函式名稱由f_字首加上指令碼的sha1校驗和(四十個字元)組成,函式體為指令碼本身。
2、將客戶端給定的指令碼儲存到lua_scripts字典中。
3、執行步驟1中定義的函式,以此來執行客戶端給定的lua指令碼,過程如下:
每個被eval命令成功執行過的lua指令碼都會生成乙個sha1校驗和,為了節省頻寬資源,在下次執行相同的指令碼時可以使用evalsha命令,把之前生成的校驗和傳到伺服器就可以了。
當伺服器執行在複製模式下,eval命令、script flush、script load、evalsha命令會複製給從伺服器,除了evalsha命令,其它三個命令都是直接傳播,在傳播evalsha命令,先檢查從伺服器是否載入過這個命令,如果載入過了直接複製,如果未載入過先要把evalsha命令轉換成等價的eval命令再傳播。
Redis設計實現 學習筆記
最近在準備面試,問到redis相關知識,只能說個皮毛,說的既不深入也不全面,所以抓緊突擊一下,先學 redis設計與實現 選擇看書的原因是 書中全面深入,且能出書一定十分用心 搜部落格也找不到比書更全面的文章,且費時 直接看原始碼乙個是對c掌握不好,且易困,效率不高,所以跟著書同步學原始碼,是我認為...
Linux設計與實現學習筆記
從第三章開始吧,前面都是overview的介紹 第三章 程序管理 程序的概念 處於執行期的程式 其他占用的資源 開啟的檔案,掛起的訊號.linux中線程是一種特殊的程序,區別於其他系統。fork exec exit 程序描述符及任務結構 每個程序對應乙個資料結構 task struct,稱為程序描述...
《Redis設計與實現》學習筆記 單機資料庫
乙個redis伺服器例項在單機執行時可以新增多個資料庫來儲存鍵值對,redis在實現中通過乙個redisdb結構體來描述資料庫,該結構體中有乙個字典型別的字段來儲存資料庫中所有的鍵值對,redisserver結構體來描述伺服器例項,該結構體中有乙個dbnum欄位來儲存資料庫數量,乙個redisdb陣...