最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Redis并發(fā)訪問問題詳細(xì)講解

 更新時間:2022年12月02日 10:25:50   作者:肥肥技術(shù)宅  
本文主要介紹了Redis如何應(yīng)對并發(fā)訪問,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

我們在使用Redis的過程中,難免會遇到并發(fā)訪問及數(shù)據(jù)更新的問題。但很多場景對數(shù)據(jù)的并發(fā)修改是很敏感的,比如庫存數(shù)據(jù)如果沒有做好并發(fā)讀取和更新的版本控制,就會導(dǎo)致嚴(yán)重的業(yè)務(wù)問題。今天就來說說應(yīng)該如何做好并發(fā)訪問及數(shù)據(jù)更新問題。

什么場景需要控制并發(fā)訪問

需要控制并發(fā)訪問,說明這些并發(fā)的訪問可能會對其他的訪問造成影響。比如上面提到的庫存問題,若同一時期有多個客戶端訪問商品A的庫存數(shù)據(jù),并且可能要更更新庫存數(shù)據(jù),這時候就需要對并發(fā)訪問進(jìn)行控制了。

說到底,并發(fā)訪問需要控制的就是對數(shù)據(jù)的更新動作。 一般來說,客戶端要進(jìn)行數(shù)據(jù)更新時可分為2個步驟:

  • 客戶端讀取Redis數(shù)據(jù)到本地。
  • 確認(rèn)數(shù)據(jù)后,修改Redis的數(shù)據(jù)。

單個訪問來看,這個過程并沒什么問題。但是并發(fā)多了,一分為二的過程就會造成數(shù)據(jù)錯誤的問題。這里還是用庫存的例子來說:

  • 時間a::客戶端1讀取到庫存=10,我們需要對庫存+1=11的操作。
  • 時間b:客戶端2讀取到的庫存也是10,這次要對庫存-1=9的操作。
  • 時間c:客戶端1將+1后的值11寫回到Redis中。
  • 時間d:客戶端2將-1后的值9寫回到Redis中。

這樣下來,很明顯能發(fā)現(xiàn)庫存數(shù)據(jù)錯了。10+1-1 = 10,正確庫存是10,而上述場景最后為9。

由此可見,這個一分為二的操作不具有原子性,從而產(chǎn)生了錯誤的結(jié)果。類型這種場景很多,因此我們需要對這些并發(fā)訪問的場景加以控制。

并發(fā)訪問的控制方法

Redis并發(fā)訪問的控制,總的來說有2種方式。分別是加入鎖機(jī)制和讓一系列操作原子化。

1、加入鎖機(jī)制

首先第一點,加入鎖機(jī)制是很常見的解決方案。簡單來說就是一個客戶端訪問數(shù)據(jù)之前,先要獲取鎖,等數(shù)據(jù)操作完之后再解鎖。而在這個客戶端擁有鎖的過程中,其他客戶端如果也想訪問修改該數(shù)據(jù),必須得等鎖釋放了之后,獲取到了鎖才行。

加鎖這個方案是可以解決并發(fā)訪問的數(shù)據(jù)準(zhǔn)確問題,但放在redis這個場景中并不是很好。首先,Redis作為緩存本身并發(fā)訪問就很多,頻繁的加鎖解鎖,會大大降低redis的訪問性能;然后,Redis的客戶端在要加鎖時,需要用到分布式鎖。我們又得用額外的精力去維護(hù)這個分布式鎖。

2、操作原子化

操作原子化,也就是讓要執(zhí)行的一系列動作都保持原子性操作。它的優(yōu)點就是不需要加入額外的鎖機(jī)制。并發(fā)的數(shù)據(jù)準(zhǔn)確性達(dá)到了,對Redis的性能也不會有太大的影響。

Redis要實現(xiàn)原子操作,總結(jié)有2種方式:

  • 單命令操作:也就是Redis中的INCR、HINCRBY等命令,直接將簡單的加減操作合成一個命令執(zhí)行;
  • Lua腳本:借助Lua腳本,讓多個操作在Lua腳本上實現(xiàn)原子性操作。

1.單命令操作

首先,單命令操作,將數(shù)值的加減直接用Redis命令來執(zhí)行。像string的加減可用INCR、DECR操作,hash列表field的加減可用HINCRBY操作。

比如下面截圖,兩個客戶端在不同時刻讀取的linux_pids a值為4,各自+1、-1后a值為4。結(jié)果是正確的。

由此可見,用Redis的INCR、DECR等命令可以解決數(shù)值簡單增減的并發(fā)場景。但如果我們對數(shù)據(jù)的更新不僅僅是簡單的加減操作時,Redis的這些命令就無能為力了。此時我們可以考慮另一種方案:Lua腳本。

2.Lua腳本

Lua語言是由C寫的,因此支持多平臺和系統(tǒng)。從Redis2.6開始,Redis就內(nèi)置了Lua解釋器,我們能直接用Redis客戶端來執(zhí)行l(wèi)ua腳本。

我們可以將需要執(zhí)行的一系列操作用Lua腳本寫好,然后用Redis執(zhí)行它。Lua腳本的方法能保證原子性操作的原因是:Redis會將Lua腳本一次性執(zhí)行,也就是說執(zhí)行Lua腳本是0-1的操作,要么成功,要么失敗。可以理解成MySQL的事務(wù)特性。

Redis使用lua腳本有2種方式:

  • 客戶端中使用:用到script load腳本內(nèi)容、evalsha等命令
  • 執(zhí)行直接執(zhí)行l(wèi)ua腳本

我們一般用第二種方式來執(zhí)行。

客戶端使用方法:

先用script load加載腳本命令,再用evalsha執(zhí)行加載得到的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:          執(zhí)行l(wèi)ua腳本的命令
{lua_path}:         lua腳本的路徑
KEYS[1] KEYS[2]:       lua腳本中要操作的redis鍵,我們可以在lua腳本中用KEYS[1],KEYS[2],KEYS[3]指定多個
ARGV[1] ARGV[2]:    傳入到lua腳本的參數(shù),在腳本中用ARGV[1],ARGV[2]...來獲取。

Redis使用lua腳本的場景很多,最經(jīng)典的案例當(dāng)屬利用lua來控制某個IP的訪問頻率了。比如說需要防止惡意訪問網(wǎng)站的行為,我們規(guī)定1分鐘內(nèi)訪問次數(shù)不能超過30次,實現(xiàn)的方法有很多,比如說漏桶方案、令牌桶方案,但使用最多的還是Redis+lua的分布式限流方案。

我們用lua腳本(test_lua.script)來簡單實現(xiàn)一下上述功能,就是1分鐘內(nèi)若訪問次數(shù)超過30,直接攔截,否則訪問次數(shù)+1:

-- 限流的key
local limit_key = KEYS[1]
-- 限流次數(shù)
local limit_nums = 30
-- 當(dāng)前訪問次數(shù)
local current_num = tonumber(redis.call('get', limit_key) or 0)
-- 超出限流次數(shù)
if current_num + 1 > limit_num
    then
    return '超出訪問次數(shù)'
-- 沒有超出限流數(shù),訪問次數(shù)+1
else
  redis.call("INCRBY", limit_key, "1")
  -- 第一次訪問,設(shè)置過期時間
  if current_num == 0 then
    redis.call("expire", limit_key, "60")
  return current + 1
end

用Redis執(zhí)行,命令如下:

redis-cli --eval test_lua.script limit_key

小結(jié)

本文介紹了Redis并發(fā)訪問的控制問題,以及如何保證并發(fā)操作的原子化。原子化操作可通過單命令操作和Lua腳本的方式實現(xiàn)。我們在應(yīng)對相關(guān)問題時,可根據(jù)需要選擇對應(yīng)方案解決之。

到此這篇關(guān)于Redis并發(fā)訪問問題詳細(xì)講解的文章就介紹到這了,更多相關(guān)Redis并發(fā)訪問內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 聊聊使用RedisTemplat實現(xiàn)簡單的分布式鎖的問題

    聊聊使用RedisTemplat實現(xiàn)簡單的分布式鎖的問題

    這篇文章主要介紹了使用RedisTemplat實現(xiàn)簡單的分布式鎖問題,文中給大家介紹在SpringBootTest中編寫測試模塊的詳細(xì)代碼,需要的朋友可以參考下
    2021-11-11
  • Redis中Lua腳本的使用場景示例分析

    Redis中Lua腳本的使用場景示例分析

    通過使用Lua腳本,可以在Redis中實現(xiàn)復(fù)雜邏輯和原子操作,如原子計數(shù)、條件更新、事務(wù)性操作、分布式鎖、批量處理、計數(shù)器與過期管理、條件刪除、數(shù)據(jù)聚合等,本文介紹了Redis中Lua腳本的幾種常見使用場景及其Java實現(xiàn)示例,為開發(fā)者提供了一個參考
    2024-11-11
  • Redis的緩存更新策略及最佳實踐方案

    Redis的緩存更新策略及最佳實踐方案

    這篇文章主要介紹了Redis的緩存更新策略及最佳實踐方案,當(dāng)我們向redis插入太多數(shù)據(jù),此時就可能會導(dǎo)致緩存中的數(shù)據(jù)過多,所以redis會對部分?jǐn)?shù)據(jù)進(jìn)行更新,或者把它成為淘汰更合適,需要的朋友可以參考下
    2023-08-08
  • 淺談Redis分片集群搭建及其原理

    淺談Redis分片集群搭建及其原理

    本文主要介紹了Redis分片集群搭建及其原理,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • k8s部署redis哨兵的實現(xiàn)

    k8s部署redis哨兵的實現(xiàn)

    本文主要介紹了k8s部署redis哨兵的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Redis GEO地理信息定位功能

    Redis GEO地理信息定位功能

    Redis 提供了GEO地理信息定位功能,地理空間項(經(jīng)度、緯度、名稱),實現(xiàn)查找附近的人、上班打卡、自行車租賃、搖一搖等相關(guān)與地理位置信息的功能,這篇文章主要介紹了Redis GEO地理信息定位功能,需要的朋友可以參考下
    2023-12-12
  • Python的Flask框架使用Redis做數(shù)據(jù)緩存的配置方法

    Python的Flask框架使用Redis做數(shù)據(jù)緩存的配置方法

    Redis數(shù)據(jù)庫依賴于主存,在關(guān)系型數(shù)據(jù)庫以外再配套Redis管理緩存數(shù)據(jù)將對性能會有很大的提升,這里我們就來看一下Python的Flask框架使用Redis做數(shù)據(jù)緩存的配置方法
    2016-06-06
  • 高并發(fā)技巧之Redis和本地緩存使用技巧分享

    高并發(fā)技巧之Redis和本地緩存使用技巧分享

    在這篇文章中,我主要介紹的是分布式緩存和本地緩存的使用技巧,包括緩存種類介紹,各種的使用場景,以及如何使用,最后再給出實戰(zhàn)案例,需要的可以參考一下
    2022-10-10
  • Redis鎖完美解決高并發(fā)秒殺問題

    Redis鎖完美解決高并發(fā)秒殺問題

    本文主要介紹了Redis鎖完美解決高并發(fā)秒殺問題,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Redis主從復(fù)制詳解

    Redis主從復(fù)制詳解

    今天小編就為大家分享一篇關(guān)于Redis主從復(fù)制詳解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01

最新評論

政和县| 万安县| 胶南市| 新营市| 合肥市| 平和县| 衡阳县| 凌海市| 东乌| 平乡县| 门源| 肃南| 莱阳市| 万荣县| 元阳县| 宝山区| 治多县| 济南市| 河津市| 洞口县| 微博| 延安市| 双峰县| 横山县| 东明县| 岫岩| 雅安市| 兴海县| 德清县| 利津县| 安阳市| 比如县| 安国市| 介休市| 东宁县| 虎林市| 苍山县| 嵊州市| 松溪县| 睢宁县| 昌平区|