Redis 過期時間、訪問限制與快取
過期時間
之前應該提到過 redis 的特性之一是可以設定鍵的超時時間。命令是expire。
|
EXPIRE命令返回1表示成功,返回0表示鍵值不存在或設定失敗。
同時這裡還有一個比較常用的命令是ttl,用於檢視一個鍵還有多久時間會被刪除。返回的是剩餘時間(秒數)。
這裡就不貼程式碼了,有一點需要說明的是,ttl命令在鍵不存在或被刪除之後,會返回-2,在沒有為鍵設定生存時間(即永久存在,建一個鍵之後的預設情況)時返回的是-1。大家可以親自操作一把。
如果想要把一個設定過過期時間的鍵取消過期時間設定,則需要使用persist命令。
|
這裡需要說明一點的是,除了使用persist命令外,使用set、getset命令為鍵賦值,也會同時消除鍵的生存時間,如果需要可以重新使用expire命令為鍵設定生存時間。而其他對鍵的操作命令(如incr、lpush、hset、zrem)都不會影響鍵的生存時間。
expire命令的單位是秒,而且這個引數必須為整數,如果需要更精準的時間的話,需要使用pexpire命令設定,其單位為毫秒,同理也需要用pttl命令來看鍵的剩餘毫秒數。當然使用expire命令設定的過期時間也是可以用pttl看鍵的剩餘毫秒數的。
訪問限制
有時候我們會有一個需求是需要限制一個使用者對一個資源的訪問頻率,我們假定一個使用者(用IP作為判斷)每分鐘對一個資源訪問次數不能超過10次。
我們可以使用一個鍵,每次使用者訪問則把值加1,當值加到10的時候,我們設定鍵的過期時間為60秒,並且禁止訪問。這時候下次訪問發現值為10,則不讓訪問了,然後60秒後鍵被刪除,這時候再次建立鍵。這樣就可以解決,但是其實這樣時間並不精準,問題還是挺大的。
我們還有一個方案:使用佇列。前面的章節也說到了,使用列表型別可以用作佇列。
我們設定一個佇列rate.limiting.192.168.1.1(假定是這個IP),我們把每次的訪問時間都新增到佇列中,當佇列長度達到10以後,判斷當前時間與佇列第一個值的時間差是否小於60,如果小於60則說明60秒內訪問次數超過10次,不允許訪問;否則說明可以訪問,則把佇列頭的值刪除,佇列尾增加當前訪問時間。
這種方法可以比較精準的實現訪問限制,但是當限制的次數比較大時,這種方法佔用的儲存空間也會比較大。
快取
有時候會把一些對CPU或IO資源消耗比較大的操作結果快取起來,並設定一定時間的自動過期。比如我們設定一個微博外鏈的最熱站點快取放於新浪微博的首頁,這樣我們不可能每次訪問都重新計算最熱的外鏈站點,所以我們可以設定兩小時更新一次。每次訪問是判斷這個鍵有沒有,如果存在則直接返回,如果沒有則通過計算把內容存入鍵中,並設定兩小時的過期時間。
然而在很多場合這種方法會很恐怖,當伺服器記憶體有限的時候,大量使用快取切設定生存時間過長就會導致redis佔用太多記憶體,而redis有時候會把系統記憶體都吃掉,導致系統崩潰。但是設定時間過短又會導致快取的命中太低。
所以我們最好的辦法是設定快取的淘汰規則。這種方式比較適用於將redis用作快取系統的時候比較好。
具體就是:修改配置檔案中的maxmemory引數,限制redis的最大記憶體,當超出後會按照maxmemory-policy引數指定的策略刪除不需要的鍵,直到redis佔用的記憶體小於設定值。
規則 |
說明 |
volatile-lru |
使用LRU 演算法 刪除一個鍵(只對設定了生存時間的鍵) |
allkeys-lru |
使用LRU演算法刪除一個鍵 |
volatile-random |
隨機刪除一個鍵(只對設定了生存時間的鍵) |
allkeys- random |
隨機刪除一個鍵 |
volatile-ttl |
刪除生存時間最近的一個鍵 |
noeviction |
不刪除鍵,只返回錯誤 |
其中的LRU演算法即是【最近最少使用】。
這裡提一句,實際上redis根本就不會準確的將整個 資料庫 中最久未被使用的鍵刪除,而是每次從資料庫中隨機取3個鍵並刪除這3個鍵裡最久未被使用的鍵。上面提到的所有的隨機的操作實際上都是這樣的,這個3可以用過redis的配置檔案中的maxmemeory-samples引數配置。