<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
我們在使用Redis的過程中,難免會遇到並行存取及資料更新的問題。但很多場景對資料的並行修改是很敏感的,比如庫存資料如果沒有做好並行讀取和更新的版本控制,就會導致嚴重的業務問題。今天就來說說應該如何做好並行存取及資料更新問題。
需要控制並行存取,說明這些並行的存取可能會對其他的存取造成影響。比如上面提到的庫存問題,若同一時期有多個使用者端存取商品A的庫存資料,並且可能要更更新庫存資料,這時候就需要對並行存取進行控制了。
說到底,並行存取需要控制的就是對資料的更新動作。 一般來說,使用者端要進行資料更新時可分為2個步驟:
單個存取來看,這個過程並沒什麼問題。但是並行多了,一分為二的過程就會造成資料錯誤的問題。這裡還是用庫存的例子來說:
這樣下來,很明顯能發現庫存資料錯了。10+1-1 = 10,正確庫存是10,而上述場景最後為9。
由此可見,這個一分為二的操作不具有原子性,從而產生了錯誤的結果。型別這種場景很多,因此我們需要對這些並行存取的場景加以控制。
Redis並行存取的控制,總的來說有2種方式。分別是加入鎖機制和讓一系列操作原子化。
首先第一點,加入鎖機制是很常見的解決方案。簡單來說就是一個使用者端存取資料之前,先要獲取鎖,等資料操作完之後再解鎖。而在這個使用者端擁有鎖的過程中,其他使用者端如果也想存取修改該資料,必須得等鎖釋放了之後,獲取到了鎖才行。
加鎖這個方案是可以解決並行存取的資料準確問題,但放在redis這個場景中並不是很好。首先,Redis作為快取本身並行存取就很多,頻繁的加鎖解鎖,會大大降低redis的存取效能;然後,Redis的使用者端在要加鎖時,需要用到分散式鎖。我們又得用額外的精力去維護這個分散式鎖。
操作原子化,也就是讓要執行的一系列動作都保持原子性操作。它的優點就是不需要加入額外的鎖機制。並行的資料準確性達到了,對Redis的效能也不會有太大的影響。
Redis要實現原子操作,總結有2種方式:
1.單命令操作
首先,單命令操作,將數值的加減直接用Redis命令來執行。像string的加減可用INCR、DECR操作,hash列表field的加減可用HINCRBY操作。
比如下面截圖,兩個使用者端在不同時刻讀取的linux_pids a值為4,各自+1、-1後a值為4。結果是正確的。
由此可見,用Redis的INCR、DECR等命令可以解決數值簡單增減的並行場景。但如果我們對資料的更新不僅僅是簡單的加減操作時,Redis的這些命令就無能為力了。此時我們可以考慮另一種方案:Lua指令碼。
2.Lua指令碼
Lua語言是由C寫的,因此支援多平臺和系統。從Redis2.6開始,Redis就內建了Lua直譯器,我們能直接用Redis使用者端來執行lua指令碼。
我們可以將需要執行的一系列操作用Lua指令碼寫好,然後用Redis執行它。Lua指令碼的方法能保證原子性操作的原因是:Redis會將Lua指令碼一次性執行,也就是說執行Lua指令碼是0-1的操作,要麼成功,要麼失敗。可以理解成MySQL的事務特性。
Redis使用lua指令碼有2種方式:
我們一般用第二種方式來執行。
使用者端使用方法:
先用script load
載入指令碼命令,再用evalsha
執行載入得到的sha1值。
127.0.0.1:6379> script load "return 'hello'"
"1b936e3fe509bcbc9cd0664897bbe8fd0cac101b"
127.0.0.1:6379> evalsha "1b936e3fe509bcbc9cd0664897bbe8fd0cac101b" 0
"hello"
再來看看Redis使用Lua指令碼的語法:
redis-cli --eval {lua_path} KEYS[1] KEYS[2]... , ARGV[1] ARGV[2]...
--eval: 執行lua指令碼的命令
{lua_path}: lua指令碼的路徑
KEYS[1] KEYS[2]: lua指令碼中要操作的redis鍵,我們可以在lua指令碼中用KEYS[1],KEYS[2],KEYS[3]指定多個
ARGV[1] ARGV[2]: 傳入到lua指令碼的引數,在指令碼中用ARGV[1],ARGV[2]...來獲取。
Redis使用lua指令碼的場景很多,最經典的案例當屬利用lua來控制某個IP的存取頻率了。比如說需要防止惡意存取網站的行為,我們規定1分鐘記憶體取次數不能超過30次,實現的方法有很多,比如說漏桶方案、令牌桶方案,但使用最多的還是Redis+lua的分散式限流方案。
我們用lua指令碼(test_lua.script)來簡單實現一下上述功能,就是1分鐘內若存取次數超過30,直接攔截,否則存取次數+1:
-- 限流的key
local limit_key = KEYS[1]
-- 限流次數
local limit_nums = 30
-- 當前存取次數
local current_num = tonumber(redis.call('get', limit_key) or 0)
-- 超出限流次數
if current_num + 1 > limit_num
then
return '超出存取次數'
-- 沒有超出限流數,存取次數+1
else
redis.call("INCRBY", limit_key, "1")
-- 第一次存取,設定過期時間
if current_num == 0 then
redis.call("expire", limit_key, "60")
return current + 1
end
用Redis執行,命令如下:
redis-cli --eval test_lua.script limit_key
本文介紹了Redis並行存取的控制問題,以及如何保證並行操作的原子化。原子化操作可通過單命令操作和Lua指令碼的方式實現。我們在應對相關問題時,可根據需要選擇對應方案解決之。
到此這篇關於Redis並行存取問題詳細講解的文章就介紹到這了,更多相關Redis並行存取內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45