大神教你實現redis鍵空間通知
導讀 | 最近在開發一個定時活動,而且活動是多個場次的。這個是後就需要在活動開始的時候推送資訊給客戶端,結束的時候也要推送一次。簡單的設計方案就是將配置快取在redis,然後每隔一秒就輪詢reids,獲取配置資訊,然後判斷是不是到活動開始或者結束的時間點,然後推送給客戶端。 |
但是,這裡會有一個問題,如果沒有到活動開始或結束的時間點,這裡會造成很多無用的輪詢操作。這個操作不但增大了對這個key的訪問量,同時也會佔用cu,降低機器效能。
redis在2.8.0版本提供了一個鍵空間通知功能機制,對於這個功能的詳細描述,可以查閱官方文件。簡單總結就是,客戶端可以訂閱一個key,當這個可以發生改變時,redis會通知到已經訂閱的客戶端。
這個實現也很簡單,我們可以透過一個demo來看看如何使用這個機制。
package main import ( "context" "fmt" "github.com/go-redis/redis/v8" "time" ) var redisCli *redis.Client func init() { // 連線redis redisCli = redis.NewClient(&redis.Options{ Addr: "127.0.0.1:6379", Password: "redis123", }) } /* * redis key 過期自動通知 */ func SetExpireEvent() { // 設定一個鍵,並且3秒鐘之後過期 redisCli.Set(context.Background(), "test_expire_event_notify", "測試鍵值過期通知", 3*time.Second) } func SubExpireEvent() { // 訂閱key過期事件 sub := redisCli2.Subscribe(context.Background(), "__keyevent@0__:expired") // 這裡透過一個for迴圈監聽redis-server發來的訊息。 // 當客戶端接收到redis-server傳送的事件通知時, // 客戶端會透過一個channel告知我們。我們再根據 // msg的channel欄位來判斷是不是我們期望收到的訊息, // 然後再進行業務處理。 for { msg := <-sub.Channel() fmt.Println("Channel ", msg.Channel) fmt.Println("pattern ", msg.Pattern) fmt.Println("pattern ", msg.Payload) fmt.Println("PayloadSlice ", msg.PayloadSlice) } } func main() { SetExpireEvent() go SubExpireEvent() // 這裡sleep是為了防止main方法直接推出 time.Sleep(10 * time.Second) }
程式碼結果輸出如下:
上面程式碼實現邏輯很簡單,核心邏輯就是訂閱__keyevent@0__:expired這個事件,然後一個迴圈等待事件的通知。值得注意的是,要啟用這個特性需要修改配置檔案,啟用notify-keyspace-events這個配置,可以參考配置檔案中的註釋對不同事件進行啟用。
回到開始提及的業務場景,如何在這種場景中使用redis的機制呢?其實很簡單,當活動配置到資料庫之後,會有一個更新快取的步驟。在將資料設定在活動快取時,只要我們計算當前時間到活動開始/結束這個時間差,將這個差作為鍵的過期時間。
例如,活動id1的開始時間為t0, 結束時間為t2, 當前時間為t。這個時候就可以這麼設定:
// 活動開始的key設定 redisCli.Set(context.Background(), "id1:start", "活動開始了", t0 - t) // 活動結束結束的key設定 redisCli.Set(context.Background(), "id1:start", "活動開始了", t1 - t)
透過這麼設定,當活動開啟/結束就可以接收到相應的通知了。
這種方案其實可以完全滿足文中的需求場景,但是這種方案其實也存在一些問題。其實這些問題在redis文件中也有相應說明。
第一,redis-server在推送這個事件通知時,只要訂閱了這個事件的客戶端端都會收到這個訊息。通常,我們的業務都是跑在多個結點中,所以這個時候就要根據場景看要不要進行業務的原子操作。
第二,redis-server只會推送一次這個通知。假如說在redis-server推送這個通知時,結點掛了或者由於其他異常情況沒有收到訊息,redis-server不會再重新推送。
第三,通知可能會延遲。由於redis實現機制,對於過期的鍵,會有兩種機制進行處理,一種是當 訪問鍵時,發現鍵已過期。另一種是透過後臺系統在後臺逐步查詢過期的鍵,以便能夠收集那些從未被訪問的鍵。所以會有出現延遲的可能。
本文介紹了使用redis的鍵空間通知機制來實現了一種業務場景,當然這種方式並不是最好的,還有其他方式來實現。在實際開發中會有很多的因素要考慮,而且實現方式也是多種多樣,這個就需要我們分析每一種方案的利弊,然後進行抉擇。
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2792316/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Redis鍵空間通知Redis
- Redis實踐操作之——keyspacenotification(鍵空間通知)Redis
- Oracle RMAN實現“一鍵式”表空間TSPITROracle
- 解決Redis叢集條件下鍵空間通知伺服器接收不到訊息的問題Redis伺服器
- 開啟 Redis 就出現這個錯誤 Redis 正常執行 配置項沒問題 磁碟空間足 哪位大神遇到過?Redis
- Laravel5.6使用redis佇列實現系統通知LaravelRedis佇列
- [實戰]laravel + redis訂閱釋出 +swoole實現實時訂單通知LaravelRedis
- liunx使用者空間和核心空間之間的通訊實現(在PPC下的實現)(轉)
- 大神教你如何優化變壓器匝間電容?優化
- 大神教你如何判斷Python中字串是否為空和nullPython字串Null
- 大神教你用Python實現Wake On Lan遠端開機功能Python
- 大神教你C++寫時複製實現原理及例項解析C++
- MySQL空間函式實現位置打卡MySql函式
- redis入門指南(四)—— redis如何節省空間Redis
- Redis 資料庫、鍵過期的實現Redis資料庫
- 建站老司機教你如何選擇海外空間
- js 實現鏈式呼叫名稱空間JS
- redis+lua實現指令碼一鍵查詢Redis指令碼
- 教你整合Nearby Service實現一鍵Wi-Fi分享功能
- 教你JavaScript實現一鍵複製內容剪貼簿JavaScript
- DIY 實現 ThinkPHP 核心框架(四)名稱空間PHP框架
- 一個RecyclerView實現QQ空間相簿佈局View
- 跨平臺表空間傳輸的實現
- 使用RMAN實現可傳輸的表空間
- 利用PLSQL實現表空間的遷移(一)SQL
- 利用PLSQL實現表空間的遷移(二)SQL
- 利用PLSQL實現表空間的遷移(四)SQL
- 利用PLSQL實現表空間的遷移(三)SQL
- 利用PLSQL實現表空間的遷移(五)SQL
- 教你如何實現頁面間的資料通訊
- 教你一招:基於Redis實現一個分散式鎖Redis分散式
- Redis 地理空間(geospatial)介紹及應用Redis
- 處理鍵盤通知
- 開源GIS-geos實現空間快速連線
- Java 實現高斯模糊和影像的空間卷積Java卷積
- Java 實現高斯模糊和影象的空間卷積Java卷積
- 空間索引 - GeoHash演算法及其實現優化索引演算法優化
- 指令碼實現檢視錶空間使用情況指令碼