今天主要讲两个东西,一个是Redis的多个db机制,另一个是渐进式遍历。
首先来讲一下Redis的多个db机制
Redis中有个默认配置
databases 16
这个配置表示Redis启动后将有16个数据库,select 0 操作将切换到第一个数据库,select 15 将切换到最后一个数据库。每个数据库的数据之间没有任何关联,key都独立存在。
多个数据库起到了一个隔离key的作用,但是这里强烈不推荐使用将一个Redis服务的多个数据库供给多个服务共同使用,主要原因有在于Redis是单线程的,即使使用多个数据库,这些数据库的数据还是由一个线程去读写的,加入出现一个慢查询,将导致所有的服务都阻塞。
在Redis 3.0中已经弱化了这个功能了,Redis Cluster只允许使用 0 号数据库,即使又有多个数据库。并且部分Redis客户端根本就不支持这个切换数据库的操作。
所以我们可以将这个切换数据库的功能想象成官方想要提供的一个很炫酷的功能,然而发现并没有什么卵用,与其使用多个数据库不如多启动几个Redis实例。
下面来讲一下渐进式遍历
我们知道要查询Redis中所有key的数量可以使用 keys * 的操作,但是这个操作会遍历所有的key,在数据量大的情况下会阻塞整个Redis,那么如果需要查询Redis中所有key的数量我们就可以使用渐进式遍历的方式。
在Redis 2.8版本之后,提供了一个 scan 命令,和 key * 遍历所有key不同的是,scan命令会采用渐进式遍历的方式来解决 keys * 命令带来的阻塞问题。
scan命令的用法如下:
scan cursor [pattern] [count]
- cursor是一个游标,第一次从 0 开始,每次遍历完都会返回当前游标的值,直到游标的值为 0 表示遍历结束
- pattern是可选参数,是用来做模糊匹配的
- count是可选参数,表示每次遍历的个数,默认值 10
scan命令会返回两个部分,第一个部分是游标位置 ,第二个部分是这次遍历的key:
192.168.1.4:0>scan 0
1) "7"
2) 1) "list1"
2) "hh"
3) "hhh"
4) "bb"
5) "tt"
6) "set2"
7) "aa"
8) "set3"
9) "user1"
10) "set1"
那么如果要查询key总数量,就可以使用下面这段代码来实现(使用了Jedis客户端):
public static int countKeys() {
// 记录key总数
int count = 0;
// 游标位置
String cursor = "0";
while (true) {
// 渐进式遍历
ScanResult<String> scanResult = jedis.scan(cursor);
// 遍历结果
List<String> list = scanResult.getResult();
if (list != null && list.size() > 0) {
count += list.size();
}
cursor = scanResult.getStringCursor();
// 如果游标为0,遍历结束
if ("0".equals(cursor)) {
break;
}
}
return count;
}
当然了scan命令帮我们规避了 keys * 命令带来的阻塞问题,但也不是没有问题的。keys * 命令是一个原子操作,所以可以保证计算出来的结果是一定正确的,而使用scan命令去计算key总数的时候,使用了多次scan命令,如果在多次scan命令之间发生了key的增删变化,将导致遍历出来的结果将不是完全准确的,可能出现新增的key没有遍历到或者重复遍历同一个key的情况。
不过一般我们对于key总数的统计不需要那么精确,所以scan命令计算出来的结果产生的细微误差一般是在允许范围内的。
最后说一句,Redis是一个很强大的缓存工具,不仅仅是用来做key-value的缓存,还能做很多其他的事情,让我们慢慢深入去了解它。
喜欢这篇文章的朋友,欢迎扫描下图关注公众号lebronchen,第一时间收到更新内容。


3391

被折叠的 条评论
为什么被折叠?



