Redis指令使用實例分析
問題原因
小編負責的應用是一個管理後台應用,權限管理使用 Shiro 框架,由於存在多個節點,需要使用分散式 Session,於是這裡使用 Redis 儲存 Session 資訊。
由於 Shiro 並沒有直接提供 Redis 儲存 Session 元件,阿粉不得不使用 Github 一個開源元件 shiro-redis。
由於 Shiro 框架需要定期驗證 Session 是否有效,因此 Shiro 底層將會呼叫 SessionDAO#getActiveSessions
取得所有的 Session 資訊。
而shiro-redis
剛好繼承SessionDAO
這個接口,底層使用用keys
指令來尋找Redis 所有儲存的Session
key。
public Set<byte[]> keys(byte[] pattern){ checkAndInit(); Set<byte[]> keys = null; Jedis jedis = jedisPool.getResource(); try{ keys = jedis.keys(pattern); }finally{ jedis.close(); } return keys; }
找到問題原因,解決方法就比較簡單了,github 上查找到解決方案,升級一下 shiro-redis
到最新版本。
在這個版本,shiro-redis
採用 scan
指令取代 keys
,從而修正這個問題。
public Set<byte[]> keys(byte[] pattern) { Set<byte[]> keys = null; Jedis jedis = jedisPool.getResource(); try{ keys = new HashSet<byte[]>(); ScanParams params = new ScanParams(); params.count(count); params.match(pattern); byte[] cursor = ScanParams.SCAN_POINTER_START_BINARY; ScanResult<byte[]> scanResult; do{ scanResult = jedis.scan(cursor,params); keys.addAll(scanResult.getResult()); cursor = scanResult.getCursorAsBytes(); }while(scanResult.getStringCursor().compareTo(ScanParams.SCAN_POINTER_START) > 0); }finally{ jedis.close(); } return keys; }
雖然問題成功解決了,但阿粉心裡還是有點不解。
為什麼keys
指令會導致其他指令執行變慢?
為什麼Keys
指令查詢會這麼慢?
為什麼Scan
指令就沒有問題?
Redis 執行指令的原理
首先我們來看第一個問題,為什麼keys
指令會導致其他指令執行變慢?
站在客戶端的視角,執行一條指令分成三步驟:
發送指令
執行指令
返回結果
但是這僅僅是客戶端自己以為的過程,但是實際上同一時刻,可能存在很多客戶端發送命令給Redis ,而Redis 我們都知道它採用的是單線程模型。
為了處理同一時刻所有的客戶端的請求命令,Redis 內部採用了佇列的方式,排隊執行。
於是客戶端執行一條指令實際上需要四個步驟:
發送指令
指令排隊
- 執行指令
- 傳回結果
#由於Redis 單執行緒執行指令,只能依序從佇列取出任務開始執行。
只要 3 這個流程執行指令速度過慢,佇列其他任務不得不進行等待,這對外部客戶端看來,Redis 好像就被阻塞一樣,一直無法回應。
所以使用 Redis 程序切勿執行需要長時間運行的指令,這可能導致 Redis 阻塞,影響執行其他指令。
KEYS 原理接下來開始回答第二個問題,為什麼
指令查詢會這麼慢?
回答這個問題之前,請先回想 Redis 底層儲存結構。
不太清楚朋友的也沒關係,大家可以回看一下之前的文章「阿里面試官:HashMap 熟悉吧?好的,那就來聊聊 Redis 字典吧!」。 keys
指令需要回傳所有的符合給定模式pattern
的 Redis 中鍵,為了實現這個目的,Redis 不得不遍歷字典中ht[ 0]哈希表底層數組,這個時間複雜度為
(N 為Redis 中key 所有的數量)。
即使 Redis 中的鍵數量很少,它仍然會有很快的執行速度。當Redis鍵的數量逐漸增多,達到百萬、千萬,甚至上億級時,它的執行速度會變得非常緩慢。 下面是阿粉本地做的一次實驗,使用lua 腳本往Redis 中增加10W 個key,然後使用
查詢所有鍵,這個查詢大概會阻塞十幾秒的時間。這裡阿粉使用 Docker 部署 Redis,效能可能會稍差。eval "for i=1,100000 do redis.call('set',i,i+1) end" 0登入後複製
SCAN 原理最後我們來看下第三個問題,為什麼
指令就沒有問題? 這是因為 scan指令採用一種黑科技-
。 每次呼叫
指令,Redis 都會向使用者傳回一個新的遊標以及一定數量的 key。下次再想繼續取得剩餘的 key,需要將這個遊標傳入 scan 指令, 以此來延續先前的迭代過程。 簡單來講,
指令使用分頁查詢 redis 。
下面是一個scan 指令的迭代過程範例:
指令使用遊標這個方式,巧妙將一次全量查詢拆分成多次,降低查詢複雜度。 雖然
scan
指令時間複雜度與keys一樣,都是「O(N)」
,但由於
指令只需要回傳少量的key,所以執行速度會很快。 最後,雖然
scan
指令解決
- 不足,但同時也引入其他一些缺陷:
- ###同一個元素可能會被回傳多次,這需要我們應用程式增加處理重複元素功能。 ###
在迭代過程中,有可能會傳回正在增加到 Redis 的元素,或是正在被刪除的元素,也有可能不會。
以上這些缺陷,在我們開發中需要考慮這種情況。
除了scan
以外,redis 還有其他幾個用於增量迭代命令:
sscan
:用於迭代目前資料庫中的資料庫鍵,用於解決smembers
可能產生阻塞問題hscan
指令用於迭代雜湊鍵中的鍵值對,用於解決hgetall
可能產生阻塞問題。zscan
:指令用於迭代有序集合中的元素(包括元素成員和元素分數),用於產生zrange
#可能產生阻塞問題。
以上是Redis指令使用實例分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Redis集群模式通過分片將Redis實例部署到多個服務器,提高可擴展性和可用性。搭建步驟如下:創建奇數個Redis實例,端口不同;創建3個sentinel實例,監控Redis實例並進行故障轉移;配置sentinel配置文件,添加監控Redis實例信息和故障轉移設置;配置Redis實例配置文件,啟用集群模式並指定集群信息文件路徑;創建nodes.conf文件,包含各Redis實例的信息;啟動集群,執行create命令創建集群並指定副本數量;登錄集群執行CLUSTER INFO命令驗證集群狀態;使

如何清空 Redis 數據:使用 FLUSHALL 命令清除所有鍵值。使用 FLUSHDB 命令清除當前選定數據庫的鍵值。使用 SELECT 切換數據庫,再使用 FLUSHDB 清除多個數據庫。使用 DEL 命令刪除特定鍵。使用 redis-cli 工具清空數據。

要從 Redis 讀取隊列,需要獲取隊列名稱、使用 LPOP 命令讀取元素,並處理空隊列。具體步驟如下:獲取隊列名稱:以 "queue:" 前綴命名,如 "queue:my-queue"。使用 LPOP 命令:從隊列頭部彈出元素並返回其值,如 LPOP queue:my-queue。處理空隊列:如果隊列為空,LPOP 返回 nil,可先檢查隊列是否存在再讀取元素。

在CentOS系統上,您可以通過修改Redis配置文件或使用Redis命令來限制Lua腳本的執行時間,從而防止惡意腳本佔用過多資源。方法一:修改Redis配置文件定位Redis配置文件:Redis配置文件通常位於/etc/redis/redis.conf。編輯配置文件:使用文本編輯器(例如vi或nano)打開配置文件:sudovi/etc/redis/redis.conf設置Lua腳本執行時間限制:在配置文件中添加或修改以下行,設置Lua腳本的最大執行時間(單位:毫秒)

使用 Redis 命令行工具 (redis-cli) 可通過以下步驟管理和操作 Redis:連接到服務器,指定地址和端口。使用命令名稱和參數向服務器發送命令。使用 HELP 命令查看特定命令的幫助信息。使用 QUIT 命令退出命令行工具。

Redis計數器是一種使用Redis鍵值對存儲來實現計數操作的機制,包含以下步驟:創建計數器鍵、增加計數、減少計數、重置計數和獲取計數。 Redis計數器的優勢包括速度快、高並發、持久性和簡單易用。它可用於用戶訪問計數、實時指標跟踪、遊戲分數和排名以及訂單處理計數等場景。

Redis數據過期策略有兩種:定期刪除:定期掃描刪除過期鍵,可通過 expired-time-cap-remove-count、expired-time-cap-remove-delay 參數設置。惰性刪除:僅在讀取或寫入鍵時檢查刪除過期鍵,可通過 lazyfree-lazy-eviction、lazyfree-lazy-expire、lazyfree-lazy-user-del 參數設置。

在Debian系統中,readdir系統調用用於讀取目錄內容。如果其性能表現不佳,可嘗試以下優化策略:精簡目錄文件數量:盡可能將大型目錄拆分成多個小型目錄,降低每次readdir調用處理的項目數量。啟用目錄內容緩存:構建緩存機制,定期或在目錄內容變更時更新緩存,減少對readdir的頻繁調用。內存緩存(如Memcached或Redis)或本地緩存(如文件或數據庫)均可考慮。採用高效數據結構:如果自行實現目錄遍歷,選擇更高效的數據結構(例如哈希表而非線性搜索)存儲和訪問目錄信
