激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|數據庫技術|

服務器之家 - 數據庫 - Redis - Redis 如何為 List/Set/Hash 的元素設置單獨的過期時間

Redis 如何為 List/Set/Hash 的元素設置單獨的過期時間

2023-12-16 05:00未知服務器之家 Redis

大家好,我是小?,一個漂泊江湖多年的 985 非科班程序員,曾混跡于國企、互聯網大廠和創業公司的后臺開發攻城獅。 1. 引言 1.1 消費隊列 這天,小?在購買火車票時,發現如果存在一個未支付的訂單時,就不能再進行購票了。

大家好,我是小?,一個漂泊江湖多年的 985 非科班程序員,曾混跡于國企、互聯網大廠和創業公司的后臺開發攻城獅。

1. 引言

1.1 消費隊列

這天,小?在購買火車票時,發現如果存在一個未支付的訂單時,就不能再進行購票了。如果把待支付的訂單放在一個隊列里面,那么隊列的長度就只能是 1.

正好最近用 Redis 比較多,于是,我突發奇想,如何用 Redis 原生的數據結構實現一個簡易版的延時消費隊列呢?

業務狀態圖如下:

Redis 如何為 List/Set/Hash 的元素設置單獨的過期時間圖片

并且,需要保證隊列的長度是可控的,比如,我們只允許用戶有 3 個未支付的訂單。

1.2 Redis實現

Redis,作為一款高性能的緩存和數據存儲數據庫,一直以來都是后臺開發者的得力助手。

如果用 Redis 作為消費隊列,那么我們可以用到的數據結構有:List、Hash 和 Set。在上述的業務場景中,由于我們只需要關注 orderId(訂單 ID),因此這三個數據結構都是可用的。

比如,用 hash 來存儲時,我們可以將 key 設置為 UnpaidOrder-{userId},每個 field 都是一個訂單。

Redis 如何為 List/Set/Hash 的元素設置單獨的過期時間圖片

但是,我們現在面臨一個挑戰:每個訂單的存活時長是不同的,分為手動消費和定期刪除的邏輯。

  • 訂單 1 手動支付后,需要將 orderId1 從列表中刪除
  • 訂單 2 在半小時內還未支付,就自動過期,用戶還可以繼續提交訂單到未支付狀態

所以在 List、Set 或者 Hash 結構中,每個 field 都需要設置單獨的過期時間。

這是一個常見而又棘手的問題,本文將從互聯網業務中常見的解決方案入手,來深入探討一下 Redis 的底層實現。

2. 常見方案

在實際業務中,我們經常會遇到這樣的場景:需要統計某些字段的個數,并且這些字段的過期時間各有先后。

就上述場景而言,我們需要統計用戶的未支付訂單數,但是每個訂單數的過期時間是不同的。

在這種情況下,我們需要在業務中手動刪除過期的字段,或者讓它們自動過期。

2.1 為單獨的 field 設置過期?

我們知道,Redis 里面暫時沒有接口給 List、Set 或者 Hash 的 field 單獨設置過期時間,只能給整個列表、集合或者 Hash 設置過期時間。

這樣,當 List/Set/Hash 過期時,里面的所有 field 元素就全部過期了。

但這樣并不滿足需求。

小?嘗試在網上找一些已知方案,其中有一個 Stack Overflow 的問題帖子和我面臨的很相似:

Redis 如何為 List/Set/Hash 的元素設置單獨的過期時間

圖來源:StackOverflow,Redis 中如何給 HSET 的孩子key(指 field)設置過期時間?

接著,帖子下面的回答里無意看到了 Redis 作者的回答:

Redis 如何為 List/Set/Hash 的元素設置單獨的過期時間圖片

中文翻譯如下:

嗨,這是不可能的,要么為該特定字段使用不同的頂級 key,要么與提交的字段一起存儲另一個具有過期時間的字段,然后同時獲取這兩個字段,并讓應用程序了解它是否仍然有效(基于當前時間)。

大意就是,不可能,除非你同時把 field 和過期時間都存下來,然后在程序里面判斷它是否過期。

這真是布袋里失火,很燒包!

2.2. 設置整體過期時間

既然 Redis 創始人都這么說了,Redis 是不可能為單獨的 field 設置過期時間,那我們首先考慮的就是給整個 List/Set/Hash 設置過期時間。

這樣的做法簡單粗暴,但卻很難滿足每個字段單獨設置過期時間的需求。

于是,我思前想后,既然每個訂單的過期時間不一樣,那我們是否可以根據時間來創建不同的集合,將同一時間過期的訂單放在同一個集合里面:

Redis 如何為 List/Set/Hash 的元素設置單獨的過期時間圖片

然后,分別為不同的集合設置 TTL,當訂單過期未支付時,訂單會隨著集合的過期而在同一分鐘內被刪除。

但是這樣的問題是,每次新增訂單時,都得把過去 30 分鐘的集合全部遍歷一遍,查詢是否有該用戶的訂單,再判斷用戶的未支付訂單數有沒有超量。

并且,以分鐘創建集合,可能存在一個問題:用戶的訂單本來在 01 秒就過期了,但是在 59 秒才被刪除。

如果以秒來創建集合,30 分鐘又需要創建 1800 個集合,就更難管理了,所以對集合設置整體過期時間不太可行。

那有沒有更優雅的實現方式呢?

2.3 zset 結合 score實現

當然是有的!

Redis 除了常用的 List/Set/Hash 結構,它還有一個專門用來排序的數據結構 zset(即 Sorted Set,排序集合)。

而基于 Redis 的 Zset 結構,可以通過 Score 來表示過期時間,我們可以輕松地實現每個 Field 的單獨過期。

Redis 如何為 List/Set/Hash 的元素設置單獨的過期時間圖片

具體實現為:

  1. 每當新增一個待支付訂單,就將當前時間的 Unix timestamp 加上過期時間 30min 作為 score 設置到這個元素上,這樣,sorted set 會根據這個過期時間戳對元素排序存儲;
  2. 當訂單被支付后,根據 userId 和 orderId 去刪除 sorted set 里的待支付訂單;
  3. 同時,在程序里新增一個定時任務,每隔一秒去刪除當前時間已過期的訂單。

2.4 底層實現

用 Redis 的 zset 一方面可以很方便地實現了對每個字段的單獨過期,不再受整個 Key 的過期時間限制,提高了靈活性。

另一方面,Redis 的 zset 操作是十分高效的,不會給系統帶來顯著的性能壓力。

這得益于 zset 底層的數據結構,Zset 底層實現采用了 ZipList(壓縮列表)和 SkipList(跳表)兩種實現方式,當滿足:

  • Zset 中保存的元素個數小于 128(可通過修改 zset-max-ziplist-entries 配置來修改)
  • Zset 中保存的所有元素長度小于 64byte(通過修改 zset-max-ziplist-values 配置來修改)

兩個條件時,Zset 采用 ZipList 實現;否則,用 SkipList 實現。

ZipList 實現

Redis 如何為 List/Set/Hash 的元素設置單獨的過期時間圖片

ZipList 是一個數組的形式,存儲數據時分為列表頭部分和數據部分,列表頭部分有 3 個元素:

  • zlbytes:表示當前 list 的存儲元素的總長度
  • zllen:表示當前 list 存儲的元素的個數
  • zltail:表示當前 list 的頭結點的地址,通過 zltail 就是可以實現 list 的遍歷

數據部分以鍵值對的方式依次排列,鍵存儲的是實際 member,值存儲的是 member 對應的分值(score)。

SkipList 實現

Redis 如何為 List/Set/Hash 的元素設置單獨的過期時間圖片

SkipList 分為兩部分:

  1. dict 部分是由字典實現(其實就是 HashMap,里面放了成員到 score 的映射);
  2. zset 部分使用跳躍表實現(存放了所有的成員,解決了 HashMap 中 key 無序的問題)。

從圖中可以看出,dict 和 zset 都存儲數據。

但實際上 dict 和 zset 最終使用的指針都指向了同一份成員數據,即數據是被兩部分共享的,為了方便表達將同一份數據展示在兩個地方。

2.5 代碼實現

當我們插入一個過期時間到 zset 時,Redis 會自動幫我們排好序,我們只需要在程序中新增一個定時任務,比如:每秒執行一次刪除任務,刪除時間戳從 0 到當前時間戳的 score 值即可。

偽代碼如下:

# 1. 創建新的待支付訂單時,查詢zset個數
count = zcard UnpaidOrder-{userId}

# 2. 判斷未支付訂單個數
if count >= 3:
    return

# 3. 新增訂單
zadd UnpaidOrder-{userId} redis.Z{Score: {timestamp1}, Member: {order1}}

# 4.1 訂單支付后,從 set 中刪除未支付訂單
zrem UnpaidOrder-{userId} order1

# 4.2 過期時間到了,從 set 中刪除未支付訂單
zremrange UnpaidOrder-{userId} 0 {current_timestamp}

3. 結語

通過合理的數據結構選擇和巧妙的應用,我們成功地解決了為 List、Set 和 Hash 結構中的字段設置單獨過期時間的問題。

這個方案在實際項目中得到了驗證,并取得了顯著的效果。對比其它的延時隊列,或者 etcd 的 field 過期方案,Redis 的實現相對而言更為便捷,理解起來也更為簡單。

希望這個方案能夠在你的項目中派上用場,提高開發效率,更好地應對實際需求。如果你有更多關于 Redis 使用的問題,也歡迎在評論區交流討論。

愿你在 Redis 的世界里愈發游刃有余,取得更多技術的新突破。

延伸 · 閱讀

精彩推薦
  • Redisredis 交集、并集、差集的具體使用

    redis 交集、并集、差集的具體使用

    這篇文章主要介紹了redis 交集、并集、差集的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友...

    xiaojin21cen10152021-07-27
  • RedisRedis全量復制與部分復制示例詳解

    Redis全量復制與部分復制示例詳解

    這篇文章主要給大家介紹了關于Redis全量復制與部分復制的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Redis爬蟲具有一定的參考學習...

    豆子先生5052019-11-27
  • Redis詳解Redis復制原理

    詳解Redis復制原理

    與大多數db一樣,Redis也提供了復制機制,以滿足故障恢復和負載均衡等需求。復制也是Redis高可用的基礎,哨兵和集群都是建立在復制基礎上實現高可用的...

    李留廣10222021-08-09
  • RedisRedis 事務知識點相關總結

    Redis 事務知識點相關總結

    這篇文章主要介紹了Redis 事務相關總結,幫助大家更好的理解和學習使用Redis,感興趣的朋友可以了解下...

    AsiaYe8232021-07-28
  • RedisRedis的配置、啟動、操作和關閉方法

    Redis的配置、啟動、操作和關閉方法

    今天小編就為大家分享一篇Redis的配置、啟動、操作和關閉方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧 ...

    大道化簡5312019-11-14
  • Redisredis中如何使用lua腳本讓你的靈活性提高5個逼格詳解

    redis中如何使用lua腳本讓你的靈活性提高5個逼格詳解

    這篇文章主要給大家介紹了關于redis中如何使用lua腳本讓你的靈活性提高5個逼格的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具...

    一線碼農5812019-11-18
  • RedisRedis如何實現數據庫讀寫分離詳解

    Redis如何實現數據庫讀寫分離詳解

    Redis的主從架構,能幫助我們實現讀多,寫少的情況,下面這篇文章主要給大家介紹了關于Redis如何實現數據庫讀寫分離的相關資料,文中通過示例代碼介紹...

    羅兵漂流記6092019-11-11
  • Redisredis實現排行榜功能

    redis實現排行榜功能

    排行榜在很多地方都能使用到,redis的zset可以很方便地用來實現排行榜功能,本文就來簡單的介紹一下如何使用,具有一定的參考價值,感興趣的小伙伴們...

    乘月歸5022021-08-05
主站蜘蛛池模板: 成人在线视频播放 | 精品一区久久久 | av电影在线观看网址 | 国产亚洲黑人性受xxxx精品 | 看毛片电影 | 一级影片在线观看 | av在线一区二区三区 | 久久久久久三区 | 久久久久久久久久久高潮一区二区 | h视频在线免费看 | 91情侣在线偷精品国产 | 免费在线观看中文字幕 | 久久国产夫妻视频 | 久久影院在线观看 | 人人舔人人射 | 九九热在线免费观看视频 | 国产精品久久久久久久久岛 | www.99av| 鲁丝片一区二区三区免费入口 | 日韩精品a在线观看 | 午夜影视一区二区 | 久久99久久99精品 | 欧美a视频| 国产成人午夜精品 | 国内精品久久久久久久久久 | 电影一级毛片 | 久久精精| 国产91一区二区三区 | 欧美成人精品欧美一级 | 色av成人天堂桃色av | 免费一级在线 | 91高清免费 | 国产午夜精品久久久久 | 国产成人强伦免费视频网站 | 国产精品夜色视频一级区 | 99精品视频在线观看免费播放 | 一级片999 | 在线中文字幕播放 | 日本道中文字幕 | 久久久久亚洲精品 | 性少妇videosexfreexxx片 |