Scripting in Redis: atomic execution - redis

In the documentation about scripting in redis the following is stated:
Redis guarantees the script's atomic execution. While executing the script, all server activities are blocked during its entire runtime.
Do I understand that correctly that really all server activities are blocked? In the call to EVAL you state the keys that are modified, so why would Redis not only block activities for those keys?
Thanks in advance for any clarification!

Because Redis runs commands one-by-one in a single thread. When it runs your script, i.e. EVAL, it cannot run other commands until it finishes the script.
So, NEVER run complicated Lua script, since it might block Redis for a long time, and hurt performance.

Related

why we need the eval command in redis, if redis is single-threaded?

One way to execute commands in REDIS, is via the EVAL script.
Redis uses the same Lua interpreter to run all the commands. Also
Redis guarantees that a script is executed in an atomic way: no other
script or Redis command will be executed while a script is being
executed.
Since redis is single threaded, why do we need EVAL to offer atomicity? I would expect that this is implied by the one running thread.
Am I missing something? Apologies if my question is pretty simple, I am quite new to redis
Every (data path) command in Redis is indeed atomic. EVAL allows you to compose an "atomic" command with a script that can include many Redis commands, not to mention control structures and some other utilities that are helpful to implement server-side logic. To achieve the similar "atomicity" of multiple commands you can also use MULTI/EXEC blocks (i.e. transactions) by the way.
Without an EVAL or a MULTI/EXEC block, your commands will run one after another, but other clients' commands may interleave between them. Using a script or transaction eliminates that.
Redis uses a single thread to execute commands from many different clients. So if you want a group of commands from one client to be executed in sequence, you need a way to direct Redis to do that. That's what EVAL is for. Without it, Redis could interleave the execution of commands from other clients in with yours.

What happens if Elasticache decides to reshard while my script is running?

I have some scripts that touch a handful of keys. What happens if Elasticache decides to reshard while my script is running? Will it wait for my script to complete before it moves the underlying keys? Or should I assume that it is not the case and design my application with this edge case in mind?
One example would be a script that increment 2 keys at once. I could receive a "cluster error" which means something went wrong and I have to execute my script again (and potentially end up with one key being incremented twice and the other once)
Assuming you are talking about a Lua script, for as long as you're passing the keys in the arguments (and not hardcoded in the script) you should be good. It will be all or nothing. If you are not using a Lua script - consider doing so
From EVAL command:
All Redis commands must be analyzed before execution to determine
which keys the command will operate on. In order for this to be true
for EVAL, keys must be passed explicitly. This is useful in many ways,
but especially to make sure Redis Cluster can forward your request to
the appropriate cluster node.
From AWS ElastiCache - Best Practices: Online Cluster Resizing:
During resharding, we recommend the following:
Avoid expensive commands – Avoid running any computationally and I/O
intensive operations, such as the KEYS and SMEMBERS commands. We
suggest this approach because these operations increase the load on
the cluster and have an impact on the performance of the cluster.
Instead, use the SCAN and SSCAN commands.
Follow Lua best practices – Avoid long running Lua scripts, and always
declare keys used in Lua scripts up front. We recommend this approach
to determine that the Lua script is not using cross slot commands.
Ensure that the keys used in Lua scripts belong to the same slot.

Redis Lua memory consumption

I have an issue with using lua scripts running on redis
When running INFO command
used_memory_lua_human:1.08G
The usage of Lua is not extensive (single set and get commands)
How can I reduce this value?
Apparently Redis caches every Lua script that is running on it, in order to spare loading it.
This is a good feature given the set of the scripts is limited.
The problem caused because we are formatting the script with different variable every execution, and it gets a different identifier every execution.
The solution I found is running SCRIPT FLUSH command after every execution, in order to remove it from cache
The explanation of why this is happening is explained by gCoh's answer very well.
The only problem is that running SCRIPT FLUSH can lead to a lot of errors and even loss of processing if you use EVALSHA to run LUA scripts. (For example, a library like scripto runs LUA scripts using EVALSHA). Read more about EVALSHA here
EVALSHA keeps the script cached in redis server and gives out a hash when you load the script for the first time. When you run the script second time, rather than loading the script on the server it just sends the script hash and redis executes it.
Now if you run SCRIPT FLUSH it will remove all the cached scripts and your SHA hashes will become obsolete, which will lead to runtime errors when the script is being executed and it isn't found.
For me it was this: NOSCRIPT No matching script. Please use EVAL.
This should be handled in the scripto library, where if the script isn't found it should load it again but until them, please take care that this doesn't happen with you.

What about redis EVAL atomicity regarding keys with TTL?

As I know redis is single threaded solution from client point of view.
But what about the general architecture?
Amuse we have some lua script that going to execute several commands on keys that has some TTL.
How does redis garbage collections works? Could it interrupt the EVAL execution & evict some value or internal tasks share the single thread with user tasks?
Lua is majik, and because that is the case time stops when Redis is doing Lua. Put differently, expiration stops once you start running the script in the sense that time does not advance. However, if a key expired before the script started, it will not be available for the script to use.

Redis script error during execution recovery

During any redis lua script (atomic/exclusive?) execution, any writes that have occured during the script, but before the error will be committed/written and not rolled back as part of the implementation.
I am just wondering about the situation where your script is mainly bullet proof (e.g preconditions checked, but the instance executing your script crashes half way, with some writes already committed and stored in AOF log (or propagated to other masters in case of the upcoming redis-cluster)? How do you recovery/what are the best practices for this?
Also I would like to double check if the redis script is executed atomically/exclusively, as in, no other operations can occur? I am fairly sure this is the case, although does this also hold true for the upcoming redis cluster implementation and would multiple masters execute scripts concurrently?