Redis常用技術----超時命令
Java中有GC,可以自動回收不再使用的Java物件。同樣,Redis也是基於記憶體而執行的資料集合,也存在著對記憶體垃圾的回收和管理的問題。
對於Redis,del命令可以刪除一些鍵值對,所以Redis比JVM更靈活。於此同時,當記憶體執行空間滿了之後,它還會按照回收機制去自動回收一些鍵值對,這和JVM有一定相似之處。但是當進行垃圾回收的時候,又有可能引發系統停頓,因此選擇恰當的回收機制和回收時間將有利於系統性能的提高。
首先看看鍵值對的超時命令,因為大部分情況下,我們都想回收那些超時的鍵值對。
命令 | 說明 | 備註 |
---|---|---|
persist key | 持久化key,取消超時時間 | 移除key的超時時間 |
ttl key | 檢視key的超時時間 | 以秒計算,-1代表沒有超時時間,如果不存在key或者key已經超時則為-2 |
expire key seconds | 設定超時時間戳 | 以秒為單位 |
expireat key timestamp | 設定超時時間點 | 用uninx時間戳確定 |
pptl key milliseconds | 檢視key的超時時間戳 | 以毫秒計算 |
pexpire key | 設定鍵值超時的時間 | 以毫秒為單位 |
pexpireat key stamptimes | 設定超時時間點 | 以毫秒為單位的uninx時間戳 |
下面使用spring來執行這個過程
/**
* 測試Redis的超時命令
* @author liu
*/
public class TestExpire {
@SuppressWarnings({ "unchecked", "resource" , "rawtypes", "unused" })
@Test
public void testExpire() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
RedisTemplate rt = applicationContext.getBean(RedisTemplate.class);
rt.execute((RedisOperations ops)->{
ops.boundValueOps("key1").set("value1");
String keyValue = (String)ops.boundValueOps("key1").get();
long expSecond = ops.getExpire("key1");
System.out.println(expSecond);
boolean b = false;
b = ops.expire("key1", 120L, TimeUnit.SECONDS);
b = ops.persist("key1");
long l = 0L;
l = ops.getExpire("key1");
long now = System.currentTimeMillis();
Date date = new Date();
date.setTime(now + 120000);
ops.expireAt("key1", date);
return null;
}
);
}
}
這裡討論一個問題:如果key超時了,Redis會回收key的儲存空間嗎?
答案是不會。Redis的Key超時不會被其自動回收,它只會標識哪些鍵值對超時了。這樣做的好處是如果一個很大的鍵值對超時,比如一個列表或hash結構,存著百萬個元素,要對其回收需要很長時間。如果採用超時回收,則可能會產生停頓。壞處也很明顯,這些超時的鍵值對會浪費比較多的空間。
Redis提供兩種方式回收這些超時鍵值對,分別是定時回收和惰性回收。
定時回收:在確定的某個時間觸發一次程式碼,回收超時的鍵值對。
惰性回收:當一個超時的鍵,被再次使用get命令訪問到時,將觸發Redis將其從記憶體中清空。
定時回收可以完全回收掉那些超時的鍵,但是缺點也很明顯,如果這件鍵值對比較多,那麼就會耗費較多的時間,從而導致卡頓。
對於惰性回收,它的優勢是可以指定回收的鍵值對,它的缺點是要執行一個get操作進行觸發,或者在某些時候,我們難以判斷哪些鍵值對已經超時。
無論使用那一種回收策略,都需要根據情況而定。如果一個鍵值對儲存著數億千萬的資料,使用expire命令使其到達一個時間超時,然後用get命令訪問觸發其回收,顯然會付出卡頓代價,這是現實中需要考慮的。