Redis
 sql >> Base de Dados >  >> NoSQL >> Redis

APIs LUA do RedisClient


O IRedisClient As APIs para suporte a LUA do lado do servidor redis foram reformuladas nas APIs mais fáceis de usar abaixo:
public interface IRedisClient 
{
    //Eval/Lua operations 
    T ExecCachedLua<T>(string scriptBody, Func<string, T> scriptSha1);

    RedisText ExecLua(string body, params string[] args);
    RedisText ExecLua(string luaBody, string[] keys, string[] args);
    RedisText ExecLuaSha(string sha1, params string[] args);
    RedisText ExecLuaSha(string sha1, string[] keys, string[] args);

    string ExecLuaAsString(string luaBody, params string[] args);
    string ExecLuaAsString(string luaBody, string[] keys, string[] args);
    string ExecLuaShaAsString(string sha1, params string[] args);
    string ExecLuaShaAsString(string sha1, string[] keys, string[] args);
    
    int ExecLuaAsInt(string luaBody, params string[] args);
    int ExecLuaAsInt(string luaBody, string[] keys, string[] args);
    int ExecLuaShaAsInt(string sha1, params string[] args);
    int ExecLuaShaAsInt(string sha1, string[] keys, string[] args);

    List<string> ExecLuaAsList(string luaBody, params string[] args);
    List<string> ExecLuaAsList(string luaBody, string[] keys, string[] args);
    List<string> ExecLuaShaAsList(string sha1, params string[] args);
    List<string> ExecLuaShaAsList(string sha1, string[] keys, string[] args);

    string CalculateSha1(string luaBody);
    
    bool HasLuaScript(string sha1Ref);
    Dictionary<string, bool> WhichLuaScriptsExists(params string[] sha1Refs);
    void RemoveAllLuaScripts();
    void KillRunningLuaScript();
    string LoadLuaScript(string body);
}

Digitalização eficiente em LUA #


A API C# abaixo retorna os 10 primeiros resultados correspondentes à key:* padronizar:
var keys = Redis.ScanAllKeys(pattern: "key:*", pageSize: 10)
    .Take(10).ToList();

No entanto, a API de streaming C# acima requer um número desconhecido de operações do Redis (limitado ao número de chaves no Redis) para concluir a solicitação. O número de chamadas SCAN pode ser reduzido escolhendo um pageSize maior para dizer ao Redis para escanear mais chaves cada vez que a operação SCAN for chamada.

Como o número de chamadas de API tem o potencial de resultar em um grande número de operações Redis, pode acabar gerando um atraso inaceitável devido à latência de várias chamadas de rede remota dependentes. Uma solução fácil é realizar as várias chamadas SCAN em processo no Redis Server, eliminando a latência de rede de várias chamadas SCAN, por exemplo:
const string FastScanScript = @"
local limit = tonumber(ARGV[2])
local pattern = ARGV[1]
local cursor = 0
local len = 0
local results = {}
repeat
    local r = redis.call('scan', cursor, 'MATCH', pattern, 'COUNT', limit)
    cursor = tonumber(r[1])
    for k,v in ipairs(r[2]) do
        table.insert(results, v)
        len = len + 1
        if len == limit then break end
    end
until cursor == 0 or len == limit
return results";

RedisText r = redis.ExecLua(FastScanScript, "key:*", "10");
r.Children.Count.Print() //= 10

O ExecLua A API retorna essa resposta complexa da tabela LUA no Children coleção do RedisText Resposta.

Resposta de API complexa alternativa #


Outra maneira de retornar estruturas de dados complexas em uma operação LUA é serializar o resultado como JSON
return cjson.encode(results)

Que você pode acessar como JSON bruto analisando a resposta como uma String com:
string json = redis.ExecLuaAsString(FastScanScript, "key:*", "10");

INFORMAÇÕES

Essa também é a abordagem usada nos RedisServices do Redis React.

ExecCachedLua #


ExecCachedLua é uma API de alto nível conveniente que elimina a escrituração necessária para executar scripts LUA de servidor de alto desempenho que sofrem de muitos dos problemas que os procedimentos armazenados do RDBMS têm que dependem do estado pré-existente no RDBMS que precisa ser atualizado com o última versão do procedimento armazenado.

Com o Redis LUA, você tem a opção de enviar, analisar, carregar e executar todo o script LUA toda vez que for chamado ou, alternativamente, pode pré-carregar o script LUA no Redis uma vez na inicialização e executá-lo usando o hash SHA1 do script. O problema com isso é que, se o servidor Redis for liberado acidentalmente, você ficará com um aplicativo quebrado contando com um script pré-existente que não está mais lá. O novo ExecCachedLua A API fornece o melhor dos dois mundos, onde sempre executará o script SHA1 compilado, economizando largura de banda e CPU, mas também recriará o script LUA se ele não existir mais.

Em vez disso, você pode executar o script LUA compilado acima por seu identificador SHA1, que continua a funcionar independentemente de nunca ter existido ou ter sido removido em tempo de execução, por exemplo:
// #1: Loads LUA script and caches SHA1 hash in Redis Client
r = redis.ExecCachedLua(FastScanScript, sha1 =>
    redis.ExecLuaSha(sha1, "key:*", "10"));

// #2: Executes using cached SHA1 hash
r = redis.ExecCachedLua(FastScanScript, sha1 =>
    redis.ExecLuaSha(sha1, "key:*", "10"));

// Deletes all existing compiled LUA scripts 
redis.ScriptFlush();

// #3: Executes using cached SHA1 hash, gets NOSCRIPT Error, 
//     re-creates then re-executes the LUA script using its SHA1 hash
r = redis.ExecCachedLua(FastScanScript, sha1 =>
    redis.ExecLuaSha(sha1, "key:*", "10"));

Exemplos de uso #


Veja como você pode implementar um ZPOP em Lua para remover os itens com a classificação mais baixa de um conjunto ordenado:
var luaBody = @"
    local val = redis.call('zrange', KEYS[1], 0, ARGV[1]-1)
    if val then redis.call('zremrangebyrank', KEYS[1], 0, ARGV[1]-1) end
    return val";

var i = 0;
var alphabet = 26.Times(c => ((char)('A' + c)).ToString());
alphabet.ForEach(x => Redis.AddItemToSortedSet("zalphabet", x, i++));

//Remove the letters with the lowest rank from the sorted set 'zalphabet'
var letters = Redis.ExecLuaAsList(luaBody, keys: new[] { "zalphabet" }, args: new[] { "3" });
letters.PrintDump(); //[A, B, C]

E como implementar ZREVPOP para remover itens com a classificação mais alta de um conjunto classificado:
var luaBody = @"
    local val = redis.call('zrange', KEYS[1], -ARGV[1], -1)
    if val then redis.call('zremrangebyrank', KEYS[1], -ARGV[1], -1) end
    return val";

var i = 0;
var alphabet = 26.Times(c => ((char)('A' + c)).ToString());
alphabet.ForEach(x => Redis.AddItemToSortedSet("zalphabet", x, i++));

//Remove the letters with the highest rank from the sorted set 'zalphabet'
List<string> letters = Redis.ExecLuaAsList(luaBody, 
    keys: new[] { "zalphabet" }, args: new[] { "3" });

letters.PrintDump(); //[X, Y, Z]

Outros exemplos #


Retornando um int :
int intVal = Redis.ExecLuaAsInt("return 123"); //123
int intVal = Redis.ExecLuaAsInt("return ARGV[1] + ARGV[2]", "10", "20"); //30

Retornando uma string :
//Hello, Redis Lua!
var strVal = Redis.ExecLuaAsString(@"return 'Hello, ' .. ARGV[1] .. '!'", "Redis Lua");

Retornando uma List de cordas:
Enum.GetNames(typeof(DayOfWeek)).ToList()
    .ForEach(x => Redis.AddItemToList("DaysOfWeek", x));

var daysOfWeek = Redis.ExecLuaAsList("return redis.call('LRANGE', 'DaysOfWeek', 0, -1)");
daysOfWeek.PrintDump(); //[Sunday, Monday, Tuesday, ...]

Mais exemplos podem ser encontrados nos testes Redis Eval Lua