zoukankan      html  css  js  c++  java
  • redis与lua

    内容大纲

    redis里使用eval和evalsha

    redis管理Lua脚本 

    php里使用redis的lua脚本

    在redis里使用lua脚本的好处

    1.Lua脚本在Redis中是原子执行的,执行过程中间不会插入其他命令
    2.Lua脚本可以帮助开发和运维人员创造出自己定制的命令,并可以将这些命令常驻在Redis内存中,实现复用的效果。
    3.Lua脚本可以将多条命令一次性打包,有效地减少网络开销

    在redis中

    eval的语法格式
    EVAL script numkeys key [key ...] arg [arg ...]
    其中:
    <1> script: 你的lua脚本
    <2> numkeys: key的个数
    <3> key: redis中各种数据结构的替代符号
    <4> arg: 你的自定义参数

    eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 username age hk 20
    第一个参数的字符串是script,也就是lua脚本,2表示keys的个数,KEYS[1] 就是username的占位符, KEYS[2]就是
    age的占位符,ARGV[1]就是jk的占位符,ARGV[2]就是20的占位符,以此类推,所以最后的结果应该就是:{return username age hk 20}

    其中要要读写的键名应该作为key参数,其它的数据都作为arg参数
    eval命令依据第二个参数将后面的所有参数分别存入脚本中KEYS和ARGV两个表类型的全局变量。
    当脚本不需要任何参数时也不能省略这个参数(设为0)

    在cli中执行

    250:0>eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 username age hk 20
     1)  "username"
     2)  "age"
     3)  "hk"
     4)  "20"

    执行Lua脚本文件

    redis-cli --eval keys.lua k1 k2 , v1 v2

    key和value用一个逗号隔开

    keys.lua

    return {
    KEYS,
    type(KEYS),
    '-----',
    ARGV,
    type(ARGV)
    }
    [root@centos1 lua]# redis-cli --eval keys.lua k1 k2 , v1 v2
    1) 1) "k1"
       2) "k2"
    2) "table"
    3) "-----"
    4) 1) "v1"
       2) "v2"
    5) "table"

    evalsha

    将Lua脚本加载到Redis服务端,得到该脚本的sha1校验和,evalsha命令使用sha1作为参数可以直接执行对应的Lua脚本,
    避免每次发送Lua脚本的开销。这样客户端就不需要每次执行脚本内容,而脚本也会常驻在服务端,脚本内容得到了复用
    加载脚本: script load命令可以将脚本内容加载到Redis内存中

    hmgetall.lua  获取多个hash key的值

    --获取指定的多个hash key
    
    local result={}
    for i,v in ipairs(KEYS) do
        result[i]=redis.call('HGETALL',v)
    end
    return result

    [root@centos1 redis-lua]# redis-cli script load "$(cat hmgetall.lua)"
    "032f22e507d134837f1c948f5b4f6b979b2e8beb"
    得到sha1的值
    在redis里执行脚本
    evalsha 脚本sha1值 key个数 key列表 参数列表
    evalsha 032f22e507d134837f1c948f5b4f6b979b2e8beb 2 user:1 user:2 0

    127.0.0.1:6379> evalsha 032f22e507d134837f1c948f5b4f6b979b2e8beb 2 user:1 user:2 
    1) 1) "name"
       2) "hk"
       3) "age"
       4) "20"
    2) 1) "name"
       2) "hk2"
       3) "age"
       4) "22"

    Redis管理Lua脚本
    1.script load
    此命令用于将Lua脚本加载到Redis内存中
    2.script exists
    scripts exists sha1 [sha1 …]
    此命令用于判断sha1是否已经加载到Redis内存中
    3.script flush
    此命令用于清除Redis内存已经加载的所有Lua脚本,在执行script flush后,sha1不复存在 
    4.script kill
    此命令用于杀掉正在执行的Lua脚本

    为了防止某个脚本执行时间过长导致redis无法提供服务
    redis提供lua-time-limit 参数限制脚本的最长运行时间,默认为5秒
    当脚本运行超过这一限制后,redis将开始接收其它命令但不会执行(以确认脚本的原子性,因为此时脚本并没有终止),而是返回busy 错误
    打开2个redis客户端
    redis A> eval "while true do end" 0
    redis B中
    127.0.0.1:6379> keys *
    (error) BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.
    此时redis虽然可以接收任何命令,但实际会执行的只有2个 SCRIPT KILL or SHUTDOWN NOSAVE
    127.0.0.1:6379> script kill
    OK
    需要注意的是 如果当执行的是修改操作,则 SCRIPT KILL 命令不会终止脚本的运行以防止脚本只执行了一部分(违背原子性的要求)
    redis A>eval "redis.call('set','name','hk') while true do end" 0
    redis B里

    127.0.0.1:6379> keys *
    (error) BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.
    127.0.0.1:6379> script kill
    (error) UNKILLABLE Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in a hard way using the SHUTDOWN NOSAVE command.

    此时只能 SHUTDOWN NOSAVE
    SHUTDOWN NOSAVE 不会进行持久化的操作 与 SHUTDOWN 的区别

    php里使用redis的lua脚本

    lua.php

    <?php
    require "./vendor/autoload.php";
    
    class HMGetAll extends PredisCommandScriptCommand{
    
        public function getKeysCount()
        {
            return false;
        }
        public function getScript(){
            return
            <<<LUA
            local result = {}
            for i ,v in ipairs(ARGV) do
                result[i] =redis.call('HGETALL',v)
            end
            return result
    LUA;
    
        }
    }
    $client= new PredisClient(
        [
            'scheme'=>'tcp',
            'host' => '192.168.0.250',
            'port' => 6379,
            ]
    );
    //定义hmgetall命令
    $client->getProfile()->defineCommand("hmgetall",'HMGetAll');
    
    var_dump($client->hgetall('user:1'));
    var_dump($client->hgetall('user:2'));
    //执行hmgetall
    
    $value=$client->hmgetall('user:1','user:2');
    var_dump($value);

    结果类似

    D:wamp64wwwcnblogsluaphplua.php:32:
    array (size=2)
      'name' => string 'hk' (length=2)
      'age' => string '20' (length=2)
    D:wamp64wwwcnblogsluaphplua.php:33:
    array (size=2)
      'name' => string 'hk2' (length=3)
      'age' => string '22' (length=2)
    D:wamp64wwwcnblogsluaphplua.php:37:
    array (size=2)
      0 => 
        array (size=4)
          0 => string 'name' (length=4)
          1 => string 'hk' (length=2)
          2 => string 'age' (length=3)
          3 => string '20' (length=2)
      1 => 
        array (size=4)
          0 => string 'name' (length=4)
          1 => string 'hk2' (length=3)
          2 => string 'age' (length=3)
          3 => string '22' (length=2)
    View Code

    参考redis入门指南(书中这块有错误 应该是ARGV而不是循环KEYS) 

    详细代码见  https://gitee.com/hk/cnblogs/tree/master/lua/php

  • 相关阅读:
    将SVD应用于推荐系统
    matrix.A
    机架感知配置
    PCA主成分分析进行数据降维
    Rabbitmq的高级特性
    Topics(主题模式)
    Routing(exchange--direct)
    fanout(Publish/Subscribe)发布/订阅
    Work Queues(工作队列)
    simple queue(简单队列)
  • 原文地址:https://www.cnblogs.com/HKUI/p/9251110.html
Copyright © 2011-2022 走看看