新聞中心
一、引言

10年積累的成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、外貿(mào)網(wǎng)站建設(shè)經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站制作后付款的網(wǎng)站建設(shè)流程,更有江夏免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
Redis是高性能的key-value數(shù)據(jù)庫(kù),
在很大程度克服了memcached這類key/value存儲(chǔ)的不足,在部分場(chǎng)景下,是對(duì)關(guān)系數(shù)據(jù)庫(kù)的良好補(bǔ)充
。
得益于超高性能和豐富的數(shù)據(jù)結(jié)構(gòu),Redis已成為當(dāng)前架構(gòu)設(shè)計(jì)中的首選key-value存儲(chǔ)系統(tǒng)。
雖然Redis官網(wǎng)上提供了200多個(gè)命令,但做程序設(shè)計(jì)時(shí)還是避免不了為了實(shí)現(xiàn)一小步業(yè)務(wù)邏輯而多次調(diào)用Redis的情況。
以compare and set場(chǎng)景為例
。
如果使用Redis原生命令,需要從Redis中獲取這個(gè)key,然后提取其中的值進(jìn)行比對(duì):
如果相等就不做處理;
如果不相等或者key不存在則將key設(shè)置成目標(biāo)值。
僅僅一個(gè)單點(diǎn)的compare and set操作就需要與Redis通訊兩次。
此外,這種分散操作無法利用Redis的原子特性,占用多次網(wǎng)絡(luò)IO。
今天我們就來探討一下如何優(yōu)雅地應(yīng)對(duì)上述場(chǎng)景。
二、Redis與Lua
在介紹Lua之前,我們需要先對(duì)這個(gè)語言有個(gè)初步了解。Lua 是一個(gè)小巧的腳本語言,幾乎可以運(yùn)行在所有操作系統(tǒng)和平臺(tái)上。我們一般不會(huì)用Lua處理特別復(fù)雜的事務(wù),因此只需了解一些lua的基本語法即可。
Redis問世之后,其開發(fā)者也意識(shí)到了開篇提到的問題,因此Redis從2.6版本開始支持Lua腳本。新版本的Redis還支持Lua Script debug,感興趣的小伙伴可以去官網(wǎng)的Documentation中找到對(duì)應(yīng)介紹和QuickStart。
有了Lua腳本之后,使用Redis程序時(shí)便能夠在以下方面實(shí)現(xiàn)顯著提升:
- 減少網(wǎng)絡(luò)開銷 :本來N次網(wǎng)絡(luò)請(qǐng)求的操作,可以用一個(gè)請(qǐng)求完成。原先N次請(qǐng)求的邏輯放在Redis服務(wù)器上完成,減少了網(wǎng)絡(luò)往返時(shí)延;
- 原子操作 :Redis會(huì)將整個(gè)腳本作為一個(gè)整體執(zhí)行,中間不會(huì)被其他命令插入。這是一個(gè)重要特性,一定要拿小本本記好。至于為什么是一個(gè)原子操作,我們以后再分析;
- 復(fù)用:客戶端發(fā)送的腳本會(huì)永久存儲(chǔ)在Redis中。這樣其他客戶端就可以復(fù)用這一腳本,而不需要使用代碼完成同樣的邏輯。
所以現(xiàn)在流傳一句話:要想學(xué)好Redis,必會(huì)Lua Script。
三、通過Lua腳本實(shí)現(xiàn)compare and set
接下來我們就實(shí)現(xiàn)一個(gè)簡(jiǎn)單的compare and set,并通過這個(gè)例子感受一下Lua腳本給Redis使用帶來的全新體驗(yàn)。
首先看一下如何讓Redis執(zhí)行Lua腳本。
3.1 Redis的EVAL
- Redis 127.0.0.1:6379> EVAL script numkeys key [key ...] arg [arg ...]
- script :參數(shù)是一段 Lua 5.1 腳本程序。腳本不必(也不應(yīng)該)定義為一個(gè)Lua函數(shù)。
- numkeys :用于指定鍵名參數(shù)的個(gè)數(shù)。
- key [key ...] :從 EVAL 的第三個(gè)參數(shù)開始算起,表示在腳本中所用到的Redis鍵(key)。在Lua中,這些鍵名參數(shù)可以通過全局變量 KEYS 數(shù)組,用1為基址的形式訪問( KEYS[1] ,KEYS[2],依次類推)。
- arg [arg ...] :附加參數(shù),在Lua中通過全局變量ARGV數(shù)組訪問,訪問的形式和KEYS變量類似( ARGV[1] 、 ARGV[2] ,諸如此類)。
這里借用一下官網(wǎng)的例子。
上述腳本直接返回了入?yún)ⅰ?br />
- eval為Redis關(guān)鍵字;
- 第一個(gè)引號(hào)中的內(nèi)容就是Lua腳本;
- 2為參數(shù)個(gè)數(shù);
- key1和key2是KEYS[1]、KEYS[2]的入?yún)ⅲ?nbsp;
- first和second是ARGV[1],ARGV[2]的入?yún)ⅰ?/li>
大家可以簡(jiǎn)單地將KEYS[1],KEYS[2], ARGV[1],ARGV[2]理解為占位符。
3.2 執(zhí)行腳本文件和緩存腳本
如果只能在命令行中寫腳本執(zhí)行,遇到復(fù)雜的腳本程序豈不是會(huì)抓狂?
下面我們來看一下,如何讓Redis執(zhí)行Lua腳本文件,同時(shí)也驗(yàn)證一下lua腳本的復(fù)用特性(以后我們?cè)僖膊恍枰ㄆ谂縿h除某些符合特定規(guī)則的key了)。
- Redis 127.0.0.1:6379> SCRIPT LOAD script
- Redis 127.0.0.1:6379> EVALSHA sha1 numkeys key [key ...] arg [arg ...]
Redis提供了一個(gè)SCRIPTLOAD命令,命令后面的script即為L(zhǎng)ua腳本。命令將腳本script添加到腳本緩存中,但并不立即執(zhí)行這個(gè)腳本。執(zhí)行命令后,Redis會(huì)返回一個(gè)SHA1串,第二個(gè)EVALSHA命令即可執(zhí)行。
需要注意的是,腳本可以在緩存中保留無限長(zhǎng)的時(shí)間,直到執(zhí)行完SCRIPT FLUSH。我們來看一下效果。
Redis還支持直接執(zhí)行Lua腳本文件。
首先編寫并存儲(chǔ)一個(gè)Lua腳本。
然后調(diào)用Redis-cli –eval命令。
Redis-cli –eval命令語法基本與原eval語法相同。
3.3 使用Lua腳本實(shí)現(xiàn)compare and set
compareand set的實(shí)現(xiàn)邏輯是這樣的:
首先獲取Redis中指定key的value,然后與給定值進(jìn)行比較:
如果相等,則將key設(shè)定為目標(biāo)值并返回一個(gè)標(biāo)識(shí)符;
如果不相等,則不作任何操作并返回一個(gè)標(biāo)識(shí)符。
- if Redis.call('get', KEYS[1]) == ARGV[1] then
- Redis.call('set', KEYS[1], ARGV[2]);
- return 1
- else
- return 0 end
下面我們來測(cè)試一下這個(gè)腳本。
首先向Redis的指定key compareAndSet:key寫入一個(gè)值value。
在Redis中執(zhí)行l(wèi)ua腳本。
可以看到第一次執(zhí)行返回1,說明修改成功了;
再使用原參數(shù)執(zhí)行時(shí)返回0,說明沒有做任何修改。
我們?cè)俨樵円幌耤ompareAndSet:key這個(gè)key。
可以看到compareAndSet:key這個(gè)key已經(jīng)被修改為new_value了。
四、總結(jié)
我們通過lua腳本實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的compareAndSet操作。
下面我們通過這個(gè)例子來驗(yàn)證一下開篇提到的特性。
- 減少網(wǎng)絡(luò)開銷 :不使用腳本的情況下,我們實(shí)現(xiàn)一個(gè)compareAndSet至少需要與Redis交互兩次,而現(xiàn)在只需要執(zhí)行一次操作即可完成;
- 原子操作 :得益于Redis的設(shè)計(jì),Redis會(huì)將整個(gè)腳本作為一個(gè)整體執(zhí)行,中間不會(huì)被其他命令插入。因此在編寫腳本的過程中無需擔(dān)心出現(xiàn)競(jìng)態(tài)條件,無需使用事務(wù),感興趣的可以百度或等待以后后續(xù)文章更新;
- 復(fù)用:可以將一系列操作封裝成一個(gè)Lua腳本,存儲(chǔ)在文件或Redis上,下次使用時(shí)直接調(diào)用即可。
讀到這里,希望你已經(jīng)對(duì)Redis+Lua有了一定的了解,并能使用腳本完成一些簡(jiǎn)單的復(fù)合操作。后續(xù)還會(huì)繼續(xù)更新一些基于Lua腳本+java程序?qū)崿F(xiàn)的分布式數(shù)據(jù)結(jié)構(gòu),如延遲隊(duì)列、可重入鎖等,感興趣的小伙伴可以持續(xù)關(guān)注。
【本文是專欄機(jī)構(gòu)宜信技術(shù)學(xué)院的原創(chuàng)文章,微信公眾號(hào)“宜信技術(shù)學(xué)院( id: CE_TECH)”】
戳這里,看該作者更多好文
文章標(biāo)題:Redis進(jìn)階應(yīng)用:Redis+Lua腳本實(shí)現(xiàn)復(fù)合操作
網(wǎng)站網(wǎng)址:http://www.5511xx.com/article/cdepphc.html
其他資訊
- 數(shù)據(jù)庫(kù)調(diào)用方法大全,讓您輕松實(shí)現(xiàn)數(shù)據(jù)操作!(可以調(diào)用的數(shù)據(jù)庫(kù)嗎)
- Redis的哨兵架構(gòu)保障集群安全(Redis的哨兵架構(gòu))
- 計(jì)算機(jī)發(fā)展路線:小型機(jī)逐漸演變?yōu)閤86服務(wù)器(從小型機(jī)到x86服務(wù)器)
- Oracle數(shù)據(jù)庫(kù)中如果存在表就刪除不存在就創(chuàng)建的實(shí)例
- Linux系統(tǒng)是否適合進(jìn)行編程實(shí)踐?(適合編程linux系統(tǒng)嗎)


咨詢
建站咨詢
