一、對key的操作命令
1. DEL
刪除已存在的鍵。不存在的 key 會被忽略
2. DUMP
如果 key 不存在,那麼返回 nil 。 否則,返回序列化之後的值
3. EXISTS
若 key 存在返回 1 ,否則返回 0 。
4. KEYS
查找所有符合給定模式 pattern 的 key,返回符合給定模式的 key 列表
5. MOVE
將當前數據庫的 key 移動到給定的數據庫 db 當中,成功返回 1 ,失敗則返回 0
6. RANDOMKEY
從當前數據庫中隨機返回一個 key
7. RENAME
給key重命名,改名成功時提示 OK ,失敗時候返回一個錯誤。當 舊的key 和 新的key相同,或者 舊的key 不存在時,返回一個錯誤。
當 新的key 已經存在時, RENAME 命令將覆蓋舊值
8.RENAMENX
也是重命名,新的key不存在的時候可以用,新的key已經有了的情況下會失敗而不會覆蓋
9. TYPE
返回 key 所儲存的值的類型
二、使用期限
more: https://segmentfault.com/a/1190000017776475?utm_source=tag-newest
1.使用期限相關命令
1.EXPIRE
設置一個基於秒的存活時間,設置成功返回 1 。 當 key 不存在或者不能爲 key 設置過期時間時返回 0 。
這個命令在60秒後刪掉zhangkun這個key
2. EXPIREAT
設置一個Unix時間戳形式(自1970年1月1日起)的絕對時間, 成功返回 1 。 當 key 不存在或者不能爲 key 設置過期時間時(比如在低於 2.1.3 版本的 Redis 中你嘗試更新 key 的過期時間)返回 0
3. PEXPIRE
和EXPIRE一樣,但是它以毫秒爲單位設置 key 的生存時間。
設置成功,返回 1, key 不存在或設置失敗,返回 0
4. PEXPIREAT
和EXPIREAT一樣,但是以毫秒計。
設置成功,返回 1, key 不存在或設置失敗,返回 0
5. PERSIST
移除給定 key 的過期時間,使得 key 永不過期,成功時,返回 1 。 如果 key 不存在或 key 沒有設置過期時間,返回 0
6. PTTL
以毫秒爲單位返回 key 的剩餘過期時間
7. TTL
以秒爲單位返回 key 的剩餘過期時間
2. 過期策略
過期鍵是保存在哈希表中的。那這些過期鍵到了過期的時間,就會立馬被刪除掉嗎??
要回答上面的問題,需要我們瞭解一下刪除策略的知識,刪除策略可分爲三種
- 定時刪除(對內存友好,對CPU不友好) 到時間點上就把所有過期的鍵刪除了。
- 惰性刪除(對CPU極度友好,對內存極度不友好)每次從鍵空間取鍵的時候,判斷一下該鍵是否過期了,如果過期了就刪除。
- 定期刪除(折中)每隔一段時間去刪除過期鍵,限制刪除的執行時長和頻率。
Redis採用的是惰性刪除+定期刪除兩種策略,所以說,在Redis裏邊如果過期鍵到了過期的時間了,未必被立馬刪除的!
3.內存淘汰機制
如果定期刪除漏掉了很多過期key,也沒及時去查(沒走惰性刪除),大量過期key堆積在內存裏,導致redis內存塊耗盡了,咋整?
我們可以設置內存最大使用量,當內存使用量超出時,會施行數據淘汰策略。
Redis的內存淘汰機制有以下幾種:
- 一般使用 Redis 緩存數據時,爲了提高緩存命中率,需要保證緩存數據都是熱點數據。可以將內存最大使用量設置爲熱點數據佔用的內存量,然後啓用allkeys-lru淘汰策略,將最近最少使用的數據淘汰
注意這裏的6種機制,volatile和allkeys規定了是對已設置過期時間的數據集淘汰數據還是從全部數據集淘汰數據,後面的lru、ttl以及random是三種不同的淘汰策略,再加上一種no-enviction永不回收的策略。
使用策略規則:
1、如果數據呈現冪律分佈,也就是一部分數據訪問頻率高,一部分數據訪問頻率低,則使用allkeys-lru
2、如果數據呈現平等分佈,也就是所有的數據訪問頻率都相同,則使用allkeys-random
三種數據淘汰策略:
ttl和random比較容易理解,實現也會比較簡單。主要是Lru最近最少使用淘汰策略,設計上會對key 按失效時間排序,然後取最先失效的key進行淘汰
二、發佈和訂閱(Publication and Subscriptions)
Redis的列表數據結構有blpop和brpop命令,能從列表裏返回且刪除第一個(或最後一個)元素,或者被堵塞,直到有一個元素可供操作。這可以用來實現一個簡單的隊列。
對於blpop和brpop命令,如果列表裏沒有關鍵字可供操作,連接將被堵塞,直到有另外的Redis客戶端使用lpush或rpush命令推入關鍵字爲止。
此外,Redis對於消息發佈和頻道訂閱有着一流的支持。你可以打開第二個redis-cli窗口,去嘗試一下這些功能。
在第一個窗口裏訂閱一個頻道(我們會稱它爲warnings):
subscribe warnings
其將會答覆你訂閱的信息。現在,在另一個窗口,發佈一條消息到warnings頻道:
publish warnings "it's over 9000!"
如果你回到第一個窗口,你應該已經接收到warnings頻道發來的消息。
你可以訂閱多個頻道(subscribe channel1 channel2 …),訂閱一組基於模式的頻道(psubscribe warnings:*),以及使用unsubscribe和punsubscribe命令停止監聽一個或多個頻道,或一個頻道模式。
可以注意到publish命令的返回值是1,這指出了接收到消息的客戶端數量。
- 發佈訂閱常用命令
1. PSUBSCRIBE
PSUBSCRIBE pattern [pattern …] 訂閱一個或多個符合給定模式的頻道。
2. PUBSUB
PUBSUB subcommand [argument [argument …]] 查看訂閱與發佈系統狀態。
3. PUBLISH
PUBLISH channel message 將信息發送到指定的頻道。
4. PUNSUBSCRIBE
PUNSUBSCRIBE [pattern [pattern …]] 退訂所有給定模式的頻道。
5. SUBSCRIBE
SUBSCRIBE channel [channel …] 訂閱給定的一個或多個頻道的信息。
6. UNSUBSCRIBE
UNSUBSCRIBE [channel [channel …]] 指退訂給定的頻道。
三、監控和延遲日誌(Monitor and Slow Log)
monitor命令可以讓你查看Redis正在做什麼。這是一個優秀的調試工具,能讓你瞭解你的程序如何與Redis進行交互。在兩個redis-cli窗口中選一個(如果其中一個還處於訂閱狀態,你可以使用unsubscribe命令退訂,或者直接關掉窗口再重新打開一個新窗口)鍵入monitor命令。在另一個窗口,執行任何其他類型的命令(例如get或set命令)。在第一個窗口裏,你應該可以看到這些命令,包括他們的參數。
在實際生產環境裏,你應該謹慎運行monitor命令,這真的僅僅就是一個很有用的調試和開發工具。除此之外,沒有更多要說的了。
隨同monitor命令一起,Redis擁有一個slowlog命令,這是一個優秀的性能剖析工具。其會記錄執行時間超過一定數量微秒的命令。在下一章節,我們會簡略地涉及如何配置Redis,現在你可以按下面的輸入配置Redis去記錄所有的命令:
config set slowlog-log-slower-than 0
然後,執行一些命令。最後,你可以檢索到所有日誌,或者檢索最近的那些日誌:
slowlog get
slowlog get 10
通過鍵入slowlog len,你可以獲取延遲日誌裏的日誌數量。
對於每個被你鍵入的命令,你應該查看4個參數:
-
一個自動遞增的id
-
一個Unix時間戳,表示命令開始運行的時間
-
一個微妙級的時間,顯示命令運行的總時間
-
該命令以及所帶參數
延遲日誌保存在存儲器中,因此在生產環境中運行(即使有一個低閥值)也應該不是一個問題。默認情況下,它將會追蹤最近的1024個日誌。
四、排序 Sort
sort命令是Redis最強大的命令之一。它讓你可以在一個列表、集合或者分類集合裏對值進行排序(分類集合是通過標記來進行排序,而不是集合裏的成員)。下面是一個sort命令的簡單用例:
rpush users:leto:guesses 5 9 10 2 4 10 19 2
sort users:leto:guesses
這將返回進行升序排序後的值。這裏有一個更高級的例子:
sadd friends:ghanima leto paul chani jessica alia duncan
sort friends:ghanima limit 0 3 desc alpha
上面的命令向我們展示了,如何對已排序的記錄進行分頁(通過limit),如何返回降序排序的結果(通過desc),以及如何用字典序排序代替數值序排序(通過alpha)。
sort命令的真正力量是其基於引用對象來進行排序的能力。早先的時候,我們說明了列表、集合和分類集合很常被用於引用其他的Redis對象,sort命令能夠解引用這些關係,而且通過潛在值來進行排序。例如,假設我們有一個Bug追蹤器能讓用戶看到各類已存在問題。我們可能使用一個集合數據結構去追蹤正在被監視的問題:
sadd watch:leto 12339 1382 338 9338
你可能會有強烈的感覺,想要通過id來排序這些問題(默認的排序就是這樣的),但是,我們更可能是通過問題的嚴重性來對這些問題進行排序。爲此,我們要告訴Redis將使用什麼模式來進行排序。首先,爲了可以看到一個有意義的結果,讓我們添加多一點數據:
set severity:12339 3
set severity:1382 2
set severity:338 5
set severity:9338 4
要通過問題的嚴重性來降序排序這些Bug,你可以這樣做:
sort watch:leto by severity:* desc
Redis將會用存儲在列表(集合或分類集合)中的值去替代模式中的*(通過by)。這會創建出關鍵字名字,Redis將通過查詢其實際值來排序。
在Redis裏,雖然你可以有成千上萬個關鍵字,類似上面展示的關係還是會引起一些混亂。幸好,sort命令也可以工作在散列數據結構及其相關域裏。相對於擁有大量的高層次關鍵字,你可以利用散列:
hset bug:12339 severity 3
hset bug:12339 priority 1
hset bug:12339 details "{id: 12339, ....}"
hset bug:1382 severity 2
hset bug:1382 priority 2
hset bug:1382 details "{id: 1382, ....}"
hset bug:338 severity 5
hset bug:338 priority 3
hset bug:338 details "{id: 338, ....}"
hset bug:9338 severity 4
hset bug:9338 priority 2
hset bug:9338 details "{id: 9338, ....}"
所有的事情不僅變得更爲容易管理,而且我們能通過severity或priority來進行排序,還可以告訴sort命令具體要檢索出哪一個域的數據:
sort watch:leto by bug:*->priority get bug:*->details
相同的值替代出現了,但Redis還能識別->符號,用它來查看散列中指定的域。裏面還包括了get參數,這裏也會進行值替代和域查看,從而檢索出Bug的細節(details域的數據)。
對於太大的集合,sort命令的執行可能會變得很慢。好消息是,sort命令的輸出可以被存儲起來:
sort watch:leto by bug:*->priority get bug:*->details store watch_by_priority:leto
使用我們已經看過的expiration命令,再結合sort命令的store能力,這是一個美妙的組合。
五、事務(Transactions)
每一個Redis命令都具有原子性,包括那些一次處理多項事情的命令。此外,對於使用多個命令,Redis支持事務功能。Redis實際上是單線程運行的,這就是爲什麼每一個Redis命令都能夠保證具有原子性。當一個命令在執行時,沒有其他命令會運行。在你考慮到一些命令去做多項事情時,這會特別的有用。例如:
-
incr命令實際上就是一個get命令然後緊隨一個set命令。
-
getset命令設置一個新的值然後返回原始值。
-
setnx命令首先測試關鍵字是否存在,只有當關鍵字不存在時才設置值
雖然這些都很有用,但在實際開發時,往往會需要運行具有原子性的一組命令。若要這樣做,首先要執行multi命令,緊隨其後的是所有你想要執行的命令(作爲事務的一部分),最後執行exec命令去實際執行命令,或者使用discard命令放棄執行命令。
單個 Redis 命令的執行是原子性的,但 Redis 最開始沒有在事務上增加任何維持原子性的機制,所以 Redis 事務最開始並不是原子性的。redis 自從2.2版本以後纔開始保證事務的基本特性:要麼執行所有的命令要麼都不執行另外,另外還提供了樂觀鎖提供更多保證。
事務可以理解爲一個打包的批量執行腳本,但批量指令並非原子化的操作,中間某條指令的失敗不會導致前面已做指令的回滾,也不會造成後續的指令不做,因爲redis無法實現命令之間的邏輯關係計算。
multi
hincrby groups:1percent balance -9000000000
hincrby groups:99percent balance 9000000000
exec
最後,Redis能讓你指定一個關鍵字(或多個關鍵字),當關鍵字有改變時,可以查看或者有條件地應用一個事務。這是用於當你需要獲取值,且待運行的命令基於那些值時,所有都在一個事務裏。對於上面展示的代碼,我們不能去實現自己的incr命令,因爲一旦exec命令被調用,他們會全部被執行在一塊。我們不能這麼做:
redis.multi()
current = redis.get('powerlevel')
redis.set('powerlevel', current + 1)
redis.exec()
雖然Redis是單線程運行的,但是我們可以同時運行多個Redis客戶端進程,常見的併發問題還是會出現。像上面的代碼,在get運行之後,set運行之前,powerlevel的值可能會被另一個Redis客戶端給改變,從而造成錯誤。
這些不是Redis的事務功能的工作。但是,如果我們增加一個watch到powerlevel,我們可以這樣做:
redis.watch('powerlevel')
current = redis.get('powerlevel')
redis.multi()
redis.set('powerlevel', current + 1)
redis.exec()
在我們調用watch後,如果另一個客戶端改變了powerlevel的值,我們的事務將會運行失敗。如果沒有客戶端改變powerlevel的值,那麼事務會繼續工作。我們可以在一個循環裏運行這些代碼,直到其能正常工作。
- 事務常用命令
1. DISCARD
取消事務,放棄執行事務塊內的所有命令。
2. EXEC
執行所有事務塊內的命令。
3. MULTI
標記一個事務塊的開始。
4. UNWATCH
取消 WATCH 命令對所有 key 的監視。
5. WATCH
WATCH key [key …] 監視一個(或多個) key ,如果在事務執行之前這個(或這些) key 被其他命令所改動,那麼事務將被打斷。