【PHP】Redis 中如何更好的加载Lua脚本

【PHP】Redis 中如何更好的加载Lua脚本

1、直接使用EVAL执行,不算在“更好”的范围内,不做讨论。

2、正常判断式:先判断脚本存不存在,再进行操作。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * Redis注册Lua脚本
 *
 * @param Redis $redis
 * @param $file
 *
 * @return bool|mixed|string
 */
function load_lua_script(Redis $redis, $file) {
    if (!is_file($file)) {
        return false;
    }

    $sha1 = sha1_file($file);

    if ($redis->script('EXISTS', $sha1)[0] == 1) {
        return $sha1;
    } else {
        return $redis->script('LOAD', file_get_contents($file));
    }
}

$script_sha = load_lua_script($redis, '/path/to/lua_script.lua');
$reuslt = $redis->evalSha($script_sha, $args, $key_number);

3、触发式执行:如果执行失败了,才LOAD脚本,并重新运行。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
 * 执行Lua脚本
 *
 * @param Redis $redis
 * @param $file
 * @param $args
 * @param $numKeys
 *
 * @return bool|mixed|string
 */
function run_lua_script(Redis $redis, $file, $args, $numKeys) {
    if (!is_file($file)) {
        return false;
    }

    $sha1 = sha1_file($file);

    for ($run_number = 0; $run_number < 3; $run_number++) {

        $redis_result = $redis->evalSha($sha1, $args, $numKeys);

        // 检测脚本是否不存在,如果不存在,则加载,并重新执行
        if (substr($redis->getLastError(), 0, 8) === 'NOSCRIPT') {

            echo 'LOAD' . PHP_EOL;
            $sha1 = $redis->script('LOAD', file_get_contents($file));
            $redis->clearLastError();
            continue;
        }

        return $redis_result;
    }

    return false;
}

$reuslt = run_lua_script($redis, '/path/to/lua_script.lua', $args, $key_number);

测试:

Lua脚本:

1
2
3
4
5
-- lua_script.lua

local value = redis.call('INCRBY', KEYS[1], ARGV[1])

return 'hello ' .. value

二号脚本测试运行10000次:8万次单程 IO 运行 0.9738 秒。

三号脚本测试运行10000次:4万次单程 IO 运行 0.6284 秒。

显而易见,触发式脚本可以更好的节约IO、以高的性能运行。