Do you often use get() and set() when using Redis? In fact, there are many useful data structures and various methods in Redis. Today we will test the eval() method.
Recommended: "Redis Video Tutorial"
Redis Eval official description (excerpt)
EVAL script numkeys key [key ...] arg [arg ...]
From Redis 2.6.0 Starting from version 1, through the built-in Lua interpreter, you can use the EVAL command to evaluate Lua scripts.
Redis uses a single Lua interpreter to run all scripts, and Redis also guarantees that scripts will be executed in an atomic manner: when a script is running, there will be no other scripts or Redis The command is executed. This is very similar to using MULTI / EXEC surrounded transactions. From the perspective of other clients, the script's effects are either not visible or already completed.
On the other hand, this also means that executing a slow script is not a good idea. It is not difficult to write a script that runs fast and smoothly, because the running overhead of the script is very small, but when you have to use some scripts that run slowly, please be careful, because when these snail scripts are slow, When running Tuntundi, other clients will be unable to execute commands because the server is busy.
Actual measurement
My understanding is that the eval() method in Redis is generally used in scenarios where multiple redis operations need to be performed to complete a goal.
Below I simulated a scenario of operating redis 100 times. Of course, this may not be necessary in practice. I just want everyone to see the difference.
<?php $redis = new \Redis; $redis->connect('127.0.0.1', 6379); // 清空Redis $redis->flushDB(); // PHP 中循环 set $t = microtime(true); for($i = 0; $i < 100; ++$i) { $redis->set('key' . $i, $i); } echo 'php for set: ', microtime(true) - $t, PHP_EOL; // 清空Redis $redis->flushDB(); // 使用 eval 方法 $t = microtime(true); $keys = []; $values = []; for($i = 0; $i < 100; ++$i) { $keys[] = 'key' . $i; $values[] = $i; } $redis->eval(<<<SCRIPT for i=1,#KEYS do redis.call('set', KEYS[i], ARGV[i]) end SCRIPT , array_merge($keys, $values), count($keys)); echo 'eval:', microtime(true) - $t, PHP_EOL;
Result:
php for set: 0.056596040725708 eval:0.00089216232299805
Obviously, eval is overwhelmingly faster than looping set in the code.
......
Do you think this is over?
No!
evalSha to find out?
EvalSha Description
EVALSHA sha1 numkeys key [key ...] arg [arg ...]
Evaluate the script cached in the server based on the given sha1 check code.
The operation of caching scripts to the server can be performed through the SCRIPT LOAD command.
Other aspects of this command, such as the method of passing parameters, are the same as the EVAL command.
EvalSha actual measurement
<?php function testEval($redis) { $keys = []; $values = []; for($i = 0; $i < 100; ++$i) { $keys[] = 'key' . $i; $values[] = $i; } $redis->eval(<<<SCRIPT for i=1,#KEYS do redis.call('set', KEYS[i], ARGV[i]) end SCRIPT , array_merge($keys, $values), count($keys)); } function testEvalSha($redis) { $keys = []; $values = []; for($i = 0; $i < 100; ++$i) { $keys[] = 'key' . $i; $values[] = $i; } $redis->evalSha(sha1(<<<SCRIPT for i=1,#KEYS do redis.call('set', KEYS[i], ARGV[i]) end SCRIPT ), array_merge($keys, $values), count($keys)); } $redis = new \Redis; $redis->connect('127.0.0.1', 6379); // 清空Redis $redis->flushDB(); // 使用 eval 方法 $t = microtime(true); for($i = 0; $i < 100; ++$i) { testEval($redis); } echo 'eval:', microtime(true) - $t, PHP_EOL; // 清空Redis $redis->flushDB(); // 使用 evalSha 方法 $t = microtime(true); for($i = 0; $i < 100; ++$i) { testEvalSha($redis); } echo 'evalSha:', microtime(true) - $t, PHP_EOL;
Result:
eval:0.081475973129272 evalSha:0.076005220413208
From my test results, evalSha is no faster than eval There is a significant improvement.
However, in a production environment, using evalSha will send smaller data packets than eval and occupy less network resources.
Because eval needs to send the complete script to redis every time, and evalSha only needs to pass a sha1.
evalSha can be called directly only after eval has been executed once.
Benefits
The following is a method I encapsulated. Use evalSha first to try, and use the eval method if it fails.
/** * eval扩展方法,结合了 eval、evalSha * * 优先使用 evalSha 尝试,失败则使用 eval 方法 * * @param \Redis $redis * @param string $script * @param array $args * @param int $num_keys * @return mixed */ function evalEx($redis, $script, $args = null, $num_keys = null) { $sha1 = sha1($script); $redis->clearLastError(); $result = $redis->evalSha($sha1, $args, $num_keys); if('NOSCRIPT No matching script. Please use EVAL.' === $redis->getLastError()) { $result = $redis->eval($script, $args, $num_keys); } return $result; }
The above is the detailed content of What are the benefits of Redis->eval()?. For more information, please follow other related articles on the PHP Chinese website!