sql >> Database >  >> NoSQL >> Redis

RedisClient LUA API's

De IRedisClient API's voor redis server-side LUA-ondersteuning zijn opnieuw verwerkt in de gebruiksvriendelijkere API's hieronder:

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

Efficiënte SCAN in LUA #

De C# API hieronder retourneert de eerste 10 resultaten die overeenkomen met de key:* patroon:

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

De bovenstaande C# Streaming-API vereist echter een onbekend aantal Redis-bewerkingen (beperkt aan het aantal sleutels in Redis) om de aanvraag te voltooien. Het aantal SCAN-aanroepen kan worden verminderd door een hogere pageSize te kiezen om Redis te vertellen om meer sleutels te scannen elke keer dat de SCAN-bewerking wordt aangeroepen.

Aangezien het aantal API-aanroepen het potentieel heeft om te resulteren in een groot aantal Redis-bewerkingen, kan dit leiden tot een onaanvaardbare vertraging vanwege de latentie van meerdere afhankelijke externe netwerkaanroepen. Een eenvoudige oplossing is om in plaats daarvan de meerdere SCAN-oproepen tijdens het proces op de Redis-server te laten uitvoeren, waardoor de netwerklatentie van meerdere SCAN-oproepen wordt geëlimineerd, bijvoorbeeld:

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

De ExecLua API retourneert dit complexe LUA-tabelantwoord in de Children verzameling van de RedisText Reactie.

Alternatief complex API-antwoord #

Een andere manier om complexe datastructuren in een LUA-bewerking te retourneren, is door het resultaat te serialiseren als JSON

return cjson.encode(results)

Waartoe u toegang hebt als onbewerkte JSON door het antwoord als een tekenreeks te ontleden met:

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

INFO

Dit is ook de benadering die wordt gebruikt in Redis React's RedisServices.

ExecCachedLua #

ExecCachedLua is een handige API op hoog niveau die de boekhouding elimineert die nodig is voor het uitvoeren van hoogwaardige server-LUA-scripts die last hebben van veel van de problemen die RDBMS-opgeslagen procedures hebben, die afhankelijk zijn van de reeds bestaande status in het RDBMS die moet worden bijgewerkt met de laatste versie van de Opgeslagen procedure.

Met Redis LUA heb je ofwel de optie om het hele LUA-script te verzenden, te ontleden, te laden en vervolgens uit te voeren elke keer dat het wordt aangeroepen, of je kunt het LUA-script een keer vooraf in Redis laden bij het opstarten en het vervolgens uitvoeren met behulp van de SHA1-hash van het script. Het probleem hiermee is dat als de Redis-server per ongeluk wordt leeggemaakt, je een kapotte applicatie overhoudt die vertrouwt op een reeds bestaand script dat er niet meer is. De nieuwe ExecCachedLua API biedt het beste van twee werelden, waarbij het altijd het gecompileerde SHA1-script uitvoert, bandbreedte en CPU bespaart, maar ook het LUA-script opnieuw maakt als het niet meer bestaat.

U kunt in plaats daarvan het gecompileerde LUA-script hierboven uitvoeren met zijn SHA1-identificatiecode, die blijft werken, ongeacht of deze nooit heeft bestaan ​​of tijdens runtime is verwijderd, bijvoorbeeld:

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

Gebruiksvoorbeelden #

Hier leest u hoe u een ZPOP . kunt implementeren in Lua om de items met de laagste rang uit een gesorteerde set te verwijderen:

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]

En hoe ZREVPOP te implementeren om items met de hoogste rang uit een gesorteerde set te verwijderen:

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]

Andere voorbeelden #

Een int retourneren :

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

Een string teruggeven :

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

Een List retourneren van snaren:

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

Meer voorbeelden zijn te vinden in de Redis Eval Lua-tests


  1. Benchmark Apache HBase vs Apache Cassandra op SSD in een cloudomgeving

  2. Hoe plaats je een document in mongodb met behulp van mangoest en krijg je de gegenereerde id?

  3. $uitgeschakeld is leeg. U moet een veld als volgt specificeren:{$unset:{<field>:...}}

  4. mangoest/mongoest aangepaste sortering