Maybe you've heard of the scripting language embedded in Redis, but haven't you tried it yourself? This introductory tutorial will allow you to learn to use the powerful Lua language on your Redis server.
Hello, lua!.
Our first Redis Lua script simply returns a string without interacting with redis in any meaningful way.
Copy Code code as follows:
Local msg = "Hello, world!"
Return msg
This is very simple, the first line of code defines a local variable msg stores our information, and the second line of code represents the value of MSG returned from the Redis server to the client. Save this file to Hello.lua, run like this:
Copy Code code as follows:
REDIS-CLI EVAL "$ (cat Hello.lua)" 0
Running this code will print "hello,world!", eval in the first parameter is our LUA script, which we use the Cat command to read our script content from the file. The second parameter is the numeric number of the Redis key that this script needs to access. Our simple "Hello Script" will not access any keys, so we use 0
access keys and Parameters
Let's say we want to create a URL shorthand server. We are going to store each entry URL and return a unique value so that the URL can be accessed later through this value.
We will use the Lua script to immediately get a unique ID from Redis using Incrand, which is stored as a URL in a hash key value:
Copy Code code as follows:
Local link_id = Redis.call ("INCR", key[1)
Redis.call ("Hset", keys[2], link_id, argv[1])
Return link_id
We will use the call () function to access Redis for the first time. The parameter of call () is a command issued to Redis: First incr <key>, then Hset <key> <field> <value>. The two commands will be executed sequentially--when the script executes, Redis does nothing and it runs very fast.
We will visit two LUA tables: Keys and argv. Forms are the LUA unique mechanism of associative arrays and structured data. For our purposes, you can think of them as an array of arbitrary language equivalents that you are familiar with, but remind two of the two LUA rule that can easily plague beginners:
- The table is based on 1, which means that the index starts with a value of 1. So the first element in the table is mytable[1], and the second one is mytable[2] and so on.
- The table cannot have nil values. If there is [1, Nil, 3, 4] in an action table, the result will be that [the 1]--table will be truncated at the first nil.
When this script is invoked, we also need to pass values for the keys and argv tables:
Copy Code code as follows:
REDIS-CLI EVAL "$ (cat Incr-and-stor.lua)" 2 links:counter links:urls http://malcolmgladwellbookgenerator.com/
In the Eval statement, 2 indicates the number of keys that need to be passed in, followed by the two key that needs to be passed in, and the last pass is the argv value. When you execute a LUA script in Redis, REDIS-CLI checks the number of incoming keys unless the incoming command is complete.
To explain it more clearly, the following is a list of scripts to replace key and argv:
Copy Code code as follows:
Local link_id = Redis.call ("INCR", "Links:counter")
Redis.call ("Hset", "Links:urls", link_id, "http://malcolmgladwellbookgenerator.com")
Return link_id
When you write a LUA script for Redis, each key is specified by the keys table. The argv table is used to pass parameters, in this case the argv is used for passing in the URL.
Logical conditions: Increx and Hincrex
The previous example saves a link to a short URL, wants to know the number of clicks on the link, and adds a hash counter to the Redis. When a user with a link tag accesses, we check if it exists, and if so, add 1 to the counter:
Copy Code code as follows:
If Redis.call ("Hexists", Keys[1], argv[1) = = 1 Then
Return Redis.call ("HINCR", Keys[1], argv[1])
Else
return Nil
End
Every time someone clicks on a short URL, we run this script to track the link being shared again. We use Eval to invoke the script, pass in Inlinks:visits (Keys[1]) and the link identifier (ARGV[1] returned by the previous script).
This script will check for the existence of the same hash, if present, for this standard Redis key plus 1.
Copy Code code as follows:
If Redis.call ("EXISTS", keys[1]) = = 1 Then
Return Redis.call ("INCR", Keys[1])
Else
return Nil
End
Script Loading and registration execution
Note that when Redis is running the Lua script, nothing else can be done! The script is best to simply extend the Redis for smaller atomic operations and simple logical control needs, bugs in the Lua script can raise the entire Redis server lock-preferably keeping the script short and easy to debug.
While these scripts are generally short, we do not want to use the full Lua script every time we execute it, but we can actually register the Lua script (or register it when you deploy) in the program Step by step (application boots translation is difficult). It is then invoked using the SHA-1 identity generated after registration.
Copy Code code as follows:
REDIS-CLI SCRIPT LOAD "Return to ' Hello World '"
=> "5332031c6b470dc5a0dd9b4bf2030dea6d65de91"
REDIS-CLI Evalsha 5332031c6b470dc5a0dd9b4bf2030dea6d65de91 0
=> "Hello World"
It is usually not necessary to show call script load, which is implicitly loaded when a program executes Eval. The program will try Eavalsha first and call Eval when the script is not found.
For Ruby developers, you can look at the Shopify ' s Wolverine, which can simply load and store LUA scripts for Ruby applications. For PHP developers, Predis supports loading the Lua script as a normal Redis command (to inherit the Predis\command\scriptedcommand base class and register the command). If you use these or other tools to standardize your interactions with Lua, let me know, and I'm interested to know what's outside this article.
When to use Lua
Redis supports blocks such as watch/multi/exec, can perform a set of operations, and can be submitted for execution together, seemingly overlapping with Lua. How should you choose? All operations in the mult block are independent, but in Lua, subsequent operations can rely on the results of previous operations. Using the Lua script also avoids the watch of the client-side response after using the competition condition.
In Redisgreen, a foreign service provider dedicated to Redis mainframe, we see that many applications use LUA as well as multi/exec, but they are not an alternative relationship. Many successful Lua scripts are small, only to implement one of your application needs and Redis commands do not have a single function.
Access Library
Redis's LUA interpreter loads seven libraries: base,table,string, Math, Debug,cjson, and Cmsgpack. The first few are standard libraries that allow you to use any language for basic operations. The following two features are useful for Redis to support JSON and messagepack-, and I would like to know why it is often not seen.
Web applications often use JSON as an API to return data, and you might also be able to save a bunch of JSON data into a Redis key. When you want to access some JSON data, you first need to save it to a hash, and using Redis JSON support will be handy:
Copy Code code as follows:
If Redis.call ("EXISTS", keys[1]) = = 1 Then
Local payload = Redis.call (' Get ', keys[1])
return Cjson.decode (payload) [argv[1]]
Else
return Nil
End
Here we check to see if the key exists, if it does not exist, quickly return to nil. If present, get the JSON value from the Redis, parse it with Cjson.decode (), and then return the requested content.
Copy Code code as follows:
Redis-cli set apple ' {' Color ': ' Red ', ' type ': ' Fruit '} '
=> OK
REDIS-CLI eval "$ (cat Json-get.lua)" 1 apple type
=> "Fruit"
Load this script into your Redis server and save the JSON data to the Redis, usually hash. Although we have to parse every time we visit, the operation is actually very fast as long as your object is small.
If your API is provided in-house, it's usually a matter of efficiency, messagepack is a better choice than using JSON, it's smaller, faster, Redis (and more), and Messagepack is a better alternative to JSON.
Copy Code code as follows:
If Redis.call ("EXISTS", keys[1]) = = 1 Then
Local payload = Redis.call (' Get ', keys[1])
return Cmsgpack.unpack (payload) [argv[1]]
Else
return Nil
End
Numeric Conversions
Lua and Redis each have their own set of types, so it is important to understand the change in values caused by Redis and lua transitions between boundaries. When a number from LUA returns to the Redis client, it becomes integer-. The decimal point after any digit is cleared:
Copy Code code as follows:
Local INDIANA_PI = 3.2
Return INDIANA_PI
When you run the script, Redis returns an integer of 3 and loses the useful fragment in pi. It looks simple, but you need to be more careful when you start Redis with an intermediate script. For example:
Copy Code code as follows:
Local INDIANA_PI = 3.2
Redis.call ("SET", "PI", INDIANA_PI)
Return Redis.call ("Get", "PI")
The result of the execution is a string: "3.2", what is this for? There is no proprietary numeric type in Redis, and when we first call set, Redis has saved it as a string, and has lost it as the type information for a floating-point number when it initializes the LUA. So when we take this value out later, it becomes a string.
In Redis, the data accessed by other Get,set operations is treated as strings, in addition to INCR and DECR. INCR and DECR are specifically operations on numeric values, which actually return an integer (integer) reply (maintaining and storing compliance with numerical rules), but the Redis internal save type is actually a string value.
Summarize:
The following are common errors in using LUA in Redis:
- A table is an expression in Lua, which is different from many popular languages. The first element in the keys is keys[1], and the second is keys[2] (not the beginning of 0)
- Nil is the Terminator of the table, [1,2,nil,3] will automatically change to [1,2], so do not use nil in the table.
- Redis.call triggers an exception in Lua, Redis.pcall automatically captures all the errors that can be detected and returns the wrong content in the form of a table.
- The LUA numbers are converted to integers, the decimal points sent to Redis are lost, and they are converted to string types before they are returned.
- Make sure all keys used in Lua are in the key table, otherwise your scripts will be in danger of not being well supported in future Redis editions.
- The Lua script, like any other redis operation, is not able to run when the script executes. Consider using a script to protect your Redis server capability, but keep it short and useful.