1. 程式人生 > >springmvc訂閱redis鍵過期訊息通知

springmvc訂閱redis鍵過期訊息通知

首先啟用redis通知功能(ubuntu下操作):
編輯/etc/redis/redis.conf檔案,新增或啟用以下內容(過期通知):

notify-keyspace-events Ex

或者登陸redis-cli之後,輸入以下命令:

config set notify-keyspace-events Ex

因鍵空間通知功能需要耗費一定的CPU時間,因此預設情況下,該功能是關閉的。可以通過修改配置檔案redis.conf,或者通過CONFIG SET命令,設定notify-keyspace-events選項,來啟用或關閉該功能。

         該選項的值為空字串時,該功能禁用,選項值為非空字串時,啟用該功能,非空字串由特定的多個字元組成,每個字元表示不同的意義:

K:keyspace事件,事件以[email protected]<db>__為字首進行釋出;

E:keyevent事件,事件以[email protected]<db>__為字首進行釋出;

g:一般性的,非特定型別的命令,比如del,expire,rename等;

$:字串特定命令;

l:列表特定命令;

s:集合特定命令;

h:雜湊特定命令;

z:有序集合特定命令;

x:過期事件,當某個鍵過期並刪除時會產生該事件;

e:驅逐事件,當某個鍵因maxmemore策略而被刪除時,產生該事件;

A:g$lshzxe的別名,因此”AKE”意味著所有事件。

         注意,該選項的值中至少需要包含K或者E,否則不會發布任何事件。比如,如果需要開啟針對列表的keyspace事件通知,則該選項需要配置為“Kl”;


expired事件通知的傳送時間

Redis 使用以下兩種方式刪除過期的鍵:

a:當一個鍵被訪問時,程式會對這個鍵進行檢查,如果鍵已過期,則刪除該鍵;

b:系統會在後臺定期掃描並刪除那些過期的鍵;

當過期鍵被以上兩種方式中的任意一種發現並且刪除時,才會產生expired事件通知。

Redis不保證生存時間(TTL)變為 0 的鍵會立即被刪除:如果沒有命令訪問這個鍵,或者設定生存時間的鍵非常多的話,那麼在鍵的生存時間變為0,到該鍵真正被刪除,這中間可能會有一段比較顯著的時間間隔。

因此,Redis產生expired事件通知的時間,是過期鍵被刪除的時候,而不是鍵的生存時間變為 0 的時候。

=========================================================

不同命令產生的事件通知

DEL 命令為每個被刪除的鍵產生一個 del 事件;

RENAME 產生兩個事件:為源鍵產生一個 rename_from 事件,併為目標鍵產生一個 rename_to 事件;

EXPIRE命令,在設定鍵的過期時間時產生一個 expire事件;當鍵因過期而被刪除時,產生一個 expired事件;

SORT命令,在帶有 STORE 引數時產生一個 sortstore事件。如果 STORE 指示的用於儲存排序結果的鍵已經存在,則原鍵會被刪除,因此還會產生一個 del 事件;

SET 以及它的所有變種(SETEX、SETNX和GETSET)都產生set事件。另外,SETEX命令還會產生expire 事件;

MSET 命令,為每個鍵產生一個 set 事件;

SETRANGE 產生一個 setrange 事件;

INCR 、DECR、INCRBY和DECRBY都產生 incrby 事件;

INCRBYFLOAT產生incrbyfloat事件;

APPEND產生append事件;

LPUSH和LPUSHX都產生單個 lpush 事件,即使有多個輸入元素時,也是如此;

RPUSH 和 RPUSHX 都產生單個rpush事件,即使有多個輸入元素時,也是如此;

RPOP 產生 rpop 事件,如果被彈出的元素是列表的最後一個元素,那麼還會產生一個 del 事件;

LPOP 產生 lpop 事件,如果被彈出的元素是列表的最後一個元素,那麼還會產生一個 del 事件;

LINSERT 產生一個 linsert 事件;

LSET 產生一個 lset 事件;

LREM產生一個lrem事件,如果該命令執行之後,列表鍵被清空,則還會產生一個 del 事件;

LTRIM 產生一個ltrim事件,如果該命令執行之後,列表鍵被清空,則還會產生一個 del 事件;

RPOPLPUSH 和 BRPOPLPUSH 產生一個 rpop 事件,以及一個 lpush 事件。兩個命令都保證rpop事件在 lpush 事件之前發出。如果彈出元素之後,列表鍵被清空,則還會產生一個 del 事件;

HSET 、 HSETNX 和 HMSET 都只產生一個 hset 事件;

HINCRBY 產生一個 hincrby 事件;

HINCRBYFLOAT 產生一個 hincrbyfloat 事件;

HDEL 產生一個 hdel 通知。如果執行該命令之後,雜湊鍵被清空,則還會產生一個del事件;

SADD 產生一個 sadd 事件,即使有多個輸入元素時,也是如此;

SREM 產生一個 srem 事件,如果執行該命令之後,集合鍵被清空,則還會產生一個 del 事件;

SMOVE 為源鍵產生一個 srem 事件,併為目標鍵產生一個sadd 事件;

SPOP 產生一個 spop 事件。如果執行該命令之後,集合鍵被清空,則還會產生一個 del 事件;

SINTERSTORE、SUNIONSTORE和SDIFFSTORE分別產生 sinterstore、sunionostore和sdiffstore 三種事件。如果用於儲存結果的鍵已經存在,則還會產生一個 del 事件;

ZINCR產生一個 zincr 事件;

ZADD 產生一個 zadd事件,即使有多個輸入元素時,也是如此;

ZREM 產生一個 zrem 通知,即使有多個輸入元素時,也是如此。如果執行 ZREM 之後,有序集合鍵被清空,則還會產生一個 del 事件;

ZREMEBYSCORE 產生一個 zrembyscore事件,如果用於儲存結果的鍵已經存在,則還會產生一個 del 事件。

ZREMBYRANK 產生一個 zrembyrank事件,如果用於儲存結果的鍵已經存在,則還會產生一個 del 事件。

ZINTERSTORE 和 ZUNIONSTORE 分別產生 zinterstore 和 zunionstore 兩種事件。如果用於儲存結果的鍵已經存在,那麼還會產生一個 del 事件。

每當一個鍵因為過期而被刪除時,產生一個 expired 事件。

每當一個鍵因為 maxmemory策略而被刪除並回收記憶體時,產生一個 evicted 事件。

注意:所有命令都只在鍵真的被改動了之後,才會產生事件通知。比如,當srem命令試圖刪除不存在於集合的元素時,刪除操作執行失敗,因為沒有真正的改動鍵,所以這一操作不會發送通知。


==========================================================

使用maven搭建好springmvc,和搭配好相應的redis的jar包,這個之前的部落格中有,這裡就不提了..

先寫好相應的java處理該訊息通知的類:

import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;

public class MyRedisKeyExpiredMessageDelegate    implements MessageListener {

	
	public void onMessage(Message message, byte[] pattern) {
		System.out.println("channel:" + new String(message.getChannel())
                + ",message:" + new String(message.getBody()));
    }
}
再在springmvc的xml配置裡面搭配好相應的監聽配置:
	<bean id="messageListener"
		class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
		<constructor-arg>
			<bean class="com.zww.common.redis.MyRedisKeyExpiredMessageDelegate" />
		</constructor-arg>
	</bean>
	<bean id="redisContainer"
		class="org.springframework.data.redis.listener.RedisMessageListenerContainer">
		<property name="connectionFactory" ref="connectionFactory" />
		<property name="messageListeners">
			<map>
				<entry key-ref="messageListener">
					<list>
						<!--  <bean class="org.springframework.data.redis.listener.ChannelTopic"> 
							<constructor-arg value="[email protected]__:expired" /> </bean>  -->
						<!-- <bean class="org.springframework.data.redis.listener.PatternTopic"> 
							<constructor-arg value="*" /> </bean> -->
						<bean class="org.springframework.data.redis.listener.PatternTopic">
							<constructor-arg value="__key*__:expired" />
						</bean>
					</list>
				</entry>
			</map>
		</property>
	</bean>

好了,這個時候可以啟動伺服器,隨便插入一個鍵,設定好過期時間,就會看到列印的日誌了

這裡我在弄的時候有遇到這樣一個坑,就是這個日誌列印了兩次,,仔細一看,是因為springmvc的配置載入了兩次,主要原因還是因為web.xml裡面的配置使springmvc載入兩次,配置好相應的配置就好了....

不過因此也說明了,這個 

MyRedisKeyExpiredMessageDelegate     

 類最好是搞成單列,這樣才能防止通知兩次,使同樣的程式碼執行兩次,出現一些意外的情況,和耗費系統資源

此文參考 
http://blog.csdn.net/gqtcgq/article/details/50808729

http://www.bubuko.com/infodetail-1895361.html