Maison  >  Article  >  base de données  >  Quels sont les avantages de Redis->eval() ?

Quels sont les avantages de Redis->eval() ?

藏色散人
藏色散人avant
2019-06-13 14:13:512972parcourir

Utilisez-vous souvent get() et set() lorsque vous utilisez Redis ? En fait, il existe de nombreuses structures de données utiles et diverses méthodes dans Redis. Aujourd'hui, nous allons tester la méthode eval().

Recommandé : "Tutoriel vidéo Redis"

Description officielle de Redis Eval (extrait)

EVAL script numkeys key [key ...] arg [arg ...]

De Redis 2.6.0 À partir de la version 1, via l'interpréteur Lua intégré, vous pouvez utiliser la commande EVAL pour évaluer les scripts Lua.

Redis utilise un seul interpréteur Lua pour exécuter tous les scripts, et Redis garantit également que les scripts seront exécutés de manière atomique : lorsqu'un script est en cours d'exécution, il n'y aura pas d'autres scripts ou Redis La commande est exécutée. Ceci est très similaire à l’utilisation de transactions entourées MULTI/EXEC. Du point de vue des autres clients, les effets du script ne sont pas visibles ou sont déjà terminés.

D'un autre côté, cela signifie également qu'exécuter un script lent n'est pas une bonne idée. Il n'est pas difficile d'écrire un script qui s'exécute rapidement et sans problème, car la surcharge d'exécution du script est très faible, mais lorsque vous devez utiliser des scripts qui s'exécutent lentement, soyez prudent, car lorsque ces scripts escargot sont lents, lorsque exécutant Tuntundi, les autres clients ne pourront pas exécuter de commandes car le serveur est occupé.

Mesure réelle

Je crois comprendre que la méthode eval() dans Redis est généralement utilisée dans des scénarios où plusieurs opérations Redis doivent être effectuées pour atteindre un objectif.

Ci-dessous, j'ai simulé un scénario d'opération redis 100 fois. Bien sûr, cela n'est peut-être pas nécessaire en pratique, je veux juste que tout le monde voie la différence.

<?php
 
$redis = new \Redis;
$redis->connect(&#39;127.0.0.1&#39;, 6379);
 
// 清空Redis
$redis->flushDB();
 
// PHP 中循环 set
$t = microtime(true);
for($i = 0; $i < 100; ++$i)
{
    $redis->set(&#39;key&#39; . $i, $i);
}
echo &#39;php for set: &#39;, microtime(true) - $t, PHP_EOL;
 
// 清空Redis
$redis->flushDB();
 
// 使用 eval 方法
$t = microtime(true);
$keys = [];
$values = [];
for($i = 0; $i < 100; ++$i)
{
    $keys[] = &#39;key&#39; . $i;
    $values[] = $i;
}
$redis->eval(<<<SCRIPT
for i=1,#KEYS do
    redis.call(&#39;set&#39;, KEYS[i], ARGV[i])
end
SCRIPT
, array_merge($keys, $values), count($keys));
echo &#39;eval:&#39;, microtime(true) - $t, PHP_EOL;

Résultat :

php for set: 0.056596040725708
eval:0.00089216232299805

De toute évidence, eval est extrêmement plus rapide que la boucle définie dans le code.

......

Pensez-vous que c'est la fin ?

Non !

evalSha, vous connaissez ?

EvalSha Description

EVALSHA sha1 numkeys key [key ...] arg [arg ...]

Évaluez le script mis en cache dans le serveur en fonction du code de vérification sha1 donné.

La mise en cache des scripts sur le serveur peut être effectuée via la commande SCRIPT LOAD.

Les autres aspects de cette commande, tels que la méthode de transmission des paramètres, sont les mêmes que la commande EVAL.

Mesure réelle d'EvalSha

<?php
function testEval($redis)
{
    $keys = [];
    $values = [];
    for($i = 0; $i < 100; ++$i)
    {
        $keys[] = &#39;key&#39; . $i;
        $values[] = $i;
    }
    $redis->eval(<<<SCRIPT
for i=1,#KEYS do
    redis.call(&#39;set&#39;, KEYS[i], ARGV[i])
end
SCRIPT
, array_merge($keys, $values), count($keys));
}
 
function testEvalSha($redis)
{
    $keys = [];
    $values = [];
    for($i = 0; $i < 100; ++$i)
    {
        $keys[] = &#39;key&#39; . $i;
        $values[] = $i;
    }
    $redis->evalSha(sha1(<<<SCRIPT
for i=1,#KEYS do
    redis.call(&#39;set&#39;, KEYS[i], ARGV[i])
end
SCRIPT
    ), array_merge($keys, $values), count($keys));
}
 
$redis = new \Redis;
$redis->connect(&#39;127.0.0.1&#39;, 6379);
 
// 清空Redis
$redis->flushDB();
 
// 使用 eval 方法
$t = microtime(true);
for($i = 0; $i < 100; ++$i)
{
    testEval($redis);
}
echo &#39;eval:&#39;, microtime(true) - $t, PHP_EOL;
 
 
// 清空Redis
$redis->flushDB();
 
// 使用 evalSha 方法
$t = microtime(true);
for($i = 0; $i < 100; ++$i)
{
    testEvalSha($redis);
}
echo &#39;evalSha:&#39;, microtime(true) - $t, PHP_EOL;

Résultat :

eval:0.081475973129272
evalSha:0.076005220413208

D'après mes résultats de test, evalSha n'est pas plus rapide que eval Il y a une amélioration significative.

Cependant, dans un environnement de production, si vous utilisez evalSha, il enverra des paquets de données plus petits qu'eval et occupera moins de ressources réseau.

Parce que eval doit envoyer le script complet à redis à chaque fois, alors que evalSha n'a besoin que de transmettre un sha1.

evalSha ne peut être appelé directement qu'après qu'eval ait été exécuté une fois.

Avantages

Ce qui suit est une méthode que j'ai encapsulée. Utilisez d'abord evalSha pour essayer, et utilisez la méthode eval si elle échoue.

/**
 * 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(&#39;NOSCRIPT No matching script. Please use EVAL.&#39; === $redis->getLastError())
    {
        $result = $redis->eval($script, $args, $num_keys);
    }
    return $result;
}

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer
Article précédent:Comment regrouper RedisArticle suivant:Comment regrouper Redis