Redis 原子保種的實(shí)現(xiàn)示例
功能一句話概括:
“確保 Redis 里存在該 key,且其 TTL ≥ 60 s,否則用 setnx 寫入初始 seed 并把過期時(shí)間設(shè)為 5 min。”
據(jù)此可取名:ensure_seed_with_ttl
下面給出完整封裝(含類型提示、日志英文、異常兜底),并給出兩處可優(yōu)化點(diǎn)及優(yōu)化后的代碼。
一、原始邏輯直接封裝
import datetime
import logging
from typing import Optional
log = logging.getLogger(__name__)
def ensure_seed_with_ttl(
rediz,
redis_key: str,
item_type,
msg: Optional[str] = None,
) -> None:
"""
Ensure the Redis key exists and has a TTL of at least 60 s.
If the key does not exist, atomically set it to the initial seed
and give it a 5-minute expiration.
"""
if not rediz.exists(redis_key):
seed = ensure_seed_reference(item_type)
result = rediz.setnx(redis_key, seed.ref_seq)
log.info(
"Seed ensured in Redis: result=%s, next_seq=%s, msg=%s",
result, seed.ref_seq, msg
)
ttl = rediz.ttl(redis_key)
if ttl < 60 or ttl == -1: # -1 表示 key 存在但沒有過期時(shí)間
rediz.expire(redis_key, datetime.timedelta(minutes=5))二、可優(yōu)化的兩點(diǎn)
競(jìng)爭(zhēng)窗口
兩個(gè)客戶端可能同時(shí)通過exists判斷為 False,然后都執(zhí)行setnx,雖然setnx本身是原子性的,但日志會(huì)打印兩次“Seed ensured …”,容易誤導(dǎo)。
優(yōu)化:把“判存在 + 設(shè)值 + 設(shè)過期”做成一條原子事務(wù)(Lua 腳本或 Redis pipeline)。減少一次 TTL 查詢
如果setnx成功,我們可以直接把過期時(shí)間設(shè)為 5 min,省去一次ttl查詢;
只有setnx失?。╧ey 已存在)時(shí)才需要ttl檢查。
三、優(yōu)化后代碼(Lua 腳本一次原子執(zhí)行)
import datetime
import logging
from typing import Optional
log = logging.getLogger(__name__)
# Lua 腳本:如果 key 不存在,則 set value 并設(shè)置 5 min 過期;
# 如果 key 已存在但 ttl<60,則延長到 5 min;
# 返回 1 表示寫入了新 seed,返回 0 表示僅調(diào)整過期時(shí)間。
_ENSURE_SEED_LUA = """
local key, value, min_ttl, full_ttl = KEYS[1], ARGV[1], tonumber(ARGV[2]), tonumber(ARGV[3])
local exists = redis.call('exists', key)
if exists == 0 then
redis.call('setnx', key, value)
redis.call('expire', key, full_ttl)
return 1
else
local ttl = redis.call('ttl', key)
if ttl < min_ttl then
redis.call('expire', key, full_ttl)
end
return 0
end
"""
def ensure_seed_with_ttl(
rediz,
redis_key: str,
item_type,
msg: Optional[str] = None,
) -> None:
"""
Atomically ensure the Redis key exists and has a TTL of at least 60 s.
If the key does not exist, atomically set it to the initial seed
and give it a 5-minute expiration.
"""
seed = ensure_seed_reference(item_type)
written = rediz.eval(
_ENSURE_SEED_LUA,
1, # number of keys
redis_key,
seed.ref_seq, # ARGV[1]
60, # ARGV[2] min_ttl
int(datetime.timedelta(minutes=5).total_seconds()) # ARGV[3] full_ttl
)
if written == 1:
log.info(
"Seed ensured in Redis: next_seq=%s, msg=%s",
seed.ref_seq, msg
)優(yōu)化效果
- 競(jìng)爭(zhēng)窗口消失,全程原子;
- 減少一次
ttl網(wǎng)絡(luò)往返(在 key 不存在場(chǎng)景); - 日志只在真正寫入 seed 時(shí)打印一次,避免重復(fù)誤導(dǎo)。
到此這篇關(guān)于Redis 原子保種的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)Redis 原子保種內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一文解決Redis后臺(tái)持久化失敗的問題:內(nèi)存不足導(dǎo)致fork失敗
Redis作為一個(gè)內(nèi)存數(shù)據(jù)庫,在執(zhí)行后臺(tái)持久化(例如 BGSAVE 命令時(shí))需要fork一個(gè)子進(jìn)程來生成數(shù)據(jù)庫快照(RDB 文件),在生產(chǎn)環(huán)境中,有時(shí)你可能會(huì)在Redis日志中遇到持久化失敗的問題,本文將詳細(xì)介紹該問題的原因以及如何通過調(diào)整內(nèi)核和Redis配置來解決此問題2025-07-07
Linux服務(wù)器快速安裝Redis6.0步驟示例詳解
這篇文章主要為大家介紹了Linux服務(wù)器快速安裝Redis6.0步驟示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
Unable?to?connect?to?Redis無法連接到Redis解決的全過程
這篇文章主要給大家介紹了關(guān)于Unable?to?connect?to?Redis無法連接到Redis解決的相關(guān)資料,文中通過圖文以及實(shí)例代碼將解決的過程介紹的非常詳細(xì),需要的朋友可以參考下2023-03-03
Redis不同數(shù)據(jù)類型使用場(chǎng)景代碼實(shí)例
這篇文章主要介紹了Redis不同數(shù)據(jù)類型使用場(chǎng)景代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-12-12
Redis緩存數(shù)據(jù)庫表(列單獨(dú)緩存)的示例代碼
在Redis中緩存數(shù)據(jù)庫表數(shù)據(jù),而不使用JSON結(jié)構(gòu)來表示value,通常意味著我們會(huì)將數(shù)據(jù)庫表的每一行數(shù)據(jù)映射為Redis中的一個(gè)或多個(gè)鍵值對(duì),這篇文章主要介紹了Redis緩存數(shù)據(jù)庫表(列單獨(dú)緩存),需要的朋友可以參考下2024-03-03
Redis7.2.x主從復(fù)制的實(shí)現(xiàn)示例
本文主要介紹了Redis7.2.x主從復(fù)制的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-06-06
Redis數(shù)據(jù)遷移RedisShake的實(shí)現(xiàn)方法
本文主要介紹了Redis數(shù)據(jù)遷移RedisShake的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
淺談Redis如何應(yīng)對(duì)并發(fā)訪問
本文主要介紹了Redis如何應(yīng)對(duì)并發(fā)訪問,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08
Redis中Bloom filter布隆過濾器的學(xué)習(xí)
布隆過濾器是一個(gè)非常長的二進(jìn)制向量和一系列隨機(jī)哈希函數(shù)的組合,可用于檢索一個(gè)元素是否存在,本文就詳細(xì)的介紹一下Bloom filter布隆過濾器,具有一定的參考價(jià)值,感興趣的可以了解一下2022-12-12

