Redis中的鍵值過期操作
1.過期設定
Redis 中設定過期時間主要通過以下四種方式:
- expire key seconds:設定 key 在 n 秒後過期;
- pexpire key milliseconds:設定 key 在 n 毫秒後過期;
- expireat key timestamp:設定 key 在某個時間戳(精確到秒)之後過期;
- pexpireat key millisecondsTimestamp:設定 key 在某個時間戳(精確到毫秒)之後過期;
下面分別來看以上這些命令的具體實現。
1)expire:N 秒後過期
127.0.0.1:6379> set key value OK 127.0.0.1:6379> expire key 100 (integer) 1 127.0.0.1:6379> ttl key (integer) 97
其中命令 ttl
的全稱是 Time To Live
表示此鍵值在 n 秒後過期。例如,上面的結果 97
表示 key
在 97s 後過期。
2)pexpire:N 毫秒後過期
127.0.0.1:6379> set key2 value2
OK
127.0.0.1:6379> pexpire key2 100000
(integer) 1
127.0.0.1:6379> pttl key2
(integer) 94524
其中 pexpire key2 100000
表示設定 key2
在 100000 毫秒(100秒)後過期。
3)expireat:過期時間戳精確到秒
127.0.0.1:6379> set key3 value3 OK 127.0.0.1:6379> expireat key3 1573472683 (integer) 1 127.0.0.1:6379> ttl key3 (integer) 67
其中 expireat key3 1573472683
表示 key3
在時間戳 1573472683
後過期(精確到秒),使用 ttl
查詢可以發現在 67s 後 key3
會過期。
小貼士:在 Redis 可以使用 time 命令查詢當前時間的時間戳(精確到秒),示例如下:
127.0.0.1:6379> time
1) "1573472563"
2) "248426"
4)pexpireat:過期時間戳精確到毫秒
127.0.0.1:6379> set key4 value4 OK 127.0.0.1:6379> pexpireat key4 1573472683000 (integer) 1 127.0.0.1:6379> pttl key4 (integer) 3522
其中 pexpireat key4 1573472683000
表示 key4
在時間戳 1573472683000
後過期(精確到毫秒),使用 ttl
查詢可以發現在 3522ms 後 key4
會過期。
5)字串中的過期操作
字串中幾個直接操作過期時間的方法,如下列表:
- set key value ex seconds:設定鍵值對的同時指定過期時間(精確到秒);
- set key value ex milliseconds:設定鍵值對的同時指定過期時間(精確到毫秒);
- setex key seconds valule:設定鍵值對的同時指定過期時間(精確到秒)。
實現示例如下:
① set key value ex seconds
127.0.0.1:6379> set k v ex 100
OK
127.0.0.1:6379> ttl k
(integer) 97
② set key value ex milliseconds
127.0.0.1:6379> set k2 v2 px 100000
OK
127.0.0.1:6379> pttl k2
(integer) 92483
③ setex key seconds valule
127.0.0.1:6379> setex k3 100 v3
OK
127.0.0.1:6379> ttl k3
(integer) 91
2.移除過期時間
使用命令: persist key
可以移除鍵值的過期時間,如下程式碼所示:
127.0.0.1:6379> ttl k3
(integer) 97
127.0.0.1:6379> persist k3
(integer) 1
127.0.0.1:6379> ttl k3
(integer) -1
可以看出第一次使用 ttl
查詢 k3
會在 97s 後過期,當使用了 persist
命令之後,在查詢 k3
的存活時間發現結果是 -1,它表示 k3
永不過期。
3.Java實現過期操作
本文將使用 Jedis 框架來實現對 Redis 過期時間的操作,如下程式碼所示:
public class TTLTest {
public static void main(String[] args) throws InterruptedException {
// 建立 Redis 連線
Jedis jedis = new Jedis("xxx.xxx.xxx.xxx", 6379);
// 設定 Redis 密碼(如果沒有密碼,此行可省略)
jedis.auth("xxx");
// 儲存鍵值對(預設情況下永不過期)
jedis.set("k", "v");
// 查詢 TTL(過期時間)
Long ttl = jedis.ttl("k");
// 列印過期日誌
System.out.println("過期時間:" + ttl);
// 設定 100s 後過期
jedis.expire("k", 100);
// 等待 1s 後執行
Thread.sleep(1000);
// 列印過期日誌
System.out.println("執行 expire 後的 TTL=" + jedis.ttl("k"));
}
}
程式的執行結果為:
過期時間:-1
執行 expire 後的 TTL=99
可以看出使用 Jedis 來操作 Redis 的過期時間還是很方便的,可直接使用 jedis.ttl("k")
查詢鍵值的生存時間,使用 jedis.expire("k",seconds)
方法設定過期時間(精確到秒)。
小貼士:使用 Jedis 之前,先要把 Jedis 引入到程式中,如果使用的是 Maven 專案的,直接在 pom.xml 檔案中新增以下引用:
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>version</version>
</dependency>
更多過期操作方法,如下列表:
- pexpire(String key, long milliseconds):設定 n 毫秒後過期;
- expireAt(String key, long unixTime):設定某個時間戳後過期(精確到秒);
- pexpireAt(String key, long millisecondsTimestamp):設定某個時間戳後過期(精確到毫秒);
- persist(String key):移除過期時間。
完整示例程式碼如下:
public class TTLTest {
public static void main(String[] args) throws InterruptedException {
// 建立 Redis 連線
Jedis jedis = new Jedis("xxx.xxx.xxx.xxx", 6379);
// 設定 Redis 密碼(如果沒有密碼,此行可省略)
jedis.auth("xxx");
// 儲存鍵值對(預設情況下永不過期)
jedis.set("k", "v");
// 查詢 TTL(過期時間)
Long ttl = jedis.ttl("k");
// 列印過期日誌
System.out.println("過期時間:" + ttl);
// 設定 100s 後過期
jedis.expire("k", 100);
// 等待 1s 後執行
Thread.sleep(1000);
// 列印過期日誌
System.out.println("執行 expire 後的 TTL=" + jedis.ttl("k"));
// 設定 n 毫秒後過期
jedis.pexpire("k", 100000);
// 設定某個時間戳後過期(精確到秒)
jedis.expireAt("k", 1573468990);
// 設定某個時間戳後過期(精確到毫秒)
jedis.pexpireAt("k", 1573468990000L);
// 移除過期時間
jedis.persist("k");
}
}
4.持久化中的過期鍵
上面我們講了過期鍵在 Redis 正常執行中一些使用案例,接下來,我們來看 Redis 在持久化的過程中是如何處理過期鍵的。
Redis 持久化檔案有兩種格式:RDB(Redis Database)和 AOF(Append Only File),下面我們分別來看過期鍵在這兩種格式中的呈現狀態。
1)RDB中的過期鍵
RDB 檔案分為兩個階段,RDB 檔案生成階段和載入階段。
① RDB 檔案生成
從記憶體狀態持久化成 RDB(檔案)的時候,會對 key 進行過期檢查,過期的鍵不會被儲存到新的 RDB 檔案中,因此 Redis 中的過期鍵不會對生成新 RDB 檔案產生任何影響。
② RDB 檔案載入
RDB 載入分為以下兩種情況:
- 如果 Redis 是主伺服器執行模式的話,在載入 RDB 檔案時,程式會對檔案中儲存的鍵進行檢查,過期鍵不會被載入到資料庫中。所以過期鍵不會對載入 RDB 檔案的主伺服器造成影響;
- 如果 Redis 是從伺服器執行模式的話,在載入 RDB 檔案時,不論鍵是否過期都會被載入到資料庫中。但由於主從伺服器在進行資料同步時,從伺服器的資料會被清空。所以一般來說,過期鍵對載入 RDB 檔案的從伺服器也不會造成影響。
RDB 檔案載入的原始碼可以在 rdb.c 檔案的 rdbLoad() 函式中找到,原始碼所示:
/* Check if the key already expired. This function is used when loading
* an RDB file from disk, either at startup, or when an RDB was
* received from the master. In the latter case, the master is
* responsible for key expiry. If we would expire keys here, the
* snapshot taken by the master may not be reflected on the slave.
*
* 如果伺服器為主節點的話,
* 那麼在鍵已經過期的時候,不再將它們關聯到資料庫中去
*/
if (server.masterhost == NULL && expiretime != -1 && expiretime < now) {
decrRefCount(key);
decrRefCount(val);
// 跳過
continue;
}
2)AOF中的過期鍵
① AOF 檔案寫入
當 Redis 以 AOF 模式持久化時,如果資料庫某個過期鍵還沒被刪除,那麼 AOF 檔案會保留此過期鍵,當此過期鍵被刪除後,Redis 會向 AOF 檔案追加一條 DEL 命令來顯式地刪除該鍵值。
② AOF 重寫
執行 AOF 重寫時,會對 Redis 中的鍵值對進行檢查已過期的鍵不會被儲存到重寫後的 AOF 檔案中,因此不會對 AOF 重寫造成任何影響。
5.主從庫的過期鍵
當 Redis 執行在主從模式下時,從庫不會進行過期掃描,從庫對過期的處理是被動的。也就是即時從庫中的 key 過期了,如果有客戶端訪問從庫時,依然可以得到 key 對應的值,像未過期的鍵值對一樣返回。
從庫的過期鍵處理依靠主伺服器控制,主庫在 key 到期時,會在 AOF 檔案裡增加一條 del 指令,同步到所有的從庫,從庫通過執行這條 del 指令來刪除過期的 key。
6.小結
本文我們知道了 Redis 中的四種設定過期時間的方式:expire、pexpire、expireat、pexpireat,其中比較常用的是 expire 設定鍵值 n 秒後過期。
字串中可以在新增鍵值的同時設定過期時間,並可以使用 persist 命令移除過期時間。同時我們也知道了過期鍵在 RDB 寫入和 AOF 重寫時都不會被記錄。
過期鍵在主從模式下,從庫對過期鍵的處理要完全依靠主庫,主庫刪除過期鍵之後會發送 del 命令給所有的從庫。
本文的知識點,如下圖所示:
7.引用&鳴謝
https://segmentfault.com/a/1190000017776475
https://www.cnblogs.com/lukexwang/p/4710333.h