DEV Community

☁ Green Panda
☁ Green Panda

Posted on

Redis Lua

Context

Do you know that you can run a script in Redis? If you don't know maybe it is time to try it out. This scripting ability is intended to optimize performance for Redis operation. However, you probably can achieve the same performance using Redis Pipeline feature. Depending on the use cases, this scripting ability is available if you have very compelling use case.

This article will show you various Redis Lua scripts use case that will make your life easier and its potential use cases where it might fit in daily life.

1. HGet Members

Description

If you have a hash and a set, where a set defines specific hash keys.

Example

Let's say you have vehicles, 3 Honda cars, 1 Mercedes car, and 2 Scooters. We can this script to pull the counts of the Cars.

> hset cars honda 3
(integer) 1
> hset cars mercedes 1
(integer) 1
> hset motorbikes scooters 1
(integer) 1
> sadd cars honda mercedes
(integer) 2
> evalsha 700c06c5ce9835bf9eef2198c8bc4d268b3b5095 2 cars produce
1) 1) "honda"
   2) "3"
2) 1) "mercedes"
   2) "1"
Enter fullscreen mode Exit fullscreen mode

Lua source:

local fields = redis.call("SMEMBERS", KEYS[2])
local values = redis.call("HMGET", KEYS[1], unpack(fields))
local result = {}
for i,k in ipairs(fields) do result[i] = {k, values[i]} end
return result
Enter fullscreen mode Exit fullscreen mode

2. HINCR IF-EXISTS

Description

If you need to increment existing value in Hash map with additional check on the key existance.

Example

> evalsha 3cb0d65c399fda8a1d4eb93b2fe85311671bc969 1 top_scorer budi 1
(nil)
> hset top_scorer budi 80
(integer) 1
> evalsha 3cb0d65c399fda8a1d4eb93b2fe85311671bc969 1 top_scorer budi 1
(integer) 91
> evalsha 3cb0d65c399fda8a1d4eb93b2fe85311671bc969 1 top_scorer budi 1
(integer) 92
Enter fullscreen mode Exit fullscreen mode

Lua source:

if redis.call("HEXISTS", KEYS[1], ARGV[1]) == 1 then
  return redis.call("HINCRBY", KEYS[1], ARGV[1], ARGV[2])
else
  return nil
end
Enter fullscreen mode Exit fullscreen mode

3. HMSET-Extended

Description

In hash set, you usually need to set value one by one. You can leverage Lua to set multiple key from the args.

Example

> evalsha 8c4bbf1b37784149128a5b96e55073538a7401d9 1 mykey foo 1 bar 2
(integer) 1
> hgetall mykey
1) "foo"
2) "1"
3) "bar"
4) "2"
> evalsha 8c4bbf1b37784149128a5b96e55073538a7401d9 1 mykey foo 1 bar 3 baz 4
(integer) 0
> hgetall mykey
1) "foo"
2) "1"
3) "bar"
4) "2"
Enter fullscreen mode Exit fullscreen mode

Lua source:

if redis.call('exists', KEYS[1]) == 0 then
    redis.call('hmset', KEYS[1], unpack(ARGV))
    return 1
end
return 0
Enter fullscreen mode Exit fullscreen mode

4. Simple Rate Limit

Description

If you use Redis for rate limiting, Lua can help you putting together logic your rate limit logic.

Example

> evalsha 089ccf077629d371793d5e928a3f06e9e483eb08 1 ratelimit:127.0.0.1 5 10000
(integer) 0
> evalsha 089ccf077629d371793d5e928a3f06e9e483eb08 1 ratelimit:127.0.0.1 5 10000
(integer) 0
> evalsha 089ccf077629d371793d5e928a3f06e9e483eb08 1 ratelimit:127.0.0.1 5 10000
(integer) 0
> evalsha 089ccf077629d371793d5e928a3f06e9e483eb08 1 ratelimit:127.0.0.1 5 10000
(integer) 0
> evalsha 089ccf077629d371793d5e928a3f06e9e483eb08 1 ratelimit:127.0.0.1 5 10000
(integer) 0
> evalsha 089ccf077629d371793d5e928a3f06e9e483eb08 1 ratelimit:127.0.0.1 5 10000
(integer) 1
Enter fullscreen mode Exit fullscreen mode

Lua source:

local cnt = redis.call('INCR', KEYS[1])
if cnt > tonumber(ARGV[1])
then
  return 1
end
if cnt == 1
then
  redis.call('PEXPIRE', KEYS[1], ARGV[2])
end
return 0
Enter fullscreen mode Exit fullscreen mode

5. Value in Multiple Sets

Description

If you have use case, where you need to check value in multiple sets. This Lua script is definitely helpful for the implementation and avoid networking call.

Example

> sadd users alice bob
(integer) 2
> sadd admin jenny
(integer) 1
> evalsha d7550c872f553141096d5134c027af5eeed283db 2 users admin alice
(integer) 1
> evalsha d7550c872f553141096d5134c027af5eeed283db 3 users admin guests jenny
(integer) 1
> evalsha d7550c872f553141096d5134c027af5eeed283db 2 users admin abner
(integer) 0
Enter fullscreen mode Exit fullscreen mode

Lua source:


-- Is an item in any of several sets? Call with:
-- EVALSHA  n set1 set2 ... setn key
for i=1,#KEYS do
  if redis.call('sismember', KEYS[i], ARGV[1]) == 1 then
    return 1
  end
end
return 0
Enter fullscreen mode Exit fullscreen mode

Source: https://www.redisgreen.com/library/

Top comments (0)