zoukankan      html  css  js  c++  java
  • Redis发布订阅、事务、脚本

    Redis 发布订阅

      Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。

      Redis 客户端可以订阅任意数量的频道。

      下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:

    pubsub1

      当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:

    pubsub2

    实例

    以下实例演示了发布订阅是如何工作的。在实例中创建了订阅频道名为 redisChat:

    redis 127.0.0.1:6379> SUBSCRIBE redisChat
    
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "redisChat"
    3) (integer) 1

    现在,重新开启个 redis 客户端,然后在同一个频道 redisChat 发布两次消息,订阅者就能接收到消息。

    redis 127.0.0.1:6379> PUBLISH redisChat "Redis is a great caching technique"
    
    (integer) 1
    
    redis 127.0.0.1:6379> PUBLISH redisChat "Learn redis by runoob.com"
    
    (integer) 1
    
    # 订阅者的客户端会显示如下消息
    1) "message"
    2) "redisChat"
    3) "Redis is a great caching technique"
    1) "message"
    2) "redisChat"
    3) "Learn redis by runoob.com"
    # 1. 订阅一个或多个符合给定模式的频道。
    PSUBSCRIBE pattern [pattern ...] 
    '''
    返回值:接收到的信息。
    redis 127.0.0.1:6379> PSUBSCRIBE mychannel
    Reading messages... (press Ctrl-C to quit)
    1) "psubscribe"
    2) "mychannel"
    3) (integer) 1
    '''
    
    # 2.查看订阅与发布系统状态。
    PUBSUB subcommand [argument [argument ...]] 
    '''
    返回值:由活跃频道组成的列表。
    redis 127.0.0.1:6379> PUBSUB CHANNELS
    (empty list or set)
    '''
    
    # 3.将信息发送到指定的频道。
    PUBLISH channel message 
    '''
    返回值:接收到信息的订阅者数量。
    redis 127.0.0.1:6379> PUBLISH mychannel "hello, i m here"
    (integer) 1
    '''
    
    # 4.退订所有给定模式的频道。
    PUNSUBSCRIBE [pattern [pattern ...]] 
    '''
    返回值:这个命令在不同的客户端中有不同的表现。
    redis 127.0.0.1:6379> PUNSUBSCRIBE mychannel 
    1) "punsubscribe"
    2) "a"
    3) (integer) 1
    '''
    
    # 5.订阅给定的一个或多个频道的信息。
    SUBSCRIBE channel [channel ...] 
    '''
    返回值:接收到的信息
    redis 127.0.0.1:6379> SUBSCRIBE mychannel 
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "mychannel"
    3) (integer) 1
    1) "message"
    2) "mychannel"
    3) "a"
    '''
    
    # 6.指退订给定的频道。
    UNSUBSCRIBE [channel [channel ...]] 
    '''
    返回值:这个命令在不同的客户端中有不同的表现。
    redis 127.0.0.1:6379> UNSUBSCRIBE mychannel 
    1) "unsubscribe"
    2) "a"
    3) (integer) 0
    '''
    redis 发布订阅命令

    Redis 事务

    Redis 事务可以一次执行多个命令, 并且带有以下两个重要的保证:

    • 批量操作在发送 EXEC 命令前被放入队列缓存。
    • 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
    • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。

    一个事务从开始到执行会经历以下三个阶段:

    • 开始事务。
    • 命令入队。
    • 执行事务。

    实例

      以下是一个事务的例子, 它先以 MULTI 开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令:

    redis 127.0.0.1:6379> MULTI
    OK
    
    redis 127.0.0.1:6379> SET book-name "Mastering C++ in 21 days"
    QUEUED
    
    redis 127.0.0.1:6379> GET book-name
    QUEUED
    
    redis 127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series"
    QUEUED
    
    redis 127.0.0.1:6379> SMEMBERS tag
    QUEUED
    
    redis 127.0.0.1:6379> EXEC
    1) OK
    2) "Mastering C++ in 21 days"
    3) (integer) 3
    4) 1) "Mastering Series"
       2) "C++"
       3) "Programming"

      单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。

      事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。

    这是官网上的说明 From redis docs on transactions:

    It's important to note that even when a command fails, all the other commands in the queue are processed – Redis will not stop the processing of commands.

    比如:

    redis 127.0.0.1:7000> multi
    OK
    redis 127.0.0.1:7000> set a aaa
    QUEUED
    redis 127.0.0.1:7000> set b bbb
    QUEUED
    redis 127.0.0.1:7000> set c ccc
    QUEUED
    redis 127.0.0.1:7000> exec
    1) OK
    2) OK
    3) OK

    如果在 set b bbb 处失败,set a 已成功不会回滚,set c 还会继续执行。

    # 1.取消事务,放弃执行事务块内的所有命令。
    DISCARD 
    '''
    返回值
    总是返回 OK 。
    redis 127.0.0.1:6379> MULTI
    OK
    redis 127.0.0.1:6379> PING
    QUEUED
    redis 127.0.0.1:6379> SET greeting "hello"
    QUEUED
    redis 127.0.0.1:6379> DISCARD
    OK
    '''
    
    # 2.执行所有事务块内的命令。
    EXEC 
    '''
    返回值:事务块内所有命令的返回值,按命令执行的先后顺序排列。 当操作被打断时,返回空值 nil 。
    # 事务被成功执行
    redis 127.0.0.1:6379> MULTI
    OK
    redis 127.0.0.1:6379> INCR user_id
    QUEUED
    redis 127.0.0.1:6379> INCR user_id
    QUEUED
    redis 127.0.0.1:6379> INCR user_id
    QUEUED
    redis 127.0.0.1:6379> PING
    QUEUED
    redis 127.0.0.1:6379> EXEC
    1) (integer) 1
    2) (integer) 2
    3) (integer) 3
    4) PONG
    
    # 监视 key ,且事务成功执行
    redis 127.0.0.1:6379> WATCH lock lock_times
    OK
    redis 127.0.0.1:6379> MULTI
    OK
    redis 127.0.0.1:6379> SET lock "huangz"
    QUEUED
    redis 127.0.0.1:6379> INCR lock_times
    QUEUED
    redis 127.0.0.1:6379> EXEC
    1) OK
    2) (integer) 1
    
    # 监视 key ,且事务被打断
    redis 127.0.0.1:6379> WATCH lock lock_times
    OK
    redis 127.0.0.1:6379> MULTI
    OK
    redis 127.0.0.1:6379> SET lock "joe"        # 就在这时,另一个客户端修改了 lock_times 的值
    QUEUED
    redis 127.0.0.1:6379> INCR lock_times
    QUEUED
    redis 127.0.0.1:6379> EXEC                  # 因为 lock_times 被修改, joe 的事务执行失败
    (nil)
    '''
    
    # 3.标记一个事务块的开始。
    MULTI 
    '''
    返回值:总是返回 OK 。
    redis 127.0.0.1:6379> MULTI            # 标记事务开始
    OK
    redis 127.0.0.1:6379> INCR user_id     # 多条命令按顺序入队
    QUEUED
    redis 127.0.0.1:6379> INCR user_id
    QUEUED
    redis 127.0.0.1:6379> INCR user_id
    QUEUED
    redis 127.0.0.1:6379> PING
    QUEUED
    redis 127.0.0.1:6379> EXEC             # 执行
    1) (integer) 1
    2) (integer) 2
    3) (integer) 3
    4) PONG
    '''
    
    # 4.取消 WATCH 命令对所有 key 的监视。
    UNWATCH 
    '''
    返回值: 总是返回 OK 。
    redis 127.0.0.1:6379> WATCH lock lock_times
    OK
    redis 127.0.0.1:6379> UNWATCH
    OK
    '''
    
    # 5.监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。
    WATCH key [key ...] 
    '''
    返回值:总是返回 OK 。
    redis> WATCH lock lock_times
    OK
    '''
    redis 事务基本操作

    Redis 脚本

      Redis 脚本使用 Lua 解释器来执行脚本。 Redis 2.6 版本通过内嵌支持 Lua 环境。执行脚本的常用命令为 EVAL

    Eval 命令的基本语法如下:

    redis 127.0.0.1:6379> EVAL script numkeys key [key ...] arg [arg ...]

    实例

    以下实例演示了 redis 脚本工作过程

    redis 127.0.0.1:6379> EVAL "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
    
    1) "key1"
    2) "key2"
    3) "first"
    4) "second"
    # 1.执行 Lua 脚本。
    EVAL script numkeys key [key ...] arg [arg ...] 
    '''
    参数说明:
    script: 参数是一段 Lua 5.1 脚本程序。脚本不必(也不应该)定义为一个 Lua 函数。
    numkeys: 用于指定键名参数的个数。
    key [key ...]: 从 EVAL 的第三个参数开始算起,表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推)。
    arg [arg ...]: 附加参数,在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)。
    redis 127.0.0.1:6379> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
    1) "key1"
    2) "key2"
    3) "first"
    4) "second"
    '''
    
    # 2.执行 Lua 脚本。
    EVALSHA sha1 numkeys key [key ...] arg [arg ...] 
    '''
    参数说明:
    sha1 : 通过 SCRIPT LOAD 生成的 sha1 校验码。
    numkeys: 用于指定键名参数的个数。
    key [key ...]: 从 EVAL 的第三个参数开始算起,表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推)。
    arg [arg ...]: 附加参数,在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)。
    
    redis 127.0.0.1:6379> SCRIPT LOAD "return 'hello moto'"
    "232fd51614574cf0867b83d384a5e898cfd24e5a"
    redis 127.0.0.1:6379> EVALSHA "232fd51614574cf0867b83d384a5e898cfd24e5a" 0
    "hello moto"
    '''
    
    # 3.查看指定的脚本是否已经被保存在缓存当中。
    SCRIPT EXISTS script [script ...] 
    '''
    返回值:一个列表,包含 0 和 1 ,前者表示脚本不存在于缓存,后者表示脚本已经在缓存里面了。
    列表中的元素和给定的 SHA1 校验和保持对应关系,比如列表的第三个元素的值就表示第三个 SHA1 校验和所指定的脚本在缓存中的状态。
    redis 127.0.0.1:6379> SCRIPT LOAD "return 'hello moto'"    # 载入一个脚本
    "232fd51614574cf0867b83d384a5e898cfd24e5a"
    redis 127.0.0.1:6379> SCRIPT EXISTS 232fd51614574cf0867b83d384a5e898cfd24e5a
    1) (integer) 1
    redis 127.0.0.1:6379> SCRIPT FLUSH     # 清空缓存
    OK
    redis 127.0.0.1:6379> SCRIPT EXISTS 232fd51614574cf0867b83d384a5e898cfd24e5a
    1) (integer) 0
    '''
    
    # 4.从脚本缓存中移除所有脚本。
    SCRIPT FLUSH 
    '''
    返回值:OK
    redis 127.0.0.1:6379> SCRIPT FLUSH
    OK
    '''
    
    # 5.杀死当前正在运行的 Lua 脚本。
    SCRIPT KILL 
    '''
    返回值:OK
    redis 127.0.0.1:6379> SCRIPT KILL
    OK
    '''
    
    # 6.将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本。
    SCRIPT LOAD script 
    '''
    返回值:给定脚本的 SHA1 校验和
    redis 127.0.0.1:6379> SCRIPT LOAD "return 1"
    "e0e1f9fabfc9d4800c877a703b823ac0578ff8db"
    '''
    redis 脚本基本操作

     

         

  • 相关阅读:
    mojo 接口示例
    MojoliciousLite: 实时的web框架 概述
    接口返回json
    centos 6.7 perl 版本 This is perl 5, version 22 安装DBI DBD
    centos 6.7 perl 5.22 安装DBD 需要使用老的perl版本
    商业智能改变汽车行业
    商业智能改变汽车行业
    读MBA经历回顾(上)目的决定手段——北漂18年(48)
    perl 升级到5.20版本
    Group Commit of Binary Log
  • 原文地址:https://www.cnblogs.com/zhuminghui/p/9645445.html
Copyright © 2011-2022 走看看