Redis的超时命令和垃圾回收策略
正如 Java 虛擬機(jī),它提供了自動(dòng) GC(垃圾回收)的功能,來保證 Java 程序使用過且不再使用的 Java 對(duì)象及時(shí)的從內(nèi)存中釋放掉,從而保證內(nèi)存空間可用。
當(dāng)程序編寫不當(dāng)或考慮欠缺的時(shí)候(比如讀入大文件),內(nèi)存就可能存儲(chǔ)不下運(yùn)行所需要的數(shù)據(jù),那么 Java 虛擬機(jī)就會(huì)拋出內(nèi)存溢出的異常而導(dǎo)致服務(wù)失敗。同樣,Redis 也是基于內(nèi)存而運(yùn)行的數(shù)據(jù)集合,也存在著對(duì)內(nèi)存垃圾的回收和管理的問題。
Redis 基于內(nèi)存,而內(nèi)存對(duì)于一個(gè)系統(tǒng)是最為寶貴的資源,而且它遠(yuǎn)遠(yuǎn)沒有磁盤那么大,所以對(duì)于 Redis 的鍵值對(duì)的內(nèi)存回收也是一個(gè)十分重要的問題,如果操作不當(dāng)會(huì)產(chǎn)生 Redis 宕機(jī)的問題,使得系統(tǒng)性能低下。
一般而言,和 Java 虛擬機(jī)一樣,當(dāng)內(nèi)存不足時(shí) Redis 會(huì)觸發(fā)自動(dòng)垃圾回收的機(jī)制,而程序員可以通過 System.gc() 去建議 Java 虛擬機(jī)回收內(nèi)存垃圾,它將“可能”(注意,System.gc() 并不一定會(huì)觸發(fā) JVM 去執(zhí)行回收,它僅僅是建議 JVM 做回收)觸發(fā)一次 Java 虛擬機(jī)的回收機(jī)制,但是如果這樣做可能導(dǎo)致 Java 虛擬機(jī)在回收大量的內(nèi)存空間的同時(shí),引發(fā)性能低下的情況。
對(duì)于 Redis 而言,del 命令可以刪除一些鍵值對(duì),所以 Redis 比 Java 虛擬機(jī)更靈活,允許刪除一部分的鍵值對(duì)。與此同時(shí),當(dāng)內(nèi)存運(yùn)行空間滿了之后,它還會(huì)按照回收機(jī)制去自動(dòng)回收一些鍵值對(duì),這和 Java 虛擬機(jī)又有相似之處,但是當(dāng)垃圾進(jìn)行回收的時(shí)候,又有可能執(zhí)行回收而引發(fā)系統(tǒng)停頓,因此選擇適當(dāng)?shù)幕厥諜C(jī)制和時(shí)間將有利于系統(tǒng)性能的提高,這是我們需要去學(xué)習(xí)的。
在談?wù)?Redis 內(nèi)存回收之前,首先要討論的是鍵值對(duì)的超時(shí)命令,因?yàn)榇蟛糠智闆r下,我們都想回收那些超時(shí)的鍵值對(duì),而不是那些非超時(shí)的鍵值對(duì)。
Redis的超時(shí)命令
這些命令在 Redis 客戶端的使用,如圖所示。
使用 Spring 也可以執(zhí)行這樣的一個(gè)過程,下面用 Spring 演示這個(gè)過程,代碼如下所示。
public static void testExpire() {ApplicationContext applicationContext = new ClassPathXmlApplicationContext ("applicationContext.xml");RedisTemplate redisTemplate = applicationContext.getBean(RedisTemplate.class);redisTemplate.execute((RedisOperations ops) -> {ops.boundValueOps("key1").set("value1");String keyValue = (String)ops.boundValueOps("key1").get();Long expSecond = ops.getExpire("key1");System.err.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("key", date);return null;}); }上面這段代碼采用的就是 Spring 操作 Redis 超時(shí)命令的一個(gè)過程。
這里有一個(gè)問題需要討論:如果 key 超時(shí)了,Redis 會(huì)回收 key 的存儲(chǔ)空間嗎?
答案是不會(huì)。這里需要非常注意的是:Redis 的 key 超時(shí)不會(huì)被其自動(dòng)回收,它只會(huì)標(biāo)識(shí)哪些鍵值對(duì)超時(shí)了。
這樣做的一個(gè)好處在于,如果一個(gè)很大的鍵值對(duì)超時(shí),比如一個(gè)列表或者哈希結(jié)構(gòu),存在數(shù)以百萬個(gè)元素,要對(duì)其回收需要很長(zhǎng)的時(shí)間。如果采用超時(shí)回收,則可能產(chǎn)生停頓。壞處也很明顯,這些超時(shí)的鍵值對(duì)會(huì)浪費(fèi)比較多的空間。
Redis 提供兩種方式回收這些超時(shí)鍵值對(duì),它們是定時(shí)回收和惰性回收。
定時(shí)回收是指在確定的某個(gè)時(shí)間觸發(fā)一段代碼,回收超時(shí)的鍵值對(duì)。
惰性回收則是當(dāng)一個(gè)超時(shí)的鍵,被再次用 get 命令訪問時(shí),將觸發(fā) Redis 將其從內(nèi)存中清空。
定時(shí)回收可以完全回收那些超時(shí)的鍵值對(duì),但是缺點(diǎn)也很明顯,如果這些鍵值對(duì)比較多,則 Redis 需要運(yùn)行較長(zhǎng)的時(shí)間,從而導(dǎo)致停頓。所以系統(tǒng)設(shè)計(jì)者一般會(huì)選擇在沒有業(yè)務(wù)發(fā)生的時(shí)刻觸發(fā) Redis 的定時(shí)回收,以便清理超時(shí)的鍵值對(duì)。
對(duì)于惰性回收而言,它的優(yōu)勢(shì)是可以指定回收超時(shí)的鍵值對(duì),它的缺點(diǎn)是要執(zhí)行一個(gè)莫名其妙的 get 操作,或者在某些時(shí)候,我們也難以判斷哪些鍵值對(duì)已經(jīng)超時(shí)。
無論是定時(shí)回收還是惰性回收,都要依據(jù)自身的特點(diǎn)去定制策略,如果一個(gè)鍵值對(duì),存儲(chǔ)的是數(shù)以千萬的數(shù)據(jù),使用 expire 命令使其到達(dá)一個(gè)時(shí)間超時(shí),然后用 get 命令訪問觸發(fā)其回收,顯然會(huì)付出停頓代價(jià),這是現(xiàn)實(shí)中需要考慮的。
總結(jié)
以上是生活随笔為你收集整理的Redis的超时命令和垃圾回收策略的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 搜索栏联想词提示
- 下一篇: MySql数据库连接种类