Back to Blog
Using lua script in fastoredis7/10/2023 script( :load, LUA_SCRIPT_CODE) retry else raise e end end # Needs to run only once in the entire lifetime of the Redis # server, until the script changes - in which case it will be # loaded under a different SHA. message.include? "NOSCRIPT" # The Redis server has never seen this script before. evalsha( LUA_SCRIPT_HASH,, ) rescue Redis :: CommandError => e if e. In both Ruby and Crystal, constants are initialised when the file is loaded for the first time, which in almost all cases will be during program startup:ĭef run_lua_throttler(redis:, identifier:, bucket_capacity:, leak_rate:, block_for:, n_tokens:) redis. To make sure that the script is correctly loaded and that it’s the latest version, the Lua script is included in the library and its hash is computed at boot time by putting it into a constant. Most of the library is implemented as a Lua script that implements the Leaky Bucket algorithm. How many requests are “too” many is configurable. For example, you can give it a ping with the client IP during every call to /auth and it will let you know if that IP has done too many requests in the last few minutes or not. (There is also a Crystal version available here). One of the libraries written at my previous job was Prorate, which turns a Redis server into a shared rate limiter. Redis is brilliant as a simple way to share state between horizontally scaled servers. Even worse, if the Redis server gets rebooted but not the app servers, they will remain under the impression that the script is in the script cache while it is actually not so. Trying to maintain some internal state in the app server to run EVAL the first time and EVALSHA is still wasteful if there are multiple horizontally scaled app servers. Relying on EVALSHA alone will not be possible, but using EVAL all the time is wasteful. For example, you might be using a hosted Redis service that might reboot the server at an unpredictable moment for maintenance or you might be working on library code that will be run by unknown users on unknown Redis instances. However, there are many cases where you do not control the server. This behavior is very nice if you have complete control over the Redis instance, since you can run the script(s) you want manually just once to get them into the script cache and from then on you can just use the EVALSHA command. If you try to run a script with EVALSHA that is not present in the script cache, Redis will respond with an error of the form (error) 'NOSCRIPT' No matching script. This is obviously faster since less bytes have to be sent across the connection but it will fail if the script is not present in the script cache for some reason. Once you have run a script, Redis will save it in the and from then on you can use the EVALSHA command, which takes the SHA hash of a script instead of the script itself and then looks up the script from the script cache. Running a Lua script is fairly simple: you can use the EVAL command which takes the script as one of its arguments. Luckily, from version 2.6 of Redis onwards you can write your own custom commands as Lua scripts and this is now the recommended way to implement more complicated transactions. There is a form of optimistic locking with the WATCH command, but it’s more a workaround than a rock solid solution since rollbacks are not supported and will have to be implemented clientside. Using the MULTI/ EXEC commands, you can queue up multiple commands to be executed atomically, but if the commands later in the transaction depend on the output of earlier commands this is not enough. Despite (or maybe because of) this, transactions in Redis are not as advanced as in many other databases. The behavior is also discussed and explained in the official StackExchange.The single threaded nature of Redis makes lot of concurrency problems much easier since a lot of issues just go away when it’s simply impossible for multiple operations to happen at the same time. The library tries to call the script by it's hash and if the script is missing it gets a NOSCRIPT error and then transmits the script. LoadedLuaScript might be useful for edge cases like loading without executing. Prepared2.Evaluate(someDb) // calls the script by it's hash Var prepared2 = LuaScript.Prepare(script) Prepared.Evaluate(someDb) // loads the script to redis and calls it For further calls of the same script only the hash is used: var prepared = LuaScript.Prepare(script) StackExchange.Redis automatically transmits the Lua script to redis on the first call to 'ScriptEvaluate'. Normally you don't have to care about loading Lua scripts manually to redis. StackExchange.Redis handles Lua script caching internally.
0 Comments
Read More
Leave a Reply. |