一 留意細節(jié)
摸清數(shù)據(jù)規(guī)模,即問清楚邊界
方法1: 利用keys pattern
KEYS pattern:查找所有符合給定模式pattern的key
eg: keys a* 找出所有以a開頭的key
使用keys對線上業(yè)務(wù)的影響
- KEYS指令一次性返回所有匹配的key
- 鍵的數(shù)量過大會使服務(wù)卡頓
方法2:SCAN cursor match pattern count countnum
eg:scan 0 match *a count 10 從游標為0
- 基于游標的迭代器胚泌,需要基于上一次的游標延續(xù)之前的迭代過程
- 以0作為游標開始一次新的迭代畸颅,直到命令返回游標0完成一次遍歷
- 不保證每次執(zhí)行都返回某個給定數(shù)量的元素单山,支持模糊查詢
- 一次返回的數(shù)量不可控揉阎,只能大概率符合count參數(shù)
二.關(guān)于scan的使用
下面提供兩個我自己包裝的scan,一個是hash里模糊取key,另外一個是直接string key的模糊取
@Override
@SuppressWarnings("unchecked")
public <T> Map<String, T> hScan(String key, String pattern) {
final Map<String, T> scanResult = Maps.newHashMap();
try (Cursor<Map.Entry<Object, Object>> cursor = template.opsForHash().scan(key, ScanOptions.scanOptions()
.count(Integer.MAX_VALUE)
.match(pattern)
.build())) {
while (cursor.hasNext()) {
final Map.Entry<Object, Object> entry = cursor.next();
scanResult.put(String.valueOf(entry.getKey()), (T) entry.getValue());
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return scanResult;
}
@Override
public Set<String> scan(String pattern) {
return template.execute((RedisCallback<Set<String>>) connection -> {
Set<String> keysTmp = Sets.newHashSet();
try (Cursor<byte[]> cursor = connection.scan(new ScanOptions.ScanOptionsBuilder()
.count(Integer.MAX_VALUE)
.match(pattern)
.build())) {
while (cursor.hasNext()) {
keysTmp.add(new String(cursor.next()));
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return keysTmp;
});
}
三.關(guān)于scan的坑
- COUNT 選項只是對增量式迭代命令的一種提示(hint),不能代表返回的個數(shù)执俩,它只是限定服務(wù)器單次遍歷的字典槽位數(shù)量(約等于)荆秦。
- count要根據(jù)掃描數(shù)據(jù)量大小而定篱竭,Scan雖然無鎖,但是也不能保證在超過百萬數(shù)據(jù)量級別搜索效率步绸;count不能太小掺逼,網(wǎng)絡(luò)交互會變多,count要盡可能的大瓤介。在搜索結(jié)果集1萬以內(nèi)吕喘,建議直接設(shè)置為與所搜集大小相同