Redis Lua Scripting
Redis provides a way to extend its functionality on the server side by providing support for Lua Scripting. If you are coming from a relational database world, you already know that you can use Stored Procedures to extend functionality of your relational database. Now, you may also know that some people do frown upon using stored procedures, I think one could also think of using scripting in Redis sort of belongs in the same category. Nevertheless its still good to know what you can do with Redis and Lua.
In order to call Lua Script from Redis.StackExchange library one can use the LuaScript class or IServer.ScriptLoad(Async), IServer.ScriptExists(Async), IServer.ScriptFlush(Async), IDatabase.ScriptEvaluate, and IDatabaseAsync.ScriptEvaluateAsync methods.
Lets try to do something with the redis console first by using the redis-cli
$redis-cli
127.0.0.1:6379> SCRIPT LOAD "return 'hello redis'"
"69dd69fc0ba1e25d8e2972008b6baee8eccf7da6"
127.0.0.1:6379> evalsha 69dd69fc0ba1e25d8e2972008b6baee8eccf7da6 0
"hello redis"
As you can see we first load the script and we get back a SHA1 Hash from it. Redis basically stores the information in one of its mapping table and we can reuse the sha1 hash to call the script by using the EVALSHA command, which in this case gave us back “hello redis”
C# code using Redis Lua Script
class Program
{
static void Main(string[] args)
{
const string script = @"
local function MGETSUM(keys)
local sum = 0
for _,key in ipairs(keys) do
local val = redis.call('GET', key) or 0
sum = sum + tonumber(val)
end
return sum
end
return MGETSUM(KEYS)";
var redis = RedisStore.RedisCache;
var server = RedisStore.Server;
var test1 = "test1";
var test2 = "test2";
var test3 = "test3";
//delete the keys
redis.KeyDelete(test1, CommandFlags.FireAndForget);
redis.KeyDelete(test2, CommandFlags.FireAndForget);
redis.KeyDelete(test3, CommandFlags.FireAndForget);
redis.StringSet(test1, 1);
redis.StringSet(test2, 2);
redis.StringSet(test3, 3);
RedisKey[] keys = { test1, test2, test3 };
byte[] hash = server.ScriptLoad(script);
//get back the sha1 key
string hexHash = string.Concat(hash.Select(x => x.ToString("X2")));
var result = redis.ScriptEvaluate(hexHash, keys);
Console.WriteLine(result); //result will be 6
Console.ReadKey();
}
You may realize that every time we call the server we need to load the script and then execute on it, there is also another way that StackExchange Redis allows us to to avoid the overhead of transmitting the script text for every call. One can convert a LuaScript into a LoadedLuaScript like the code below:
//create another script to store
var script2 = @"
local name=@name
local age=@age
return name..' '..age
";
var prepared = LuaScript.Prepare(script2);
//we now need to cache this loaded script somewhere
var loaded = prepared.Load(server);
//such that we do not need to uplaod the script every time
var val = loaded.Evaluate(redis, new { name="taswar", age=5});
//Output: taswar 5
Console.WriteLine(val);
val = loaded.Evaluate(redis, new { name = "peter", age = 25 });
//Output: peter 25
Console.WriteLine(val);
So this covers the basic usage of Redis LuaScript, in the next blog post I will cover how to use Geo spatial data in Redis.
For the code please visit
https://github.com/taswar/RedisForNetDevelopers/tree/master/12.RedisLua/RedisLua
For previous Redis topics
- Intro to Redis for .NET Developers
- Redis for .NET Developer – Connecting with C#
- Redis for .NET Developer – String Datatype
- Redis for .NET Developer – String Datatype part 2
- Redis for .NET Developer – Hash Datatype
- Redis for .NET Developer – List Datatype
- Redis for .NET Developer – Redis Sets Datatype
- Redis for .NET Developer – Redis Sorted Sets Datatype
- Redis for .NET Developer – Redis Hyperloglog
- Redis for .NET Developer – Redis Pub Sub
- Redis for .NET Developers – Redis Pipeline Batching
- Redis for .NET Developers – Redis Transactions