redis的scan的使用

1.scan命令

在有些場景中,我們希望去查找符合部分字符匹配的key,
在scan命令出來之前,都是使用keys命令 ,keys pattern,這種命令嚴禁在線上環境中使用,因爲keys命令會去匹配所有的key,與之類似的可能阻塞服務的命令還有smebmers,hgetall,如果hash和set中元素較多,由於redis的單線程的機制,這些類似的命令都可能阻塞redis服務。
在這樣的背景下,scan命令誕生了,

SCAN cursor [MATCH pattern] [COUNT count]

scan 命令調用完後每次會返回2個元素,第一個是下一次迭代的cursor,第一次cursor會設置爲0,當最後一次scan 返回的cursor等於0時,表示整個scan遍歷結束了,第二個返回的是List,一個匹配的key的數組。

cursor: :我們知道redis是key:value形式的,所以在外層的數據結構,很容易讓我們聯想到hashMap類似的數據接口,hashMap最基本的形式是採用數組加鏈表的形式進行存貯的,而cursor就是最外的一維數組的索引,第一次使用scan,cursor設置爲0, 第二cursor設置成第一次返回cursor的值,如果cursor返回是0,表示迭代完畢。
match pattern: pattern支持redis的通配符,例如 * 表示匹配任意個字符,?匹配一個字符

count: 表示查找多少個數組元素,把匹配的結果,加入到返回的結果集中,count默認是10,可以根據實際需求自由的調整。

2. Jedis操作scan

Jedis jedis = new Jedis("127.0.0.1",6379);

		for(int i =0;i<20000;i++){
			jedis.set("20200606:"+i,i+"","NX","EX",600);
		}

		for(int i =20000;i<40000;i++){
			jedis.hset("hash:20200606:"+i,i+"",i+"");
			jedis.expire("hash:20200606:"+i,600);
		}


		String cursor = "0";
		ScanParams params = new ScanParams();
		params.count(1000);
		params.match("*20200606*");
		int count = 0;
		do{
			ScanResult<String> result = jedis.scan(cursor,params);
			System.out.println(result.getResult());
			if(result.getResult() != null){
				count += result.getResult().size();
			}
			cursor = result.getStringCursor();
		}while (!cursor.equals("0"));

		System.out.println("total size is " + count);

hscan ,sscan,zscan 都是類似,只是需要指定特定的key,迭代的是相關的內部的元素。

3.scan存在問題

scan命令從開始到結束一個完整的迭代,可能會返回重複的元素,(如果hash表縮容的話),scan命令相對於keys命令不會阻塞redis服務器,如果要查某些部分字符匹配的key,用scan是很合適的。但是scan返回的不一定是此刻返回的所有匹配的結果,可能多,也可能少,因爲整個數據可能在不斷的變化,而唯一有狀態的是cursor。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章