redis常用高级功能小记(下篇)

上一篇说了redis的管道功能,并延伸了里边的一些linux基本操作,这一篇就把上一篇开篇讲的几个高级功能补全,上一篇说准备记录的高级功能有:

管道
事务
发布/订阅
过期
布隆过滤器

事务

除了管道,redis还有事务,可以一定程度上保证一组操作的原子性。主要用到multiexecwatch以及unwatch这些关键词。

一个事务以multi开头,然后可以进行很多操作指令,直到输入了exec后正式执行。

假如有两个客户端,A客户端先输入multi,然后输入了一连串的redis操作,之后B客户端在输入multi,然后也输入了一串操作,但是B客户端先执行了exec,A客户端后执行exec,实际上最终先执行的会是B的操作。

当然了,更准确的说法是,上边的先后指的是服务端接收到的时间,由于网络等原因,先输入不代表先接收。

一个事务操作示例如下:

1
2
3
4
5
6
7
multi

set k1 111

get k1

exec

除了上边这种操作外,事务还可以配合watch使用,watch用来监听某个或者多个key的变化,如果监听过程中相应的key值发生了改变,则接下来执行事务将会失败,例如:

client1先监听一个key,然后开启事务,再进行一些操作,但是不执行exec

1
2
3
4
5
6
7
watch k1

multi

set k1 111

get k1

然后client2改变key的值

1
set k1 222

接下来回到client1执行exec,就会发现返回结果nil,实际就是watch监听的数据发生了改变,导致整个事务失败。

发布/订阅

在说redis基础数据结构的时候,list中有一个异步阻塞功能,使用blpopbrpop命令可以阻塞客户端,直到取到结果为止。

这个功能在一定程度上可以实现类似消息监听和消费,只不过一取到数据就结束了。

而redis本身实现了真正的消息发布订阅功能,使用publishsubscribe命令进行操作,例如:

消费端使用subscribe监听某个channel通道:

1
subscribe channel1

重开一个命令行窗口,使用publish向上边的channel通道发布消息:

1
publish channel1 hello

发布之后,上边第一个窗口就会立即接收到消息并打印出来。

虽然redis带有发布订阅功能,但是却又一个问题存在,也就是之后消费端订阅之后的,或者说正开着订阅的情况下,消息才会接收到,如果客户端断开连接,也只能接收重连之后再重新订阅的消息,断线过程中的消息依然会丢掉。

过期

redis虽然可以持久化存储,但是实际上多数情况下都是被用作缓存,缓存也就是暂时存储,在这方面redis提供了一个很方便的功能,即设置超时。

设置超时方式有两种,一种是在设值的时候同时设置超时时间,这个方式只适用于string类型,其他类型的操作暂时没有此选项。

另一种是使用expire功能对需要设置超时的key设置超时时间,这个就是通用的,可以对任何redis支持的类型设置超时。

对于string类型数据直接设置超时时间,会有两个参数可选,一个是ex一个是px,其中ex代表秒为单位,px代表毫秒为单位,例如:

1
set k1 111 ex 2000

上边的操作会把k1在redis中保存2000秒,而下边的操作则只会保存2秒:

1
set k2 111 px 2000

但是对于通用的expire来说,就不支持毫秒参数了,后边只能是秒为单位,例如:

1
expire k1 2000

这里的2000代表的也是2000秒,而不是2000毫秒。

redis超时需要注意的是,缓存一个重要的作用实际就是为了减少数据库的io操作,又因为内存资源问题,所以正常缓存的应该是热数据,经常使用到的数据就是热数据。

所以可能会有人觉得是不是经常被读取的数据,会自动延长超时时间,而实际上读数据并不会延长改变过期时间。

重新写数据的时候,是会改变过期时间的,如果重新给了过期时间则变成新的过期时间,如果没有给新的过期时间则会变成永久,直到redis服务宕机,另外,对数据进行计算也不会改变过期时间。

布隆过滤器

上边也提到了,redis的一大作用就是缓存热数据,从而减少数据库的频繁io,就相当于数据库之前的一道屏障,进而提升系统的整体性能以及可用性。

那么在很多实际业务中,就会有缓存查不到就去查数据库的逻辑,以保证业务的整体性和可靠性。

但是这样一来,就又会存在redis缓存中没有,数据库中实际也没有,这种场景就称作redis缓存穿透,如果有大量的这种请求,可想而知数据库就很容易出现问题,而布隆过滤器就刚好可以一定程度上解决缓存穿透这个问题。

布隆过滤器不是redis的基础功能,而是一个额外的模块,若要使用,就需要先下载和挂在,大致步骤如下

1
2
3
4
5
6
7
wget https://github.com/RedisBloom/RedisBloom/archive/master.zip

unzip master.zip

make

redis-server --loadmodule /opt/soft/rdisbloom.so

上述第一行应该不用多说,就是linux基本的wget下载,第二步解压zip文件应该也不需多说,第三步是对于源码的编译更不用多说。

第四步是关键,这里是启动redis服务的时候挂在布隆过滤器,需要注意的是,后边的so文件,就是make生成的,具体的路径要视情况而定,并且一定要写绝对路径。

当然了,这个内容也可以配置到redis的配置文件中,就不需要每次启动都手动配置。

有了上边的操作,就可以使用布隆过滤器了,关键的操作有三个,分别是bf.addbf.existsbf.reserve,add的作用是往过滤器中添加内容,exists用来判断是否存在,而reserve可以设置错误率和预计容量以自定义处理,示例如下:

1
2
3
4
5
bf.add filter1 111

bf.exists filter1 111

bf.reserve filter2 0.01 100

上边的filter1和filter2可以理解为过滤器的名称,使用exists判定的时候,过滤器中有的就返回1,没有的就返回0.

对于reserve,除了过滤器名字之外,还需要给一个错误率,一个预计容量,错误率越低,消耗的存储空间越大,实际数据超出了预计容量,误判率就会升高。

同时还要注意的是,reserve只能用于还不存在的过滤器上,对已有的过滤器执行这个操作会抛出异常。

布隆过滤器底层存储像bitmap一样使用字节位存储,就存在可能多个数据占用同一个位,因而也导致了一定的误判率,误判结果就是:布隆过滤器返回不存在的一定不存在,布隆过滤器返回存在的不一定存在。

布隆过滤器的数据存储,使得空间公用,大大节省了存储空间,但是也有共用,就导致不允许删除过滤器中的元素,因此布隆顾虑器也是找不到删除元素操作的,根据网上的说法,布谷过滤器可以处理这一类的问题,这里就暂停拓展。

推荐文章