網站首頁 編程語言 正文
業務場景
我們以訂單功能為例說明下:
生成訂單后一段時間不支付訂單會自動關閉。最簡單的想法是設置定時任務輪詢,但是每個訂單的創建時間不一樣,定時任務的規則無法設定,如果將定時任務執行的間隔設置的過短,太影響效率。
還有一種想法,在用戶進入訂單界面的時候,判斷時間執行相關操作。方式可能有很多,在這里介紹一種監聽 Redis 鍵值對過期時間來實現訂單自動關閉。
實現思路
在生成訂單時,向 Redis 中增加一個 KV 鍵值對,K 為訂單號,保證通過 K 能定位到數據庫中的某個訂單即可,V 可為任意值。
假設,生成訂單時向 Redis 中存放 K 為訂單號,V 也為訂單號的鍵值對,并設置過期時間為 30 分鐘,如果該鍵值對在 30 分鐘過期后能夠發送給程序一個通知,或者執行一個方法,那么即可解決訂單關閉問題。
實現:通過監聽 Redis 提供的過期隊列來實現,監聽過期隊列后,如果 Redis 中某一個 KV 鍵值對過期了,那么將向監聽者發送消息,監聽者可以獲取到該鍵值對的 K,注意,是獲取不到 V 的,因為已經過期了,這就是上面所提到的,為什么要保證能通過 K 來定位到訂單,而 V 為任意值即可。拿到 K 后,通過 K 定位訂單,并判斷其狀態,如果是未支付,更新為關閉,或者取消狀態即可。
開啟 Redis key 過期提醒
修改 redis 相關事件配置。找到 redis 配置文件 redis.conf,查看 notify-keyspace-events 配置項,如果沒有,添加 notify-keyspace-events Ex,如果有值,則追加 Ex,相關參數說明如下:
- K:keyspace 事件,事件以 keyspace@ 為前綴進行發布
- E:keyevent 事件,事件以 keyevent@ 為前綴進行發布
- g:一般性的,非特定類型的命令,比如del,expire,rename等
- $:字符串特定命令
- l:列表特定命令
- s:集合特定命令
- h:哈希特定命令
- z:有序集合特定命令
- x:過期事件,當某個鍵過期并刪除時會產生該事件
- e:驅逐事件,當某個鍵因 maxmemore 策略而被刪除時,產生該事件
- A:g$lshzxe的別名,因此”AKE”意味著所有事件
引入依賴
在 pom.xml 中添加 org.springframework.boot:spring-boot-starter-data-redis 依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
相關配置
定義配置 RedisListenerConfig 實現監聽 Redis key 過期時間
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
@Configuration
public class RedisListenerConfig {
? ? @Bean
? ? RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
? ? ? ? RedisMessageListenerContainer container = new RedisMessageListenerContainer();
? ? ? ? container.setConnectionFactory(connectionFactory);
? ? ? ? return container;
? ? }
}
定義監聽器 RedisKeyExpirationListener,實現KeyExpirationEventMessageListener 接口,查看源碼發現,該接口監聽所有 db 的過期事件 keyevent@*:expired"
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;
/**
?* 監聽所有db的過期事件__keyevent@*__:expired"
?*/
@Component
public class RedisKeyExpirationListener extends KeyExpirationEventMessageListener {
? ? public RedisKeyExpirationListener(RedisMessageListenerContainer listenerContainer) {
? ? ? ? super(listenerContainer);
? ? }
? ? /**
? ? ?* 針對 redis 數據失效事件,進行數據處理
? ? ?* @param message
? ? ?* @param pattern
? ? ?*/
? ? @Override
? ? public void onMessage(Message message, byte[] pattern) {
? ? ? ? // 獲取到失效的 key,進行取消訂單業務處理
? ? ? ? String expiredKey = message.toString();
? ? ? ? System.out.println(expiredKey);
? ? }
}
redis 過期監聽真的好么?
在 Redis 官方手冊的keyspace-notifications: timing-of-expired-events中明確指出:
Basically expired events are generated when the Redis server deletes the key and not when the time to live theoretically reaches the value of zero
redis 自動過期的實現方式是:定時任務離線掃描并刪除部分過期鍵;在訪問鍵時惰性檢查是否過期并刪除過期鍵。redis 從未保證會在設定的過期時間立即刪除并發送過期通知。實際上,過期通知晚于設定的過期時間數分鐘的情況也比較常見。
此外鍵空間通知采用的是發送即忘(fire and forget)策略,并不像消息隊列一樣保證送達。當訂閱事件的客戶端會丟失所有在斷線期間所有分發給它的事件。
這是一種比定時掃描數據庫更 “LOW” 的解決方案,不建議使用。
實現關閉訂單的方法
一般實現的方法有幾種:
- 使用 rocketmq、rabbitmq、pulsar 等消息隊列的延時投遞功能
- 使用 redisson 提供的 DelayedQueue
有一些方案雖然廣為流傳但存在著致命缺陷,不要用來實現延時任務
- 使用 redis 的過期監聽
- 使用 rabbitmq 的死信隊列
- 使用非持久化的時間輪
原文鏈接:https://blog.csdn.net/weixin_46237429/article/details/125477984
相關推薦
- 2022-04-26 python?logging多進程多線程輸出到同一個日志文件的實戰案例_python
- 2022-12-03 Nginx部署SSL證書的過程_nginx
- 2023-05-18 Kotlin?Extension?Function擴展函數詳細介紹_Android
- 2021-12-04 Go?實現?Nginx?加權輪詢算法的方法步驟_Golang
- 2022-04-15 使用python測試prometheus的實現_python
- 2022-09-22 模擬實現vector
- 2022-03-31 jenkins?實現shell腳本化定時執行任務的方法_linux shell
- 2022-09-29 C#/VB.NET中從?PDF?文檔中提取所有表格_C#教程
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支