Redis?緩存淘汰策略和事務(wù)實(shí)現(xiàn)樂觀鎖詳情
緩存淘汰策略
標(biāo)題LRU原理
LRU(Least recently used,最近最少使用)算法根據(jù)數(shù)據(jù)的歷史訪問(wèn)記錄來(lái)進(jìn)行淘汰數(shù)據(jù),其核心思想是“如果數(shù)據(jù)最近被訪問(wèn)過(guò),那么將來(lái)被訪問(wèn)的幾率也更高”。
最常見的實(shí)現(xiàn)是使用一個(gè)鏈表保存緩存數(shù)據(jù),詳細(xì)算法實(shí)現(xiàn)如下:
- 新數(shù)據(jù)插入到鏈表頭部;
- 每當(dāng)緩存命中(即緩存數(shù)據(jù)被訪問(wèn)),則將數(shù)據(jù)移到鏈表頭部;
- 當(dāng)鏈表滿的時(shí)候,將鏈表尾部的數(shù)據(jù)丟棄。
在Java中可以使用LinkHashMap去實(shí)現(xiàn)LRU利用哈希鏈表實(shí)現(xiàn):
標(biāo)題Redis緩存淘汰策略
設(shè)置最大緩存
在 redis 中,允許用戶設(shè)置最大使用內(nèi)存大小maxmemory,默認(rèn)為0,沒有指定最大緩存,如果有新的數(shù)據(jù)添加,超過(guò)最大內(nèi)存,則會(huì)使redis崩潰,所以一定要設(shè)置。
redis 內(nèi)存數(shù)據(jù)集大小上升到一定大小的時(shí)候,就會(huì)實(shí)行數(shù)據(jù)淘汰策略。
淘汰策略
redis淘汰策略配置:maxmemory-policy voltile-lru,支持熱配置
redis 提供 6種數(shù)據(jù)淘汰策略:
- volatile-lru:從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選最近最少使用的數(shù)據(jù)淘汰
- volatile-ttl:從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選將要過(guò)期的數(shù)據(jù)淘汰
- volatile-random:從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中任意選擇數(shù)據(jù)淘汰
- allkeys-lru:從數(shù)據(jù)集(server.db[i].dict)中挑選最近最少使用的數(shù)據(jù)淘汰
- allkeys-random:從數(shù)據(jù)集(server.db[i].dict)中任意選擇數(shù)據(jù)淘汰
- no-enviction(驅(qū)逐):禁止驅(qū)逐數(shù)據(jù)
Redis事務(wù)
Redis事務(wù)介紹
- Redis 的事務(wù)是通過(guò) MULTI 、 EXEC 、 DISCARD 和 WATCH 、UNWATCH這五個(gè)命令來(lái)完成的。
- Redis 的單個(gè)命令都是原子性的,所以這里需要確保事務(wù)性的對(duì)象是命令集合。
- Redis 將命令集合序列化并確保處于同一事務(wù)的命令集合連續(xù)且不被打斷的執(zhí)行
- Redis 不支持回滾操作。 事務(wù)命令
MULTI
用于標(biāo)記事務(wù)塊的開始。 Redis會(huì)將后續(xù)的命令逐個(gè)放入隊(duì)列中,然后使用EXEC命令原子化地執(zhí)行這個(gè)命令序列。
語(yǔ)法:
multi
EXEC
在一個(gè)事務(wù)中執(zhí)行所有先前放入隊(duì)列的命令,然后恢復(fù)正常的連接狀態(tài)
語(yǔ)法:
exec
DISCARD
清除所有先前在一個(gè)事務(wù)中放入隊(duì)列的命令,然后恢復(fù)正常的連接狀態(tài)。
語(yǔ)法:
discard
WATCH
當(dāng)某個(gè)[事務(wù)需要按條件執(zhí)行]時(shí),就要使用這個(gè)命令將給定的[鍵設(shè)置為受監(jiān)控]的狀態(tài)。
語(yǔ)法:
watch key [key…]
注意事項(xiàng):使用該命令可以實(shí)現(xiàn) Redis 的樂觀鎖。
UNWATCH
清除所有先前為一個(gè)事務(wù)監(jiān)控的鍵
語(yǔ)法:
unwatch
命令圖解:
事務(wù)演示:
127.0.0.1:6379> multi OK 127.0.0.1:6379> set s1 111 QUEUED 127.0.0.1:6379> hset set1 name zhangsan QUEUED 127.0.0.1:6379> exec 1) OK 2) (integer) 1 127.0.0.1:6379> multi OK 127.0.0.1:6379> set s2 222 QUEUED 127.0.0.1:6379> hset set2 age 20 QUEUED 127.0.0.1:6379> discard OK 127.0.0.1:6379> exec (error) ERR EXEC without MULTI 127.0.0.1:6379> watch s1 OK 127.0.0.1:6379> multi OK 127.0.0.1:6379> set s1 555 QUEUED 127.0.0.1:6379> exec # 此時(shí)在沒有exec之前,通過(guò)另一個(gè)命令窗口對(duì)監(jiān)控的s1字段進(jìn)行修改 (nil) 127.0.0.1:6379> get s1 111
Redis 不支持事務(wù)回滾(為什么呢)
大多數(shù)事務(wù)失敗是因?yàn)檎Z(yǔ)法錯(cuò)誤或者類型錯(cuò)誤,這兩種錯(cuò)誤,在開發(fā)階段都是可以預(yù)見的Redis 為了性能方面就忽略了事務(wù)回滾。
Redis樂觀鎖
樂觀鎖基于CAS(Compare And Swap)思想(比較并替換),是不具有互斥性,不會(huì)產(chǎn)生鎖等待而消耗資源,但是需要反復(fù)的重試,但也是因?yàn)橹卦嚨臋C(jī)制,能比較快的響應(yīng)。因此我們可以利用redis來(lái)
實(shí)現(xiàn)樂觀鎖。具體思路如下:
- 利用redis的watch功能,監(jiān)控這個(gè)redisKey的狀態(tài)值
- 獲取redisKey的值
- 創(chuàng)建redis事務(wù)
- 給這個(gè)key的值+1
- 然后去執(zhí)行這個(gè)事務(wù),如果key的值被修改過(guò)則回滾,key不加1
public void watch() { try { String watchKeys = "watchKeys"; //初始值 value=1 jedis.set(watchKeys, 1); //監(jiān)聽key為watchKeys的值 jedis.watch(watchkeys); //開啟事務(wù) Transaction tx = jedis.multi(); //watchKeys自增加一 tx.incr(watchKeys); //執(zhí)行事務(wù),如果其他線程對(duì)watchKeys中的value進(jìn)行修改,則該事務(wù)將不會(huì)執(zhí)行 //通過(guò)redis事務(wù)以及watch命令實(shí)現(xiàn)樂觀鎖 List<Object> exec = tx.exec(); if (exec == null) { System.out.println("事務(wù)未執(zhí)行"); } else { System.out.println("事務(wù)成功執(zhí)行,watchKeys的value成功修改"); } } catch (Exception e) { e.printStackTrace(); } finally { jedis.close(); } }
Redis樂觀鎖實(shí)現(xiàn)秒殺
public class RedisLock { public static void main(String[] arg) { //庫(kù)存key String redisKey = "stock"; ExecutorService executorService = Executors.newFixedThreadPool(20); try { Jedis jedis = new RedisProperties.Jedis("127.0.0.1", 6378); // 可以被秒殺的庫(kù)存的初始值,庫(kù)存總共20個(gè) jedis.set(redisKey, "0"); jedis.close(); } catch (Exception e) { e.printStackTrace(); } for (int i = 0; i < 1000; i++) { executorService.execute(() -> { Jedis jedis1 = new Jedis("127.0.0.1", 6378); try { jedis1.watch(redisKey); String redisValue = jedis1.get(redisKey); int valInteger = Integer.valueOf(redisValue); String userInfo = UUID.randomUUID().toString(); // 沒有秒完 if (valInteger < 20) { Transaction tx = jedis1.multi(); tx.incr(redisKey); List list = tx.exec(); // 秒成功 失敗返回空l(shuí)ist而不是空 if (list != null && list.size() > 0) { System.out.println("用戶:" + userInfo + ",秒殺成 功!當(dāng)前成功人數(shù):" + (valInteger + 1)); } // 版本變化,被別人搶了。 else { System.out.println("用戶:" + userInfo + ",秒殺失 敗"); } } // 秒完了 else { System.out.println("已經(jīng)有20人秒殺成功,秒殺結(jié)束"); } } catch (Exception e) { e.printStackTrace(); } finally { jedis1.close(); } }); } executorService.shutdown(); } }
到此這篇關(guān)于Redis 緩存淘汰策略和事務(wù)實(shí)現(xiàn)樂觀鎖詳情的文章就介紹到這了,更多相關(guān)Redis 緩存淘汰策略內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深入理解Redis7哨兵模式(保姆級(jí)教學(xué))
Redis的主從復(fù)制存在一定的缺陷,為了解決這一問(wèn)題,Redis官方推薦一種高可用方案哨兵模式,本文主要介紹了深入理解Redis7哨兵模式,具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01odoo中使用redis實(shí)現(xiàn)緩存的步驟
這篇文章主要介紹了odoo中使用redis實(shí)現(xiàn)緩存的步驟,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04使用攔截器+Redis實(shí)現(xiàn)接口冪思路詳解
這篇文章主要介紹了使用攔截器+Redis實(shí)現(xiàn)接口冪等,接口冪等有很多種實(shí)現(xiàn)方式,攔截器/AOP+Redis,攔截器/AOP+本地緩存等等,本文講解一下通過(guò)攔截器+Redis實(shí)現(xiàn)冪等的方式,需要的朋友可以參考下2023-08-08Redis+Caffeine實(shí)現(xiàn)多級(jí)緩存的步驟
隨著不斷的發(fā)展,這一架構(gòu)也產(chǎn)生了改進(jìn),在一些場(chǎng)景下可能單純使用Redis類的遠(yuǎn)程緩存已經(jīng)不夠了,還需要進(jìn)一步配合本地緩存使用,例如Guava cache或Caffeine,從而再次提升程序的響應(yīng)速度與服務(wù)性能,這篇文章主要介紹了Redis+Caffeine實(shí)現(xiàn)多級(jí)緩存,需要的朋友可以參考下2024-01-01在Redis中如何保存時(shí)間序列數(shù)據(jù)詳解
與發(fā)生時(shí)間相關(guān)的一組數(shù)據(jù),就是時(shí)間序列數(shù)據(jù),這些數(shù)據(jù)的特點(diǎn)是沒有嚴(yán)格的關(guān)系模型,記錄的信息可以表示成鍵和值的關(guān)系,這篇文章主要給大家介紹了關(guān)于在Redis中如何保存時(shí)間序列數(shù)據(jù)的相關(guān)資料,需要的朋友可以參考下2021-10-10面試分析分布式架構(gòu)Redis熱點(diǎn)key大Value解決方案
這篇文章主要為大家介紹了分布式架構(gòu)Redis熱點(diǎn)key大Value解決方案,以及在面試中如果遇到這類問(wèn)題的分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-03-03gem install redis報(bào)錯(cuò)的解決方案
今天小編就為大家分享一篇關(guān)于gem install redis報(bào)錯(cuò)的解決方案,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-01-01