Redis中的Pub/Sub、事务、索引、管道、脚本

Pub/Sub

定义
  • 实现生产者 - 消费者模型
  • 生产者不直接将消息发布给特定的消费者,而是发布到频道中,而不关注消费者
  • 消费者订阅一个或多个频道,只接收感兴趣的消息,而不关注生产者
特点
  • 可靠性:消息只会被传递一次,如果消费者接收消息后无法处理消息,该消息将永久丢失。如果想要更强的可靠性,可以使用Redis的Streams,流中的消息是持久化的,并支持重新传递
  • 作用域:Pub/Sub 与键空间无关,在 数据库10 上发布消息,会被 数据库1 上的消费者接收到
命令(Commands | Docs
  • SUBSCRIBE channel1 channel2 ...:订阅一个或多个频道。
    • 消费者会按照消息发布的顺序接收消息(因为Redis是单线程模型)
  • PUBLISH channel message:发布消息到频道中
  • PSUBSCRIBE news.*:订阅匹配的频道,支持通配符风格。
    • 通配符:
      • *:匹配任意多个字符
      • ?:匹配单个任意字符
      • […]:匹配**"[]"内的任意一个**字符
    • 如果消费者订阅了多个匹配同一频道的模式,可能会多次收到同一条消息
消息格式
  • 订阅消息:“subscribe 频道名称1 当前订阅的频道数量 频道名称2 当前订阅的频道数量 …”
  • 退订消息:“unsubscribe 频道名称1 当前订阅的频道数量 频道名称2 当前订阅的频道数量 …”
  • 接收的消息:“message 频道名称 消息内容”
  • 根据匹配模式接收的消息:“pmessage 匹配模式 频道名称”

事务

定义
  • 定义:Redis 事务是一组命令的集合,这些命令会被一次性、按顺序执行。事务使用 MULTI 命令开始,用 EXEC 命令提交执行。

  • 机制:开启事务 -> 入队命令 -> 提交事务

    1. MULTI 命令开始事务
    2. 后续所有命令被排队(并没有立即执行
    3. EXEC 命令执行时,才依次执行排队的命令。
命令:命令 | 文档 — Commands | Docs
命令说明
MULTI开启事务
EXEC提交事务,此时才执行MULTI 之后入队的所有命令
DISCARD取消事务,丢弃所有已排队的命令
WATCH key1 key2 ...监视一个或多个键,在事务执行前(EXEC,如果这些键被其他客户端修改,则事务失败
UNWATCH取消监视
特点
特性是否支持说明
命令打包执行所有命令按顺序依次执行,不会被其他客户端打断。
原子性不支持回滚。若中间某命令执行失败,其它命令仍继续执行。
隔离性没有类似数据库的事务隔离级别,读的是实时值,除非配合 WATCH
并发控制✅(手动)可用 WATCH 实现乐观锁控制。
问题
  • 为什么Redis不具备像Mysq那样完整的事务机制?

    因为Redis执行所有命令都在一个主线程中,天然避免了多线程的写并发冲突问题,因此不需要额外的调度机制(MVCC,锁)

  • 为什么Redis事务执行过程中,键会被其他客户端修改?

    Redis事务在**"命令入队阶段"时,Redis 不会阻止其它客户端修改其中使用的键,所以你以为事务内部用的是旧值,但实际上外部已经修改了。因此Redis 提供了一个简洁的乐观锁机制**:

    1. WATCH 监视某些键
    2. 如果在 MULTIEXEC 之间这些键被修改过
    3. EXEC 执行前会提前失败,返回 null
    4. 此时可以选择重试事务

索引(全文索引,Full Text)

定义
  • SET user:1001 "{\"name\": \"Alice\", \"age\": 25}"
  • 在Redis中,主键索引就是每个键,比如这里的user:1001
  • 这里的索引指二级索引,如果想通过 name = "Alice"age = 25 来查询用户,就需要二级索引。因为Redis 本身是键值存储,默认无法通过 value 中的字段来查找,所以索引主要用于HASHJSON结构
命令
  • 创建索引

    # 创建一个名为 idx:bicycle 的全文索引
    FT.CREATE idx:bicycle 
    # 表示索引的数据是JSON格式的文档,也可以选择HASH
    ON JSON 
    # 表示这个索引只会应用于以 "bicycle:" 开头的 key。1 的意思是后面有1个前缀。
    PREFIX 1 bicycle:
    # 设置文档的默认分数,用于相关性排序(不常用,可省略)
    SCORE 1.0 
    # 定义要索引的字段、字段类型和相关参数
    SCHEMA 
    # path为$.brand,命名为 brand,类型是 TEXT,权重1.0(用于相关性排序)。
    $.brand AS brand TEXT WEIGHT 1.0 
    $.model AS model TEXT WEIGHT 1.0 
    $.description AS description TEXT WEIGHT 1.0 
    $.price AS price NUMERIC 
    $.condition AS condition TAG SEPARATOR ,
    
  • 使用索引进行查询:查询数据 | 文档 — Querying data | Docs

    • 通配符查询:FT.SEARCH "idx:bicycle" "*" LIMIT 0 10

      查询idx:bicycle索引下的所有文档

    • 根据某个字段查询:

      FT.SEARCH “idx:bicycle” “@model:jugger” LIMIT 0 10

      查询 model 字段中包含 jugger 该词的文档

管道(Pipeline)

  • 定义:Redis 是基于客户端-服务端模型和请求/响应协议的 TCP 服务。通常,客户端发送请求后会阻塞等待响应。通过管道技术,客户端可在未收到响应前连续发送多个请求,最后一次性读取所有响应,提高通信效率。
  • 注意:管道化请求中的命令按发送顺序执行,但在这些命令之间可能会与其他客户端的命令交错执行。
  • 返回结果:执行完管道后,Redis 会把所有命令的回复按顺序打包成一个“回复数组”返回给客户端。每一条命令对应一条回复:
    • 返回值:该命令执行后的返回值
    • 错误回复:如果该条命令执行失败,就会在对应位置放一个错误对象或消息

脚本

  • 定义:Redis 允许用户在服务器上上传并执行 Lua 脚本。Redis 保证了脚本的原子执行。在执行脚本期间,服务器在脚本的整个运行时间内都会被阻塞,不会被打断。当Redis执行脚本中的某个命令失败时不会进行回滚。

  • 使用:

    • 普通使用:EVAL "return 'Hello, scripting!'" 0

      "0"表示无参数

    • 带参数使用:

      redis> EVAL "return { KEYS[1], KEYS[2], ARGV[1], ARGV[2], ARGV[3] }" 2 key1 key2 arg1 arg2 arg3
      1) "key1"
      2) "key2"
      3) "arg1"
      4) "arg2"
      5) "arg3"
      

      "2"表示KEYS参数的数量

    • 通过redis.call(操作类型、键参数列表、值参数列表)在脚本中调用Redis命令:

      EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 foo bar

      也可以使用redis.pcall(),区别在于 redis.call() 函数遇到的错误会直接返回给执行该命令的客户端。而 redis.pcall() 函数遇到的错误会返回给脚本的执行上下文,以便可能提前进行处理。

  • 缓存:

    • 介绍:使用 EVAL 执行的每个脚本都会存储在服务器维护的一个专用缓存中,因此可以通过缓存来减少上传脚本的时间。当服务器重启或通过 SCRIPT FLUSH 显式清除时,缓存会被清空。
    • 使用:
      • SCRIPT LOAD "脚本内容":将脚本加载到服务器中,并返回其SHA1
      • EVALSHA sha1 0:通过SHA1值执行缓存中的脚本,"0"表示无参数
      • SCRIPT FLUSH:强制清空脚本缓存
      • SCRIPT EXISTS sha1 [sha1 ...]:通过SHA1值判断每个脚本是否被缓存,会返回一个由1和0构成的数组
      • SCRIPT KILL:中断长时间运行的脚本
  • 主从同步:

    • 在集群环境中,Redis 确保所有由脚本执行的写操作也会发送到从服务器以保持一致性。
    • 模式:
      • 逐字复制:主节点将脚本的源代码发送给从节点。从节点再运行脚本,以节省带宽。它要求所有写脚本必须是确定的,即脚本的执行结果不会因为环境的改变而改变。
      • 效果复制:主节点将脚本的写命令发送给从节点。从节点再运行这些命令,可能在网络流量方面更长,但避免了重新计算脚本和脚本本身的不确定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艾露z

谢谢侬!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值