redis的高级特性有哪些

53次阅读
没有评论

共计 5501 个字符,预计需要花费 14 分钟才能阅读完成。

自动写代码机器人,免费开通

这篇文章主要介绍了 redis 的高级特性有哪些,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让丸趣 TV 小编带着大家一起了解一下。

Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。

1.redis 发布订阅模式

Redis 除了提供像 list 的这种的消息队列模式,还提供了一组命令实现发布 / 订阅模式。例如微博,公众号等都是可以由此实现。

redis 的高级特性有哪些

1.2 订阅频道

发布者需要将消息发送到一个地方,让订阅者可以订阅消息,这个地方就是频道(channel)。订阅者可以订阅一个或者多个频道,所有订阅了这个频道的订阅者都会受到这条消息。

开启两个客户端进行测试

客户端 1   订阅 channel1
127.0.0.1:6379  subscribe channel1
Reading messages... (press Ctrl-C to quit)
1)  subscribe 
2)  channel1 
3) (integer) 1
客户端 2   发布一则消息
127.0.0.1:6379  publish channel1 test
(integer) 1
客户端 1   订阅消息
127.0.0.1:6379  subscribe channel1
Reading messages... (press Ctrl-C to quit)
1)  subscribe 
2)  channel1 
3) (integer) 1
1)  message 
2)  channel1 
3)  test

1.2 按规则订阅

支持?和 * 占位符。? 代表一个字符,* 代表 0 个或者多个字符。

启动四个 redis-cli,一个作为消息的发布者,另外三个作为订阅者。
订阅者 1:订阅体育相关

psubscribe *sport

订阅者 2:订阅新闻相关

psubscribe news*

订阅者 3:订阅天气相关

psubscribe new weather*

发布者:

publish news-sport Kobe
publish news-music jaychou
publish news-weather rain

此时订阅者 1 将会收到 Kobe,订阅者 2 将会收到全部信息,订阅者 3 将会收到 rain。

redis 的高级特性有哪些

2.redis 事务

2.1 为什么要用事务

我们都是知道 redis 的单个命令是原子性的,但是如果需要用多个命令作为一个不可分割的操作序列,就需要用到事务。
例如使用 setnx 实现分布式锁,我们一般先 set,然后对 key 设置 expire,防止 del 发生异常时候锁不会释放,业务处理完之后在 del,这三个操作我们就希望作为一组命令执行。
redis 事务有两个特点:

按照进入队列的顺序执行

不会受到其他客户端请求影响

redis 的事务设计四个命令:multi(开启事务),exec(执行事务),dicard(取消事务),watch(监视)

2.2 事务的用法

转账场景 A 和 B 各有 100 元,A 向 B 转账 10 元,A 减 10 元,B 加 10 元

127.0.0.1:6379  set A 100
127.0.0.1:6379  set B 100
127.0.0.1:6379  multi
127.0.0.1:6379  decrby A 10
QUEUED
127.0.0.1:6379  incrby B 10
QUEUED
127.0.0.1:6379  exec
1) (integer) 90
2) (integer) 110
127.0.0.1:6379  get A
127.0.0.1:6379  get B
 110

通过 multi 命令开启事务。事务不能嵌套,多个 multi 命令效果一样的
使用 multi 开启事务之后,客户端向服务器发送多条命令,这些命令并不会立即被执行,而是会被放到一个队列中,当 exec 命令调用之后,队列中的命令才会被执行。
我们可以使用 discard 来清空事务队列。

127.0.0.1:6379  multi
127.0.0.1:6379  set k1 1
QUEUED
127.0.0.1:6379  set k2 2
QUEUED
127.0.0.1:6379  discard
127.0.0.1:6379  get k1
(nil)
127.0.0.1:6379  get k2
(nil)

当我们执行事务的时候出现了问题会回滚吗?

exec 之前发生错误(如指令语法错误)

127.0.0.1:6379  clear
127.0.0.1:6379  multi
127.0.0.1:6379  set name test
QUEUED
127.0.0.1:6379  hset user lisi
(error) ERR wrong number of arguments for  hset  command
127.0.0.1:6379  exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379  get name
(nil)

exec 之后发生错误(对同一个 key 使用不同数据类型的命令)

127.0.0.1:6379  multi
127.0.0.1:6379  set k1 1
QUEUED
127.0.0.1:6379  hset k1 a b
QUEUED
127.0.0.1:6379  exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379  get k1
 1

通过上面操作,我们可以知道当事务在 exec 前发生错误,将会回滚所有操作;如果在 exec 后发生错误,只有错误的命令不会被执行。
为什么 redis 在一个事务中存在错误不进行回滚呢?
我们从上面操作可以看出,redis 只有在指令语法错误的时候进行回滚,而指令操作错误是有开发人员导致的 bug,例如:你对一个 int 类型进行 +1,然后不小心 +2,或者对一个 string 类型进行 +1,回滚是不适用的

2.3 watch 指令

它可以为 Redis 事务提供 CAS 乐观锁操作,也就是多个线程更新某个变量的时候,会让旧值跟内存地址相比较,如果相等,则更新为新值。
我们可以用 watch 监视一个或者多个 key,如果开启事务之后,至少有一个被监视的 key 在 exec 执行之前被修改,则会取消整个事务。

首先 client 1 执行 watch 监视 money 这个 key,并开启事务对 money 进行增加 100

127.0.0.1:6379  set money 1000
127.0.0.1:6379  watch money
127.0.0.1:6379  multi
127.0.0.1:6379  incrby money 100
QUEUED

在事务结束之前,在 client 2 对 money 进行减少 100

127.0.0.1:6379  decrby money 100
(integer) 900

此时 client 1 结束事务,money 的值并没有被增加,反而减少,说明事务的修改失效

127.0.0.1:6379  exec
(nil)
127.0.0.1:6379  get money
 900

3. Lua 脚本

Lua 脚本是一种轻量级脚本语言,C 语言编写的,跟存储过程有点类似。为啥要用 lua 脚本呢?

一次发送多个命令,减少网络开销 Redis 会将脚本作为一个整体执行,保证原子性(可用此方式替换事务)脚本复用,便于多个客户端完成相同的逻辑。

3.1 使用

我们可以使用以下命令进行调用 lua 脚本

eval script numkeys [key1 key2 key3 ....] [arg1 arg2 arg3 ....]

eval 执行 lua 脚本

script 代表 lua 脚本的内容

numkeys key 的数量

[key1 key2 key3 ….] 键名参数,表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问(KEYS[1],KEYS[2],以此类推)。

[arg1 arg2 arg3 ….] 全局变量,可以在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似(ARGV[1]、ARGV[2],诸如此类)

来个简单的例子

127.0.0.1:6379  eval  return {KEYS[1],ARGV[1],KEYS[2],ARGV[2]}  2 key1 key2 val1 val1
1)  key1 
2)  val1 
3)  key2 
4)  val1 
127.0.0.1:6379  eval  return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}  2 key1 key2 val1 val1
1)  key1 
2)  key2 
3)  val1 
4)  val1

在 lua 脚本如何调用 redis 命令呢?
我们可以使用 redis.call(command, key [param1, param2…])进行操作

commond redis 的命令,如 set,get 等 key 被操作的键 [param1, param2…] 表示给 key 的参数

127.0.0.1:6379  eval  redis.call(mset ,KEYS[1],ARGV[1],KEYS[2],ARGV[2])  2 name age lisi 18
(nil)
127.0.0.1:6379  mget name age
1)  lisi 
2)  18

以上命令等价于 mset name lisi age 18, key 的数量为 2,2 后面两个值为 key,在之后就是 args

直接在 redis-cli 中写 lua 脚本不够方便,通常我们会把脚本放在文件中,然后执行这个文件
我们在一个目录下新建一个 test.lua 的脚本,填写以下内容后执行。

root@VM-0-5-centos src]# mkdir testlua
[root@VM-0-5-centos src]# cd testlua/
[root@VM-0-5-centos testlua]# ll
total 0
[root@VM-0-5-centos testlua]# touch test.lua
[root@VM-0-5-centos testlua]# vim test.lua
redis.call(set ,KEYS[1],ARGV[1])
return redis.call(get ,KEYS[1])
[root@VM-0-5-centos testlua]# redis-cli --eval test.lua 1 myname , Armin
 Armin

值得注意的是 key 和 arg 之间需要加上空格逗号空格(myname , Armin)

3.2 缓存 lua 脚本

之所以需要缓存 lua 脚本,这是因为每次调用的时候都将整个脚本传给 redis 服务端,会产生较大的网络开销。为了解决这个问题,Redis 提供了 evalsha 命令,让开发人员通过脚本内容的 SHA1 摘要执行脚本。

那么怎么将生成这个 SHA1 并将脚本内容加载到缓存呢,这就用到 script load 命令去计算脚本的 SHA1 摘要并记录脚本到缓存中,执行 evalsha 时,redis 会根据提供的摘要去脚本缓存找到对应脚本内容,如果找到则执行,否则返回错误提示:“NOSCRIPT No matching script. Please use EVAL”

127.0.0.1:6379  script load  return  Hey boy 
 3760855b303510c83f0be2e8acfb0be64113ae6e 
127.0.0.1:6379  evalsha 3760855b303510c83f0be2e8acfb0be64113ae6e 0
 Hey boy 
127.0.0.1:6379  script exists 3760855b303510c83f0be2e8acfb0be64113ae6e // 判断是否存在
1) (integer)

Redis 还给 lua 脚本的执行提供了超时时间,默认的超时时间为 5s,超过 5s 之后 redis 会接受其他命令但是会返回一个 BUSY 的错误
可在 redis.conf 中修改指定参数

lua-time-limit 5000

Redis 提供了个 script kill 的命令来终止正在运行的脚本

127.0.0.1:6379  set name lisi
(error) BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.
127.0.0.1:6379  script kill
127.0.0.1:6379  set name lisi
OK

如果数据进行了修改操作,将无法使用 script kill 终止脚本,因为违反了原子性。此时只能通过 shutdown nosave 来强行终止 redis。
shutdown nosave 和 shutdown 的区别在于 shutdown nosave 不会进行持久化
操作,意味着发生在上一次快照后的数据库修改都会丢失。

感谢你能够认真阅读完这篇文章,希望丸趣 TV 小编分享的“redis 的高级特性有哪些”这篇文章对大家有帮助,同时也希望大家多多支持丸趣 TV,关注丸趣 TV 行业资讯频道,更多相关知识等着你来学习!

向 AI 问一下细节

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-12-16发表,共计5501字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)