• Redis-04独立功能的实现


    1、发布与订阅

    介绍:

    • Redis的发布与订阅功能由PUBLISH、SUBSCRIBE、PSUBSCRIBE等命令组成。
    • 通过SUBSCRIBE命令,客户端可以订阅一个或多个频道,成为这些频道的订阅者(subscriber)
    • 每当有其他客户端向被订阅的频道发送消息(message)时,频道的所有订阅者都会收到这条消息

    常用命令:

    • 订阅频道

      • SUBSCRIBE

      • 当一个客户端执行SUBSCRIBE命令订阅某个或某些频道的时候,这个客户端与被订阅频道之间就建立起了一种订阅关系

    • 退订频道

      • UNSUBSCRIBE

      • 当一个客户端退订某个或某些频道的时候,服务器将从pubsub_channels中解除客户端与被退订频道之间的关联

    • 订阅模式

      • PSUBSCRIBE
    • 退订模式

      • PUNSUBSCRIBE
    • 发送消息

      • PUBLISH

        • 将消息message发送给频道channel
    • 查看订阅信息

      • PUBSUB

        • PUBSUB CHANNELS [pattern]

          • 用于返回服务当前被订阅的频道,pattern参数可选,用于匹配指定频道
        • PUBSUB NUMSUB

          • 接受任意多个频道作为输入参数,并返回这些频道的订阅者数量
        • PUBSUB NUMPAT

          • 用于返回服务器当前被订阅模式的数量

    订阅频道

    有A、B、C三个客户端都执行了命令:【订阅频道】

    # 客户端订阅news.it频道
    SUBSCRIBE "news.is"
    
    • 1
    • 2

    向频道中发送消息

    # 向 “news.is” 频道中发送 Hello Redis
    PUBLISH "news.is" "Hello Redis"
    
    • 1
    • 2

    执行效果如下:

    pPjugdxpng

    频道news.is与ABC 三个订阅者

    pPjK61gpng

    向news.is 频道发送消息:

    pPjK5NVpng

    2、事务

    Redis通过MULTI、EXEC、WATCH等命令来实现事务(transaction)功能。

    事务支持:将多个命令请求打包,然后一次性、按顺序地执行多个命令的机制,并且在事务执行期间,保证事务之间的隔离性

    例如以下简单事务执行流程:

    # 通过MULTI开启一个事务
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379(TX)> SET "name" "PP419"
    QUEUED
    127.0.0.1:6379(TX)> GET "name"
    QUEUED
    127.0.0.1:6379(TX)> SET "author" "AtwoodPa"
    QUEUED
    127.0.0.1:6379(TX)> GET "author"
    QUEUED
    # EXEC 结束并提交(commit)事务
    127.0.0.1:6379(TX)> EXEC
    1) OK
    2) "PP419"
    3) OK
    4) "AtwoodPa"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.1、事务的实现

    一个事务从开始到结束会经历三个阶段

    1. 事务开始

    2. 命令入队

    3. 事务执行

    2.1.1、事务开始

    MULTI命令的执行标志着事务的开始,MULTI命令可以将执行该命令的客户端从非事务状态切换到事务状态,这一切换是通过在客户端状态的flags属性中打开REDIS_MULTI标识来完成的。

    MULTI命令实现的伪代码如下:

    def MULTI() :
        # 打开事务标识
        client.flags |= REDIS_MULTI
    
        # 返回OK回复
        replyOK()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.1.2、命令入队

    当一个客户端处于非事务状态时,该客户端发送的命令会被服务器立即执行。

    但是,当一个客户端切换到事务状态之后,服务器会根据这个客户端发来的不同命令执行不同的操作:

    • 立即执行

      • EXEC

      • DISCARD

      • WATCH

      • MULTI

    • 存入队列

      • 除了上面四种立即执行命令之外,服务器不会立即执行命令

      • 将这个命令放入一个事务队列中,然后向客户端返回QUEUED

        • 事务队列以先进先出(FIFO)的方式保存入队命令

        • 较先入队的命令会被放到数组的前面

        • 较后入队的命令会被放到数组的后面

    2.1.3、事务执行

    当一个处于事务状态的客户端向服务器发送EXEC命令时,这个EXEC命令将立即被服务器执行

    服务器会遍历客户端的事务队列,执行队列中保存的所有命令,最后将执行命令所得的结果全部返回给客户端

    3、Lua脚本

    使用lua+aop实现限流:https://www.cnblogs.com/atwood-pan/p/17418814.html

    通过在服务器中嵌入Lua环境,Redis客户端可以使用Lua脚本,直接在服务端原子地执行多个Redis命令。

    Redis使用串行化的方式来执行Redis命令,在任何特定时间内,最多都只会有一个脚本能够被放进Lua环境中运行,所以整个Redis服务器只需要创建一个Lua环境即可。

    Redis中与Lua环境进行协作有两个组件:

    • 执行组件

      • 该组件是负责执行Lua脚本中包含的Redis命令的伪客户端

        • redis.call

        • redis.pcall

      • 了解服务器与Lua环境的交互过程

    • 存储组件

      • 该组件时负责保存传入服务器的Lua脚本的脚本字典

      • 理解SCRIPT EXISTS命令和脚本复制功能的实现原理

    脚本管理命令:

    • SCRIPT FLUSH

      • 用于清除服务器中所有和Lua脚本有关的信息,会释放并重建lua_scripts字典,关闭现有的Lua环境并重新创建一个新的Lua环境
    • SCRIPT EXISTS

      • 根据输入的SHA1校验和,检查和对应的脚本是否存在于服务器中
    • SCRIPT LOAD

      • 在Lua环境中为脚本创建相对应的函数,然后再将脚本保存到lua_scripts字典里面,之后用于载入脚本
    • SCRIPT KILL

      • 结合lua-time-limit配置选项,停止未执行过任何写入操作超时运行的脚本

    4、排序

    Redis的SORT命令可以对列表键、集合键或者有序集合键的值进行排序

    列表键排序:

    # 向列表中插入5个元素
    127.0.0.1:6379> RPUSH numbers 5 3 1 4 2
    (integer) 5
    # 按插入顺序排列的列表元素
    127.0.0.1:6379> LRANGE numbers 0 -1
    1) "5"
    2) "3"
    3) "1"
    4) "4"
    5) "2"
    # 按值从小到大有序排列的列表元素
    127.0.0.1:6379> SORT numbers
    1) "1"
    2) "2"
    3) "3"
    4) "4"
    5) "5"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    对包含字符串的集合键进行排序:

    # 添加7个元素
    127.0.0.1:6379> SADD alphabet a b c d e f g
    (integer) 7
    # 乱序排序的集合元素
    127.0.0.1:6379> SMEMBERS alphabet
    1) "c"
    2) "a"
    3) "e"
    4) "b"
    5) "d"
    6) "g"
    7) "f"
    # 排序后的集合元素
    127.0.0.1:6379> SORT alphabet ALPHA
    1) "a"
    2) "b"
    3) "c"
    4) "d"
    5) "e"
    6) "f"
    7) "g"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    使用BY命操作有序集合的权重:

    # 向有序集合中,添加三个带有权重的值
    127.0.0.1:6379> ZADD test-result 3.0 jack 3.5 peter 4.0 tom
    (integer) 3
    # 按元素的分值排列
    127.0.0.1:6379> ZRANGE test-result 0 -1
    1) "jack"
    2) "peter"
    3) "tom"
    # 为各个元素设置序号
    127.0.0.1:6379> MSET peter_number 1 tom_number 2 jack_number 3
    OK
    # 使用BY命令,以序号为权重,对有序集合中的元素进行排序
    127.0.0.1:6379> SORT test-result BY *_number
    1) "peter"
    2) "tom"
    3) "jack"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    chatgpt 4V 识图功能
    Spark SQL中的正则表达式应用
    Spring cloud day(8) stream
    【算法刷题】第一篇——哈希
    PyTorch笔记 - LSTM(Long Short-Term Memory) 和 LSTMP(Projection)
    部署Node.js环境
    Eclipse插件开发demo
    SpringBoot集成百度AI实现人脸识别
    Vue在外部配置打包文件夹名称和url地址前缀
    八股系列 Flink
  • 原文地址:https://blog.csdn.net/weixin_45688141/article/details/133711378