SlideShare a Scribd company logo
Redis Lua Scripts
Itamar Haber @itamarhaber
Evangely Technicalist
This session is about Redis Lua Scripting
● Redis has an embedded sandboxed Lua v5.1 engine.
● User scripts can be sent for execution by the server.
● When a script runs, it blocks the server and is atomic.
● Scripts have full access to the data.
The next slides are a mix of:
● Lua: syntax, data structures, control, …
● Redis: loading, running scripts & specific considerations
● Use cases for using Lua
Who We Are
Open source. The leading in-memory database platform,
supporting any high performance operational, analytics or
hybrid use case.
The open source home and commercial provider of Redis
Enterprise (Redise
) technology, platform, products & services.
Itamar Haber @itamarhaber, Evangely Technicalist, formerly
Chief Developer Advocate & Chief OSS Education Officerhello I am
What is Lua https://www.lua.org/about.html
TL;DR it is a scripting language
Lua is a powerful, efficient, lightweight, embeddable
scripting language. It supports procedural programming,
object-oriented programming, functional programming,
data-driven programming, and data description.
Lua combines simple procedural syntax with powerful data
description constructs based on associative arrays and
extensible semantics. Lua is dynamically typed ...
“
Lua's Hello World
● Single line comments begin with a double dash
● Single argument function calls need no parenthesis
● "This is" a string, and also 'this one'
● Whitespace is the statement separator/terminator;
semicolon optional
-- src: http://rosettacode.org/
print "Hello, World!"
Redis' Lua sandbox
As of v2.6, Redis embeds a Lua v5.1 engine for running user
scripts.
For stability and security purposes, the engine is sandboxed
and exposes only a subset of Lua's full functionality.
The main restrictions put by the sandbox are:
• Only local variables are permitted
• dofile() and loadfile() are disabled
• External libraries can't be used, the require() function
is disabled
Sandbox built-in libraries
Standard libraries:
– Included: base, string, table and math
– Excluded: io, os and debug
Additional bundled libraries:
– bit bit manipulation routines
– struct encode/decode C-like structures
– cjson encode/decode JSON
– cmsgpack encode/decode MessagePack
– redis API to the Redis server
Running one-off scripts
● EVAL expects the raw script as input - it is dev command
● The functions tostring and tonumber are usually
implicitly called
● Remember the exotic string concatenation operator ..
● The script can return a value with the return statement
redis> EVAL
"return('I <' .. tostring(3) .. ' Lua')" 0
"I <3 Lua"
Cached scripts
Redis caches the bytecode of every script it executes in
order to avoid re-compiling it in subsequent calls.
Cached scripts offer two major performance gains:
● Sent to the server only*
once
● Parsed to bytecode only*
once
*
More accurately is "on every SCRIPT LOAD"
Important: keep an eye on the script cache's size, it may
explode.
Loading and running cached scripts
● SCRIPT LOAD returns the sha1sum of the script
● EVALSHA expects the sha1sum of the loaded script
redis> SCRIPT LOAD "return 21 * 2.01"
"935b7b8d888c7affc0bac8a49e63933c915b883f"
redis> EVALSHA
935b7b8d888c7affc0bac8a49e63933c915b883f 0
(integer) 42
redis> EVALSHA nosuchscriptsha1 0
(error) NOSCRIPT No matching script. Please use
EVAL.
# The Cache Explosion Scenario - misuse/antipattern
# Caches every script == EVAL cached, but silently
# P.S. this script should be parameterized, more below
redis> SCRIPT FLUSH
OK
redis> EVAL
"local r = 21 * 2.01 return tostring(r)" 0
"42.21"
redis> EVAL
"return redis.sha1hex(
'local r = 21 * 2.01 return tostring(r)')" 0
"f8bc25b220fcd0406938b86d7cf9d29dce7d1ee8"
redis> EVALSHA
f8bc25b220fcd0406938b86d7cf9d29dce7d1ee8 0
"42.21"
Lua has 8 data types
1. Nil: can only have the value nil
2. Boolean: can be either true or false
3. Number: 32-bit-dp-fp for reals and integers
4. String: 8-bit binary-safe strings
5. Function object: functions are 1st classers
6. Userdata object: C-bindings (n/a in our context)
7. Thread object: coroutines implementation (ditto)
8. Table object: associative array that's used for everything
Note: find out the type with Lua's type() function.
-- The table data type
local empty = {}
local associative = {
['key1'] = 'value1',
[42] = true }
associative['newkey'] = {
['another_key'] = { 'table' }, }
local indexed = { 6, 'afraid', 7 } -- 1-based index!
indexed[#indexed+1] = 'because'
table.insert(indexed, 7)
table.remove(indexed)
return indexed[4]
$ redis-cli --eval localtables.lua
"because"
Script parameters
Anti-pattern: hardcoding dynamic values in the script,
causing the cache to literally explode.
Instead, parametrize your scripts.
Redis distinguishes between two types of parameters:
1. Keys are the names of all keys accessed by the script
2. Arguments are anything excluding any names of keys
Again, why two types of parameters?
Generating key names in the script, programmatically
and/or based on the data set, is not advised.
While Redis does not enforce it, doing so may lead to
unknown results, and complexifies tracking software issues.
Additionally, this usually makes a script totally incompatible
with the Redis cluster, unless special care is taken. And even
then it is not advised.
# KEYS and ARGV are prepopulated indexed tables
$ redis-cli EVAL
"return { ARGV[1], ARGV[2], ARGV[3] }"
0 foo bar baz
1) "foo"
2) "bar"
3) "baz"
$ redis-cli EVAL
"return { KEYS[1], { ARGV[1], ARGV[2] } }"
1 foo bar baz
1) "foo"
2) 1) "bar"
2) "baz"
Accessing the Redis server from a script
As simple as that :)
-- Executes a Redis PING
local reply = redis.call('PING')
return reply
$ redis-cli EVAL "$(cat ping.lua)" 0
PONG
--[[ This adds a the same members (ARGV) to two
regular sets (KEYS[1], KEYS[2]) ]]--
local set1, set2 = KEYS[1], KEYS[2]
local rep1 = redis.call(
'SADD', set1, unpack(ARGV))
local rep2 = redis.call(
'SADD', set2, unpack(ARGV))
return rep1 + rep2
$ redis-cli --eval msadd.lua s s1 , e1 e2
(integer) 4
$ redis-cli --eval msadd.lua s s2 , e3 e4
(integer) 4
Prophecies about the #1 cause for your future...
1. Runtime errors: is forgetting about Lua's unpack(),
a.k.a the "splat" operator
2. bugs: will be redis.call() not returning what you
thought it should/could
3. "$!@$^%#@%#!!!!": redis-cli --eval , put a space before
and after comma!
Data type conversion: redis.call() to Lua
The Redis type Is converted to Lua's
Integer reply Number
Bulk string reply String
Multi bulk reply Table, may be nested
Status reply Table with a single field, ok, set in it
Error reply Table with a single field, err, set in it
Nil Boolean false
Data type conversion: Lua -> Redis (i.e. return)
The Lua type Is converted to Redis'
Number Integer reply (here be dragons)
String Bulk string reply
Table (indexed) Multi bulk reply (truncated 1st nil, if any)
Table with a single ok field Status reply
Table with a single err field Error reply
Data type conversion: Lua -> Redis, redis.call
The Lua type Is converted to Redis'
Nil Nil bulk reply
Boolean false Nil bulk reply
Boolean true Integer reply with value of 1
Note: has no corresponding conversion
4+1 more conversions conversation pieces
1. When intending to return/pass to Redis an integer from
a Lua number, make sure that you're doing that.
Helpful but dirty trick:
tonumber(string.format('%.0f', 3.14))
2. RESP has no floating points, so you'll need to return
them as strings
3. There is no simple way to have nils inside indexed arrays
because Lua table semantics, so when Redis converts a
Lua array into Redis protocol the conversion is stopped if
a nil is encountered.
The Fourth, the Fifth
4. The conversion of Lua's associative arrays, i.e. tables
that are not arrays/lists, is similarly non-trivial, so when
Redis converts an associative Lua array into Redis
protocol the conversion is stopped when the first key in
the array is encountered.
5. Assuming you know what redis.call() will return for a
command can lead to embarrassing mistakes software
issues.
# What's the time and what's with determinism?
$ redis-cli EVAL
"return redis.call('TIME')" 0
1) "1524107683"
2) "501253"
$ redis-cli EVAL "local t = redis.call('TIME')
return redis.call('SET', KEYS[1], t[1])"
1 now
ERR Write commands not allowed after non deterministic
commands. Call redis.replicate_commands()...
$ redis-cli EVAL "redis.replicate_commands()
redis.set_repl(redis.REPL_ALL) -- AOF|SLAVE|NONE
local t = redis.call('TIME')
return redis.call('SET', KEYS[1], t[1])"
1 now
OK
-- Control structure: the if statement
if nil then
-- some logic here
elseif false then
-- optionally more logic here
else
-- this always happens
end
return 'if execution completed successfully'
-- Control structures: while and repeat loops
while false do
-- your code here
end
repeat
-- all this space is yours
until 0 -- Note: everything else is true, also 0
return 'like black hole, nothing gets out of an endless
loop'
-- Control structure: two type of a for loop
local sum1 = 0
for i = 1, #ARGV, 1 do
sum1 = sum1 + tonumber(ARGV[i])
end
local sum2 = 0
for i, v in pairs(ARGV) do
sum2 = sum2 + tonumber(v)
end
if sum1 ~= sum2 then
return redis.error_reply('Something meh here')
end
return redis.status_reply('All good o/')
$ redis-cli EVAL 'while 0 do end' 0
^C
$ redis-cli PING
(error) BUSY Redis is busy running a script. You can
only call SCRIPT KILL or SHUTDOWN NOSAVE.
$ redis-cli SCRIPT KILL
OK
$ redis-cli CONFIG GET lua-time-limit
1) "lua-time-limit"
2) "5000"
$ redis-cli EVAL 'while 0 do break end return "phew"' 0
"phew"
-- Use case: reduce client -> server bandwidth
-- LMPOP key count
local key = KEYS[1]
local count = table.remove(ARGV, 1)
local reply = {}
for _ = 1, count do
local ele = redis.call('LPOP', key)
if ele then
table.insert(reply, ele)
end
end
return reply
-- Use case: reduce server -> client bandwidth
-- ZSUMRANGE key start stop
local total = 0
local data = redis.call(
'ZRANGE', KEYS[1], ARGV[1], ARGV[2], 'WITHSCORES')
while #data > 0 do
-- ZRANGE replies with an array in which
-- the scores are at even indices
total = total + tonumber(table.remove(data))
table.remove(data)
end
return total
Use Case: pure functions, better transactions
and composable commands
Lua scripts are intended to be pure functions.
If you must, store a state in a key in the database, but
always explicitly pass its name.
Lua scripts, being atomic and quite powerful, are often a
nicer alternative to using WATCH/MULTI/EXEC/DISCARD
and retry. And most times also run faster.
Put differently: Lua lets compose commands using the
existing API.
So much more important stuff left to cover...
● Dealing with errors by calling redis.pcall()
● The Redis Lua stepping debugger, aka ldb
● Controlling script effects and replication
● Common pitfalls and considerations, also in testing
● More Lua patterns
Do not fear though! Most is available at online at:
https://redis.io/commands/eval, https://redis.io/topics/ldb,
and https://www.lua.org/manual/5.1/manual.html

More Related Content

What's hot

Caching solutions with Redis
Caching solutions   with RedisCaching solutions   with Redis
Caching solutions with RedisGeorge Platon
 
MariaDB MaxScale
MariaDB MaxScaleMariaDB MaxScale
MariaDB MaxScaleMariaDB plc
 
Atomicity In Redis: Thomas Hunter
Atomicity In Redis: Thomas HunterAtomicity In Redis: Thomas Hunter
Atomicity In Redis: Thomas HunterRedis Labs
 
MySQL Timeout Variables Explained
MySQL Timeout Variables Explained MySQL Timeout Variables Explained
MySQL Timeout Variables Explained Mydbops
 
Redis and its Scaling and Obersvability
Redis and its Scaling and ObersvabilityRedis and its Scaling and Obersvability
Redis and its Scaling and ObersvabilityAbhishekDubey902839
 
Redis Introduction
Redis IntroductionRedis Introduction
Redis IntroductionAlex Su
 
Patroni: Kubernetes-native PostgreSQL companion
Patroni: Kubernetes-native PostgreSQL companionPatroni: Kubernetes-native PostgreSQL companion
Patroni: Kubernetes-native PostgreSQL companionAlexander Kukushkin
 
Rate limits and Performance
Rate limits and PerformanceRate limits and Performance
Rate limits and Performancesupergigas
 
Cloud Native PostgreSQL
Cloud Native PostgreSQLCloud Native PostgreSQL
Cloud Native PostgreSQLEDB
 
MySQL Advanced Administrator 2021 - 네오클로바
MySQL Advanced Administrator 2021 - 네오클로바MySQL Advanced Administrator 2021 - 네오클로바
MySQL Advanced Administrator 2021 - 네오클로바NeoClova
 
Postgres connections at scale
Postgres connections at scalePostgres connections at scale
Postgres connections at scaleMydbops
 
Everything you always wanted to know about Redis but were afraid to ask
Everything you always wanted to know about Redis but were afraid to askEverything you always wanted to know about Redis but were afraid to ask
Everything you always wanted to know about Redis but were afraid to askCarlos Abalde
 
Introduction to Redis
Introduction to RedisIntroduction to Redis
Introduction to RedisArnab Mitra
 

What's hot (20)

Caching solutions with Redis
Caching solutions   with RedisCaching solutions   with Redis
Caching solutions with Redis
 
Introduction to Redis
Introduction to RedisIntroduction to Redis
Introduction to Redis
 
MariaDB MaxScale
MariaDB MaxScaleMariaDB MaxScale
MariaDB MaxScale
 
Atomicity In Redis: Thomas Hunter
Atomicity In Redis: Thomas HunterAtomicity In Redis: Thomas Hunter
Atomicity In Redis: Thomas Hunter
 
MySQL Timeout Variables Explained
MySQL Timeout Variables Explained MySQL Timeout Variables Explained
MySQL Timeout Variables Explained
 
Introduction to redis
Introduction to redisIntroduction to redis
Introduction to redis
 
Redis and its Scaling and Obersvability
Redis and its Scaling and ObersvabilityRedis and its Scaling and Obersvability
Redis and its Scaling and Obersvability
 
Redis basics
Redis basicsRedis basics
Redis basics
 
Redis and it's data types
Redis and it's data typesRedis and it's data types
Redis and it's data types
 
Redis
RedisRedis
Redis
 
Redis Introduction
Redis IntroductionRedis Introduction
Redis Introduction
 
Patroni: Kubernetes-native PostgreSQL companion
Patroni: Kubernetes-native PostgreSQL companionPatroni: Kubernetes-native PostgreSQL companion
Patroni: Kubernetes-native PostgreSQL companion
 
PostgreSQL
PostgreSQLPostgreSQL
PostgreSQL
 
Rate limits and Performance
Rate limits and PerformanceRate limits and Performance
Rate limits and Performance
 
Cloud Native PostgreSQL
Cloud Native PostgreSQLCloud Native PostgreSQL
Cloud Native PostgreSQL
 
Query logging with proxysql
Query logging with proxysqlQuery logging with proxysql
Query logging with proxysql
 
MySQL Advanced Administrator 2021 - 네오클로바
MySQL Advanced Administrator 2021 - 네오클로바MySQL Advanced Administrator 2021 - 네오클로바
MySQL Advanced Administrator 2021 - 네오클로바
 
Postgres connections at scale
Postgres connections at scalePostgres connections at scale
Postgres connections at scale
 
Everything you always wanted to know about Redis but were afraid to ask
Everything you always wanted to know about Redis but were afraid to askEverything you always wanted to know about Redis but were afraid to ask
Everything you always wanted to know about Redis but were afraid to ask
 
Introduction to Redis
Introduction to RedisIntroduction to Redis
Introduction to Redis
 

Similar to Redis Lua Scripts

Introduction to Redis
Introduction to RedisIntroduction to Redis
Introduction to RedisItamar Haber
 
Extend Redis with Modules
Extend Redis with ModulesExtend Redis with Modules
Extend Redis with ModulesItamar Haber
 
Developing a Redis Module - Hackathon Kickoff
 Developing a Redis Module - Hackathon Kickoff Developing a Redis Module - Hackathon Kickoff
Developing a Redis Module - Hackathon KickoffItamar Haber
 
Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)
Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)
Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)Igalia
 
10 Things I Hate About Scala
10 Things I Hate About Scala10 Things I Hate About Scala
10 Things I Hate About ScalaMeir Maor
 
Redis Modules API - an introduction
Redis Modules API - an introductionRedis Modules API - an introduction
Redis Modules API - an introductionItamar Haber
 
Big Data for Mobile
Big Data for MobileBig Data for Mobile
Big Data for MobileBugSense
 
Postgres Vienna DB Meetup 2014
Postgres Vienna DB Meetup 2014Postgres Vienna DB Meetup 2014
Postgres Vienna DB Meetup 2014Michael Renner
 
Ruby -the wheel Technology
Ruby -the wheel TechnologyRuby -the wheel Technology
Ruby -the wheel Technologyppparthpatel123
 
ESIL - Universal IL (Intermediate Language) for Radare2
ESIL - Universal IL (Intermediate Language) for Radare2ESIL - Universal IL (Intermediate Language) for Radare2
ESIL - Universal IL (Intermediate Language) for Radare2Anton Kochkov
 
Redis is not just a cache, Andrew Lavers, ConFoo Montreal 2020
Redis is not just a cache, Andrew Lavers, ConFoo Montreal 2020Redis is not just a cache, Andrew Lavers, ConFoo Montreal 2020
Redis is not just a cache, Andrew Lavers, ConFoo Montreal 2020Andrew Lavers
 
Introducing Elixir and OTP at the Erlang BASH
Introducing Elixir and OTP at the Erlang BASHIntroducing Elixir and OTP at the Erlang BASH
Introducing Elixir and OTP at the Erlang BASHdevbash
 
20160520 what youneedtoknowaboutlambdas
20160520 what youneedtoknowaboutlambdas20160520 what youneedtoknowaboutlambdas
20160520 what youneedtoknowaboutlambdasshinolajla
 
Lisp for Python Programmers
Lisp for Python ProgrammersLisp for Python Programmers
Lisp for Python ProgrammersVsevolod Dyomkin
 
Scaling php applications with redis
Scaling php applications with redisScaling php applications with redis
Scaling php applications with redisjimbojsb
 
あなたのScalaを爆速にする7つの方法
あなたのScalaを爆速にする7つの方法あなたのScalaを爆速にする7つの方法
あなたのScalaを爆速にする7つの方法x1 ichi
 
Code for Startup MVP (Ruby on Rails) Session 2
Code for Startup MVP (Ruby on Rails) Session 2Code for Startup MVP (Ruby on Rails) Session 2
Code for Startup MVP (Ruby on Rails) Session 2Henry S
 
Orchestrating Redis & K8s Operators
Orchestrating Redis & K8s OperatorsOrchestrating Redis & K8s Operators
Orchestrating Redis & K8s OperatorsDoiT International
 
Introducing redis
Introducing redisIntroducing redis
Introducing redisNuno Caneco
 

Similar to Redis Lua Scripts (20)

Introduction to Redis
Introduction to RedisIntroduction to Redis
Introduction to Redis
 
Extend Redis with Modules
Extend Redis with ModulesExtend Redis with Modules
Extend Redis with Modules
 
Developing a Redis Module - Hackathon Kickoff
 Developing a Redis Module - Hackathon Kickoff Developing a Redis Module - Hackathon Kickoff
Developing a Redis Module - Hackathon Kickoff
 
Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)
Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)
Good news, everybody! Guile 2.2 performance notes (FOSDEM 2016)
 
10 Things I Hate About Scala
10 Things I Hate About Scala10 Things I Hate About Scala
10 Things I Hate About Scala
 
Redis Modules API - an introduction
Redis Modules API - an introductionRedis Modules API - an introduction
Redis Modules API - an introduction
 
Big Data for Mobile
Big Data for MobileBig Data for Mobile
Big Data for Mobile
 
Postgres Vienna DB Meetup 2014
Postgres Vienna DB Meetup 2014Postgres Vienna DB Meetup 2014
Postgres Vienna DB Meetup 2014
 
Ruby -the wheel Technology
Ruby -the wheel TechnologyRuby -the wheel Technology
Ruby -the wheel Technology
 
ESIL - Universal IL (Intermediate Language) for Radare2
ESIL - Universal IL (Intermediate Language) for Radare2ESIL - Universal IL (Intermediate Language) for Radare2
ESIL - Universal IL (Intermediate Language) for Radare2
 
Redis is not just a cache, Andrew Lavers, ConFoo Montreal 2020
Redis is not just a cache, Andrew Lavers, ConFoo Montreal 2020Redis is not just a cache, Andrew Lavers, ConFoo Montreal 2020
Redis is not just a cache, Andrew Lavers, ConFoo Montreal 2020
 
Introducing Elixir and OTP at the Erlang BASH
Introducing Elixir and OTP at the Erlang BASHIntroducing Elixir and OTP at the Erlang BASH
Introducing Elixir and OTP at the Erlang BASH
 
20160520 what youneedtoknowaboutlambdas
20160520 what youneedtoknowaboutlambdas20160520 what youneedtoknowaboutlambdas
20160520 what youneedtoknowaboutlambdas
 
Lisp for Python Programmers
Lisp for Python ProgrammersLisp for Python Programmers
Lisp for Python Programmers
 
Scaling php applications with redis
Scaling php applications with redisScaling php applications with redis
Scaling php applications with redis
 
あなたのScalaを爆速にする7つの方法
あなたのScalaを爆速にする7つの方法あなたのScalaを爆速にする7つの方法
あなたのScalaを爆速にする7つの方法
 
Code for Startup MVP (Ruby on Rails) Session 2
Code for Startup MVP (Ruby on Rails) Session 2Code for Startup MVP (Ruby on Rails) Session 2
Code for Startup MVP (Ruby on Rails) Session 2
 
Orchestrating Redis & K8s Operators
Orchestrating Redis & K8s OperatorsOrchestrating Redis & K8s Operators
Orchestrating Redis & K8s Operators
 
Introducing redis
Introducing redisIntroducing redis
Introducing redis
 
Comredis
ComredisComredis
Comredis
 

More from Itamar Haber

Redis v5 & Streams
Redis v5 & StreamsRedis v5 & Streams
Redis v5 & StreamsItamar Haber
 
How I Implemented the #1 Requested Feature In Redis In Less than 1 Hour with ...
How I Implemented the #1 Requested Feature In Redis In Less than 1 Hour with ...How I Implemented the #1 Requested Feature In Redis In Less than 1 Hour with ...
How I Implemented the #1 Requested Feature In Redis In Less than 1 Hour with ...Itamar Haber
 
Redis Streams - Fiverr Tech5 meetup
Redis Streams - Fiverr Tech5 meetupRedis Streams - Fiverr Tech5 meetup
Redis Streams - Fiverr Tech5 meetupItamar Haber
 
Leveraging Probabilistic Data Structures for Real Time Analytics with Redis M...
Leveraging Probabilistic Data Structures for Real Time Analytics with Redis M...Leveraging Probabilistic Data Structures for Real Time Analytics with Redis M...
Leveraging Probabilistic Data Structures for Real Time Analytics with Redis M...Itamar Haber
 
Power to the People: Redis Lua Scripts
Power to the People: Redis Lua ScriptsPower to the People: Redis Lua Scripts
Power to the People: Redis Lua ScriptsItamar Haber
 
What's new in Redis v3.2
What's new in Redis v3.2What's new in Redis v3.2
What's new in Redis v3.2Itamar Haber
 
Redis Developers Day 2015 - Secondary Indexes and State of Lua
Redis Developers Day 2015 - Secondary Indexes and State of LuaRedis Developers Day 2015 - Secondary Indexes and State of Lua
Redis Developers Day 2015 - Secondary Indexes and State of LuaItamar Haber
 
Use Redis in Odd and Unusual Ways
Use Redis in Odd and Unusual WaysUse Redis in Odd and Unusual Ways
Use Redis in Odd and Unusual WaysItamar Haber
 
Why Your MongoDB Needs Redis
Why Your MongoDB Needs RedisWhy Your MongoDB Needs Redis
Why Your MongoDB Needs RedisItamar Haber
 
Redis & MongoDB: Stop Big Data Indigestion Before It Starts
Redis & MongoDB: Stop Big Data Indigestion Before It StartsRedis & MongoDB: Stop Big Data Indigestion Before It Starts
Redis & MongoDB: Stop Big Data Indigestion Before It StartsItamar Haber
 
Benchmarking Redis by itself and versus other NoSQL databases
Benchmarking Redis by itself and versus other NoSQL databasesBenchmarking Redis by itself and versus other NoSQL databases
Benchmarking Redis by itself and versus other NoSQL databasesItamar Haber
 
Redis Indices (#RedisTLV)
Redis Indices (#RedisTLV)Redis Indices (#RedisTLV)
Redis Indices (#RedisTLV)Itamar Haber
 
Redis Use Patterns (DevconTLV June 2014)
Redis Use Patterns (DevconTLV June 2014)Redis Use Patterns (DevconTLV June 2014)
Redis Use Patterns (DevconTLV June 2014)Itamar Haber
 

More from Itamar Haber (13)

Redis v5 & Streams
Redis v5 & StreamsRedis v5 & Streams
Redis v5 & Streams
 
How I Implemented the #1 Requested Feature In Redis In Less than 1 Hour with ...
How I Implemented the #1 Requested Feature In Redis In Less than 1 Hour with ...How I Implemented the #1 Requested Feature In Redis In Less than 1 Hour with ...
How I Implemented the #1 Requested Feature In Redis In Less than 1 Hour with ...
 
Redis Streams - Fiverr Tech5 meetup
Redis Streams - Fiverr Tech5 meetupRedis Streams - Fiverr Tech5 meetup
Redis Streams - Fiverr Tech5 meetup
 
Leveraging Probabilistic Data Structures for Real Time Analytics with Redis M...
Leveraging Probabilistic Data Structures for Real Time Analytics with Redis M...Leveraging Probabilistic Data Structures for Real Time Analytics with Redis M...
Leveraging Probabilistic Data Structures for Real Time Analytics with Redis M...
 
Power to the People: Redis Lua Scripts
Power to the People: Redis Lua ScriptsPower to the People: Redis Lua Scripts
Power to the People: Redis Lua Scripts
 
What's new in Redis v3.2
What's new in Redis v3.2What's new in Redis v3.2
What's new in Redis v3.2
 
Redis Developers Day 2015 - Secondary Indexes and State of Lua
Redis Developers Day 2015 - Secondary Indexes and State of LuaRedis Developers Day 2015 - Secondary Indexes and State of Lua
Redis Developers Day 2015 - Secondary Indexes and State of Lua
 
Use Redis in Odd and Unusual Ways
Use Redis in Odd and Unusual WaysUse Redis in Odd and Unusual Ways
Use Redis in Odd and Unusual Ways
 
Why Your MongoDB Needs Redis
Why Your MongoDB Needs RedisWhy Your MongoDB Needs Redis
Why Your MongoDB Needs Redis
 
Redis & MongoDB: Stop Big Data Indigestion Before It Starts
Redis & MongoDB: Stop Big Data Indigestion Before It StartsRedis & MongoDB: Stop Big Data Indigestion Before It Starts
Redis & MongoDB: Stop Big Data Indigestion Before It Starts
 
Benchmarking Redis by itself and versus other NoSQL databases
Benchmarking Redis by itself and versus other NoSQL databasesBenchmarking Redis by itself and versus other NoSQL databases
Benchmarking Redis by itself and versus other NoSQL databases
 
Redis Indices (#RedisTLV)
Redis Indices (#RedisTLV)Redis Indices (#RedisTLV)
Redis Indices (#RedisTLV)
 
Redis Use Patterns (DevconTLV June 2014)
Redis Use Patterns (DevconTLV June 2014)Redis Use Patterns (DevconTLV June 2014)
Redis Use Patterns (DevconTLV June 2014)
 

Recently uploaded

Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfCheryl Hung
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...Product School
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Tobias Schneck
 
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...Product School
 
ODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupCatarinaPereira64715
 
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxAbida Shariff
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...Product School
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Thierry Lestable
 
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...Product School
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsPaul Groth
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaRTTS
 
Demystifying gRPC in .Net by John Staveley
Demystifying gRPC in .Net by John StaveleyDemystifying gRPC in .Net by John Staveley
Demystifying gRPC in .Net by John StaveleyJohn Staveley
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3DianaGray10
 
10 Differences between Sales Cloud and CPQ, Blanka Doktorová
10 Differences between Sales Cloud and CPQ, Blanka Doktorová10 Differences between Sales Cloud and CPQ, Blanka Doktorová
10 Differences between Sales Cloud and CPQ, Blanka DoktorováCzechDreamin
 
Search and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical FuturesSearch and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical FuturesBhaskar Mitra
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Product School
 
Introduction to Open Source RAG and RAG Evaluation
Introduction to Open Source RAG and RAG EvaluationIntroduction to Open Source RAG and RAG Evaluation
Introduction to Open Source RAG and RAG EvaluationZilliz
 
Unpacking Value Delivery - Agile Oxford Meetup - May 2024.pptx
Unpacking Value Delivery - Agile Oxford Meetup - May 2024.pptxUnpacking Value Delivery - Agile Oxford Meetup - May 2024.pptx
Unpacking Value Delivery - Agile Oxford Meetup - May 2024.pptxDavid Michel
 
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo DiehlFuture Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo DiehlPeter Udo Diehl
 
UiPath Test Automation using UiPath Test Suite series, part 2
UiPath Test Automation using UiPath Test Suite series, part 2UiPath Test Automation using UiPath Test Suite series, part 2
UiPath Test Automation using UiPath Test Suite series, part 2DianaGray10
 

Recently uploaded (20)

Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
 
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
 
ODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User Group
 
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
 
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...
 
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMsTo Graph or Not to Graph Knowledge Graph Architectures and LLMs
To Graph or Not to Graph Knowledge Graph Architectures and LLMs
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
 
Demystifying gRPC in .Net by John Staveley
Demystifying gRPC in .Net by John StaveleyDemystifying gRPC in .Net by John Staveley
Demystifying gRPC in .Net by John Staveley
 
UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3UiPath Test Automation using UiPath Test Suite series, part 3
UiPath Test Automation using UiPath Test Suite series, part 3
 
10 Differences between Sales Cloud and CPQ, Blanka Doktorová
10 Differences between Sales Cloud and CPQ, Blanka Doktorová10 Differences between Sales Cloud and CPQ, Blanka Doktorová
10 Differences between Sales Cloud and CPQ, Blanka Doktorová
 
Search and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical FuturesSearch and Society: Reimagining Information Access for Radical Futures
Search and Society: Reimagining Information Access for Radical Futures
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
 
Introduction to Open Source RAG and RAG Evaluation
Introduction to Open Source RAG and RAG EvaluationIntroduction to Open Source RAG and RAG Evaluation
Introduction to Open Source RAG and RAG Evaluation
 
Unpacking Value Delivery - Agile Oxford Meetup - May 2024.pptx
Unpacking Value Delivery - Agile Oxford Meetup - May 2024.pptxUnpacking Value Delivery - Agile Oxford Meetup - May 2024.pptx
Unpacking Value Delivery - Agile Oxford Meetup - May 2024.pptx
 
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo DiehlFuture Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
Future Visions: Predictions to Guide and Time Tech Innovation, Peter Udo Diehl
 
UiPath Test Automation using UiPath Test Suite series, part 2
UiPath Test Automation using UiPath Test Suite series, part 2UiPath Test Automation using UiPath Test Suite series, part 2
UiPath Test Automation using UiPath Test Suite series, part 2
 

Redis Lua Scripts

  • 1. Redis Lua Scripts Itamar Haber @itamarhaber Evangely Technicalist
  • 2. This session is about Redis Lua Scripting ● Redis has an embedded sandboxed Lua v5.1 engine. ● User scripts can be sent for execution by the server. ● When a script runs, it blocks the server and is atomic. ● Scripts have full access to the data. The next slides are a mix of: ● Lua: syntax, data structures, control, … ● Redis: loading, running scripts & specific considerations ● Use cases for using Lua
  • 3. Who We Are Open source. The leading in-memory database platform, supporting any high performance operational, analytics or hybrid use case. The open source home and commercial provider of Redis Enterprise (Redise ) technology, platform, products & services. Itamar Haber @itamarhaber, Evangely Technicalist, formerly Chief Developer Advocate & Chief OSS Education Officerhello I am
  • 4.
  • 5. What is Lua https://www.lua.org/about.html TL;DR it is a scripting language Lua is a powerful, efficient, lightweight, embeddable scripting language. It supports procedural programming, object-oriented programming, functional programming, data-driven programming, and data description. Lua combines simple procedural syntax with powerful data description constructs based on associative arrays and extensible semantics. Lua is dynamically typed ... “
  • 6. Lua's Hello World ● Single line comments begin with a double dash ● Single argument function calls need no parenthesis ● "This is" a string, and also 'this one' ● Whitespace is the statement separator/terminator; semicolon optional -- src: http://rosettacode.org/ print "Hello, World!"
  • 7. Redis' Lua sandbox As of v2.6, Redis embeds a Lua v5.1 engine for running user scripts. For stability and security purposes, the engine is sandboxed and exposes only a subset of Lua's full functionality. The main restrictions put by the sandbox are: • Only local variables are permitted • dofile() and loadfile() are disabled • External libraries can't be used, the require() function is disabled
  • 8. Sandbox built-in libraries Standard libraries: – Included: base, string, table and math – Excluded: io, os and debug Additional bundled libraries: – bit bit manipulation routines – struct encode/decode C-like structures – cjson encode/decode JSON – cmsgpack encode/decode MessagePack – redis API to the Redis server
  • 9. Running one-off scripts ● EVAL expects the raw script as input - it is dev command ● The functions tostring and tonumber are usually implicitly called ● Remember the exotic string concatenation operator .. ● The script can return a value with the return statement redis> EVAL "return('I <' .. tostring(3) .. ' Lua')" 0 "I <3 Lua"
  • 10. Cached scripts Redis caches the bytecode of every script it executes in order to avoid re-compiling it in subsequent calls. Cached scripts offer two major performance gains: ● Sent to the server only* once ● Parsed to bytecode only* once * More accurately is "on every SCRIPT LOAD" Important: keep an eye on the script cache's size, it may explode.
  • 11. Loading and running cached scripts ● SCRIPT LOAD returns the sha1sum of the script ● EVALSHA expects the sha1sum of the loaded script redis> SCRIPT LOAD "return 21 * 2.01" "935b7b8d888c7affc0bac8a49e63933c915b883f" redis> EVALSHA 935b7b8d888c7affc0bac8a49e63933c915b883f 0 (integer) 42 redis> EVALSHA nosuchscriptsha1 0 (error) NOSCRIPT No matching script. Please use EVAL.
  • 12. # The Cache Explosion Scenario - misuse/antipattern # Caches every script == EVAL cached, but silently # P.S. this script should be parameterized, more below redis> SCRIPT FLUSH OK redis> EVAL "local r = 21 * 2.01 return tostring(r)" 0 "42.21" redis> EVAL "return redis.sha1hex( 'local r = 21 * 2.01 return tostring(r)')" 0 "f8bc25b220fcd0406938b86d7cf9d29dce7d1ee8" redis> EVALSHA f8bc25b220fcd0406938b86d7cf9d29dce7d1ee8 0 "42.21"
  • 13. Lua has 8 data types 1. Nil: can only have the value nil 2. Boolean: can be either true or false 3. Number: 32-bit-dp-fp for reals and integers 4. String: 8-bit binary-safe strings 5. Function object: functions are 1st classers 6. Userdata object: C-bindings (n/a in our context) 7. Thread object: coroutines implementation (ditto) 8. Table object: associative array that's used for everything Note: find out the type with Lua's type() function.
  • 14. -- The table data type local empty = {} local associative = { ['key1'] = 'value1', [42] = true } associative['newkey'] = { ['another_key'] = { 'table' }, } local indexed = { 6, 'afraid', 7 } -- 1-based index! indexed[#indexed+1] = 'because' table.insert(indexed, 7) table.remove(indexed) return indexed[4] $ redis-cli --eval localtables.lua "because"
  • 15. Script parameters Anti-pattern: hardcoding dynamic values in the script, causing the cache to literally explode. Instead, parametrize your scripts. Redis distinguishes between two types of parameters: 1. Keys are the names of all keys accessed by the script 2. Arguments are anything excluding any names of keys
  • 16. Again, why two types of parameters? Generating key names in the script, programmatically and/or based on the data set, is not advised. While Redis does not enforce it, doing so may lead to unknown results, and complexifies tracking software issues. Additionally, this usually makes a script totally incompatible with the Redis cluster, unless special care is taken. And even then it is not advised.
  • 17. # KEYS and ARGV are prepopulated indexed tables $ redis-cli EVAL "return { ARGV[1], ARGV[2], ARGV[3] }" 0 foo bar baz 1) "foo" 2) "bar" 3) "baz" $ redis-cli EVAL "return { KEYS[1], { ARGV[1], ARGV[2] } }" 1 foo bar baz 1) "foo" 2) 1) "bar" 2) "baz"
  • 18. Accessing the Redis server from a script As simple as that :) -- Executes a Redis PING local reply = redis.call('PING') return reply $ redis-cli EVAL "$(cat ping.lua)" 0 PONG
  • 19. --[[ This adds a the same members (ARGV) to two regular sets (KEYS[1], KEYS[2]) ]]-- local set1, set2 = KEYS[1], KEYS[2] local rep1 = redis.call( 'SADD', set1, unpack(ARGV)) local rep2 = redis.call( 'SADD', set2, unpack(ARGV)) return rep1 + rep2 $ redis-cli --eval msadd.lua s s1 , e1 e2 (integer) 4 $ redis-cli --eval msadd.lua s s2 , e3 e4 (integer) 4
  • 20. Prophecies about the #1 cause for your future... 1. Runtime errors: is forgetting about Lua's unpack(), a.k.a the "splat" operator 2. bugs: will be redis.call() not returning what you thought it should/could 3. "$!@$^%#@%#!!!!": redis-cli --eval , put a space before and after comma!
  • 21. Data type conversion: redis.call() to Lua The Redis type Is converted to Lua's Integer reply Number Bulk string reply String Multi bulk reply Table, may be nested Status reply Table with a single field, ok, set in it Error reply Table with a single field, err, set in it Nil Boolean false
  • 22. Data type conversion: Lua -> Redis (i.e. return) The Lua type Is converted to Redis' Number Integer reply (here be dragons) String Bulk string reply Table (indexed) Multi bulk reply (truncated 1st nil, if any) Table with a single ok field Status reply Table with a single err field Error reply
  • 23. Data type conversion: Lua -> Redis, redis.call The Lua type Is converted to Redis' Nil Nil bulk reply Boolean false Nil bulk reply Boolean true Integer reply with value of 1 Note: has no corresponding conversion
  • 24. 4+1 more conversions conversation pieces 1. When intending to return/pass to Redis an integer from a Lua number, make sure that you're doing that. Helpful but dirty trick: tonumber(string.format('%.0f', 3.14)) 2. RESP has no floating points, so you'll need to return them as strings 3. There is no simple way to have nils inside indexed arrays because Lua table semantics, so when Redis converts a Lua array into Redis protocol the conversion is stopped if a nil is encountered.
  • 25. The Fourth, the Fifth 4. The conversion of Lua's associative arrays, i.e. tables that are not arrays/lists, is similarly non-trivial, so when Redis converts an associative Lua array into Redis protocol the conversion is stopped when the first key in the array is encountered. 5. Assuming you know what redis.call() will return for a command can lead to embarrassing mistakes software issues.
  • 26. # What's the time and what's with determinism? $ redis-cli EVAL "return redis.call('TIME')" 0 1) "1524107683" 2) "501253" $ redis-cli EVAL "local t = redis.call('TIME') return redis.call('SET', KEYS[1], t[1])" 1 now ERR Write commands not allowed after non deterministic commands. Call redis.replicate_commands()... $ redis-cli EVAL "redis.replicate_commands() redis.set_repl(redis.REPL_ALL) -- AOF|SLAVE|NONE local t = redis.call('TIME') return redis.call('SET', KEYS[1], t[1])" 1 now OK
  • 27. -- Control structure: the if statement if nil then -- some logic here elseif false then -- optionally more logic here else -- this always happens end return 'if execution completed successfully'
  • 28. -- Control structures: while and repeat loops while false do -- your code here end repeat -- all this space is yours until 0 -- Note: everything else is true, also 0 return 'like black hole, nothing gets out of an endless loop'
  • 29. -- Control structure: two type of a for loop local sum1 = 0 for i = 1, #ARGV, 1 do sum1 = sum1 + tonumber(ARGV[i]) end local sum2 = 0 for i, v in pairs(ARGV) do sum2 = sum2 + tonumber(v) end if sum1 ~= sum2 then return redis.error_reply('Something meh here') end return redis.status_reply('All good o/')
  • 30. $ redis-cli EVAL 'while 0 do end' 0 ^C $ redis-cli PING (error) BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE. $ redis-cli SCRIPT KILL OK $ redis-cli CONFIG GET lua-time-limit 1) "lua-time-limit" 2) "5000" $ redis-cli EVAL 'while 0 do break end return "phew"' 0 "phew"
  • 31. -- Use case: reduce client -> server bandwidth -- LMPOP key count local key = KEYS[1] local count = table.remove(ARGV, 1) local reply = {} for _ = 1, count do local ele = redis.call('LPOP', key) if ele then table.insert(reply, ele) end end return reply
  • 32. -- Use case: reduce server -> client bandwidth -- ZSUMRANGE key start stop local total = 0 local data = redis.call( 'ZRANGE', KEYS[1], ARGV[1], ARGV[2], 'WITHSCORES') while #data > 0 do -- ZRANGE replies with an array in which -- the scores are at even indices total = total + tonumber(table.remove(data)) table.remove(data) end return total
  • 33. Use Case: pure functions, better transactions and composable commands Lua scripts are intended to be pure functions. If you must, store a state in a key in the database, but always explicitly pass its name. Lua scripts, being atomic and quite powerful, are often a nicer alternative to using WATCH/MULTI/EXEC/DISCARD and retry. And most times also run faster. Put differently: Lua lets compose commands using the existing API.
  • 34. So much more important stuff left to cover... ● Dealing with errors by calling redis.pcall() ● The Redis Lua stepping debugger, aka ldb ● Controlling script effects and replication ● Common pitfalls and considerations, also in testing ● More Lua patterns Do not fear though! Most is available at online at: https://redis.io/commands/eval, https://redis.io/topics/ldb, and https://www.lua.org/manual/5.1/manual.html