sql >> Databáze >  >> NoSQL >> Redis

RedisClient LUA API

IRedisClient Rozhraní API pro podporu LUA na straně serveru redis byla přepracována do uživatelsky přívětivějších rozhraní API níže:

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);
}

Efektivní SKENOVÁNÍ v LUA #

C# API níže vrátí prvních 10 výsledků odpovídajících key:* vzor:

var keys = Redis.ScanAllKeys(pattern: "key:*", pageSize: 10)
    .Take(10).ToList();

Výše uvedené rozhraní C# Streaming API však vyžaduje neznámý počet operací Redis (vázaný na počet klíčů v Redis) k dokončení požadavku. Počet volání SCAN lze snížit výběrem vyšší pageSize říci Redis, aby prohledala více klíčů pokaždé, když je zavolána operace SCAN.

Vzhledem k tomu, že počet volání API má potenciál vést k velkému počtu operací Redis, může to skončit s nepřijatelným zpožděním kvůli latenci více závislých vzdálených síťových volání. Snadným řešením je místo toho nechat více SCAN volání provádět během procesu na Redis Server, čímž se eliminuje síťová latence více SCAN volání, např.:

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

Soubor ExecLua API vrací tuto komplexní odpověď tabulky LUA v Children kolekce RedisText Odpověď.

Alternativní komplexní odpověď API #

Dalším způsobem, jak vrátit složité datové struktury v operaci LUA, je serializovat výsledek jako JSON

return cjson.encode(results)

Ke kterému můžete přistupovat jako k raw JSON analýzou odpovědi jako řetězce s:

string json = redis.ExecLuaAsString(FastScanScript, "key:*", "10");

INFO

Toto je také přístup používaný v RedisServices Redis React.

ExecCachedLua #

ExecCachedLua je pohodlné API na vysoké úrovni, které eliminuje vedení účetnictví potřebné pro spouštění vysoce výkonných serverových skriptů LUA, které trpí mnoha problémy, které mají uložené procedury RDBMS a které závisí na již existujícím stavu v RDBMS, který je třeba aktualizovat pomocí nejnovější verzi uložené procedury.

S Redis LUA máte buď možnost odeslat, analyzovat, načíst a poté spustit celý skript LUA pokaždé, když je zavolán, nebo alternativně můžete skript LUA předem načíst do Redis jednou při spuštění a poté jej spustit pomocí hash SHA1 skriptu. Problém je v tom, že pokud dojde k náhodnému vyprázdnění serveru Redis, zůstane vám nefunkční aplikace spoléhající se na již existující skript, který tam již není. Nový ExecCachedLua API poskytuje to nejlepší z obou světů, kde vždy spustí zkompilovaný skript SHA1, čímž šetří šířku pásma a CPU, ale také znovu vytvoří skript LUA, pokud již neexistuje.

Místo toho můžete spustit zkompilovaný skript LUA výše podle jeho identifikátoru SHA1, který nadále funguje bez ohledu na to, zda nikdy neexistoval nebo byl odstraněn za běhu, např.:

// #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"));

Příklady použití #

Zde je návod, jak implementovat ZPOP v Lua k odstranění položek s nejnižším hodnocením ze setříděné sady:

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]

A jak implementovat ZREVPOP k odstranění položek s nejvyšší hodností ze seřazené sady:

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]

Další příklady #

Vrací int :

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

Vrací string :

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

Vrací List řetězců:

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, ...]

Další příklady lze nalézt v testech Redis Eval Lua


  1. Nelze svázat TCP listener *:6379 pomocí Redis v systému Windows

  2. MongoDB $strcasecmp

  3. Hadoop InputFormat a typy InputFormat v MapReduce

  4. Vraťte poslední dokument z vyhledávání