Connection Refused error in Terminal Your server’s SSH daemon may be down for a wide variety of reasons, including unexpected traffic spikes, resource outages, or even a Distributed Denial of Service (DDoS) attack. See also: Could not connect to Redis at 127.0.0.1:6379: Connection refused. Running this will print “Hello, world!”. The first argument of EVAL is the complete lua script — here we’re using the cat command to read the script from a file.
You’ve heard that Redis has an embedded scripting language, but haven’t given ita try yet? Here’s a tour of what you need to understand to use thepower of Lua with your Redis server.
Hello, Lua!
Our first Redis Lua script just returns a value without actually interacting withRedis in any meaningful way:
This is as simple as it gets. The first line sets up a local variable with ourmessage, and the second line returns that value from the Redis server to theclient. Save this file locally as hello.lua
and run it like so:
Connectivity Problems?
This redis-cli
example assumes that you're running a Redisserver locally. If you're working with a remote server like RedisGreen, you'llneed to specify host and port information. Find the Connect button onyour RedisGreen dashboard to quickly copy the login info for your server.
See also: Could not connectto Redis at 127.0.0.1:6379: Connection refused.
Running this will print “Hello, world!”. The first argument ofEVAL
is the complete lua script — here we’re using the cat
command to read the script from a file. The second argument is the number of Rediskeys that the script will access. Our simple “Hello World” script doesn’taccess any keys, so we use 0
.
Accessing Keys and Arguments
Suppose we’re building a URL-shortener. Each time a URL comes in we want to storeit and return a unique number that can be usedto access the URL later.
We’ll use a Lua script to get a unique ID from Redis using INCR
andimmediately store the URL in a hash that is keyed by the unique ID:
We’re accessing Redis for the first time here, using the call()
function.call()
’s arguments are the commands to send to Redis: first we INCR <key>
,then we HSET <key> <field> <value>
. These two commands will run sequentially— Redis won’t do anything else while this script executes, and it will runextremely quickly.
We’re accessing two Lua tables, KEYS
and ARGV
. Tables are associativearrays, and Lua’s only mechanism for structuring data. For ourpurposes you can think of them as the equivalent of an array in whateverlanguage you’re most comfortable with, but note these two Lua-isms that trip upfolks new to the language:
Tables are one-based, that is, indexing starts at 1. So the first element in
mytable
ismytable[1]
, the second ismytable[2]
, etc.Tables cannot hold nil values. If an operation would yield a table of
[ 1,nil, 3, 4 ]
, the result will instead be[ 1 ]
— the table istruncated at the first nil value.
When we invoke this script, we need to also pass along the values for the KEYS
and ARGV
tables. In the raw Redis protocol, the command looks like this:
When calling EVAL
, after the script we provide 2
as the number ofKEYS
that will be accessed, then we list our KEYS
, and finally we providevalues for ARGV
.
Normally when we build apps with Redis Lua scripts, the Redisclient library will take care of specifying the number of keys. The above codeblock is shown for completeness, but here’s the easier way to do this on at thecommand line:
When using --eval
as above, the comma separates KEYS[]
from ARGV[]
items.
Just to make things clear, here’s our original script again, this time withKEYS
and ARGV
expanded:
When writing Lua scripts for Redis, every key that isaccessed should be accessed only by the KEYS
table. The ARGV
table is used for parameter-passing — here it’s the value ofthe URL we want to store.
Conditional Logic: increx and hincrex
Our example above saves the link for our URL-shortener, but we also need totrack the number of times a URL has been accessed. To do that we’ll keep acounter in a hash in Redis. When a user comes along with a link identifier,we’ll check to see if it exists, and increment our counter for it if it does:
Each time someone clicks on a shortlink, we run this script to track that thelink was shared again. We invoke the script using EVAL
and pass inlinks:visits
for our single key and the link identifier returned from ourprevious script as the single argument.
The script would look almost the same without hashes. Here’s ascript which increments a standard Redis key only if it exists:
SCRIPT LOAD and EVALSHA
Remember that when Redis is running a Lua script, it will not run anything else.The best scripts simply extend the existing Redis vocabulary of small atomic dataoperations with the smallest bit of logic necessary. Bugs in Lua scripts can lockup a Redis server altogether — best to keep things short and easy to debug.
Even though they’re usually quite short, we need not specify the full Lua scripteach time we want to run one. In a real application you’ll instead register eachof your Lua scripts with Redis when your application boots (or when you deploy),then call the scripts later by their unique SHA-1 identifier.
An explicit call to SCRIPT LOAD
is usually unnecessary in a live applicationsince EVAL
implicitly loads the script that is passed to it. An applicationcan attempt to EVALSHA
optimistically and fall back to EVAL
only if the scriptis not found.
If you’re a Ruby programmer, take a look at Shopify’s Wolverine,which simplifies the loading and storing of Lua scripts for Ruby apps. For PHPprogrammers, Predis supports adding Luascripts to be called just as though they were normal Redis commands. If youuse these or other tools to standardize your interaction with Lua, let me know— I’d be interested to find out what else is out there.
When to use Lua?
Redis support for Lua overlaps somewhat with WATCH
/MULTI
/EXEC
blocks, which group operations so they are executed together. So how do youchoose to use one over the other? Each operation in a MULTI
block needs to beindependent, but with Lua, later operations candepend on the results of earlier operations. Using Lua scripts can also avoidrace conditions that can starve slow clients when WATCH
is used.
From what we’ve seen at RedisGreen, most apps that use Lua will also useMULTI/EXEC, but not vice versa. Most successful Lua scripts are tiny, and justimplement a single feature that your app needs but isn’t a part of the Redisvocabulary.
Visiting the Library
The Redis Lua interpreter loads seven libraries: base, table,string,math,debug,cjson,and cmsgpack. The firstseveral are standard libraries that allow you to do the basic operations you’dexpect from any language. The last two let Redis understand JSON and MessagePack— this is an extremely useful feature, and I keep wondering why I don’tsee it used more often.
Web apps with public APIs tend to have JSON lying around all over. So maybe youhave a bunch of JSON blobs stored in normal Redis keys and you want to accesssome particular values inside of them, as though you had stored them as a hash.With Redis JSON support, that’s easy:
Here we check to see if the key exists and quickly return nil if not. Then weget the JSON value out of Redis, parse it with cjson.decode()
, and return therequested value.
Loading this script into your Redis server lets you treat JSON values stored inRedis as though they were hashes. If your objects are reasonably small, this isactually quite fast, even though we have to parse the value on each access.
If you’re working on an internal API for a system that demands performance,you’re likely to choose MessagePack over JSON, as it’s smaller and faster.Luckily with Redis (as in most places), MessagePack is pretty much a drop-inreplacement for JSON:
Crunching Numbers
Lua and Redis have different type systems, so it’s important to understandhow values may change when crossing the Redis-Lua border. When a number comes fromLua back to a Redis client, it becomes aninteger — any digits past the decimal point are dropped:
When you run this script, Redis will return an integer of 3 — you lose theinteresting pieces of pi. Seems simple enough, but things get a bit more trickywhen you start interacting with Redis in the middle of the script. An example:
The resulting value here is astring: '3.2'
Why? Redis doesn’t have a dedicated numeric type. When we first SET
the value, Redis saves it as a string, losing all record of the fact that Lua initially thought of the value as a float. When we pull the value out later, it’s still a string.
Values in Redis that are accessed with GET
/SET
should be thought of as strings exceptwhen numeric operations like INCR
and DECR
are run against them. Thesespecial numeric operations will actually return integer replies (andmanipulate the stored value according to mathematical rules), but the“type” of the value stored in Redis is still a string value.
Gotchas: A Summary
These are the most common errors that we see when working with Lua in Redis:
Tables are one-based in Lua, unlike most popular languages. Thefirst element in the KEYS table is
KEYS[1]
, the second isKEYS[2]
,etc.A nil value terminates a table in Lua. So
[ 1, 2, nil, 3 ]
willautomatically become[1, 2]
. Don’t use nil values in tables.redis.call
will raise exception-style Lua errors, whileredis.pcall
will automatically trap any errors and return them astables that can be inspected.Lua numbers are converted to integers when being sent to Redis — everythingpast the decimal point is lost. Convert any floating point numbers to stringsbefore returning them.
Be sure to specify all the keys you use in your Lua scripts in the
KEYS
table, otherwise your scripts will probably break in future versions ofRedis.Lua scripts are just like any other operation in Redis: nothing else runswhile they’re being executed. Think ofscripts as a way to expand the vocabulary of the Redis server — keep themshort and to-the-point.
Further Reading
There are lots of great resources for Lua and Redis online — here are a few Iuse:
This document provides information about how Redis handles clients from the point of view of the network layer: connections, timeouts, buffers, and other similar topics are covered here.
The information contained in this document is only applicable to Redis version 2.6 or greater.
*How client connections are accepted
Redis accepts clients connections on the configured listening TCP port and on the Unix socket if enabled. When a new client connection is accepted the following operations are performed:
- The client socket is put in non-blocking state since Redis uses multiplexing and non-blocking I/O.
- The
TCP_NODELAY
option is set in order to ensure that we don't have delays in our connection. - A readable file event is created so that Redis is able to collect the client queries as soon as new data is available to be read on the socket.
After the client is initialized, Redis checks if we are already at the limit of the number of clients that it is possible to handle simultaneously (this is configured using the maxclients
configuration directive, see the next section of this document for further information).
In case it can't accept the current client because the maximum number of clients was already accepted, Redis tries to send an error to the client in order to make it aware of this condition, and closes the connection immediately. The error message will be able to reach the client even if the connection is closed immediately by Redis because the new socket output buffer is usually big enough to contain the error, so the kernel will handle the transmission of the error.
*In what order clients are served
The order is determined by a combination of the client socket file descriptor number and order in which the kernel reports events, so the order is to be considered as unspecified.
However Redis does the following two things when serving clients:
- It only performs a single
read()
system call every time there is something new to read from the client socket, in order to ensure that if we have multiple clients connected, and a few are very demanding clients sending queries at an high rate, other clients are not penalized and will not experience a bad latency figure. - However once new data is read from a client, all the queries contained in the current buffers are processed sequentially. This improves locality and does not need iterating a second time to see if there are clients that need some processing time.
*Maximum number of clients
In Redis 2.4 there was a hard-coded limit for the maximum number of clients that could be handled simultaneously.
In Redis 2.6 this limit is dynamic: by default it is set to 10000 clients, unless otherwise stated by the maxclients
directive in Redis.conf.
However, Redis checks with the kernel what is the maximum number of file descriptors that we are able to open (the soft limit is checked). If the limit is smaller than the maximum number of clients we want to handle, plus 32 (that is the number of file descriptors Redis reserves for internal uses), then the number of maximum clients is modified by Redis to match the amount of clients we are really able to handle under the current operating system limit.
When the configured number of maximum clients can not be honored, the condition is logged at startup as in the following example:
When Redis is configured in order to handle a specific number of clients it is a good idea to make sure that the operating system limit to the maximum number of file descriptors per process is also set accordingly.
Under Linux these limits can be set both in the current session and as a system-wide setting with the following commands:
- ulimit -Sn 100000 # This will only work if hard limit is big enough.
- sysctl -w fs.file-max=100000
*Output buffers limits
Redis needs to handle a variable-length output buffer for every client, since a command can produce a big amount of data that needs to be transferred to the client.
However it is possible that a client sends more commands producing more output to serve at a faster rate at which Redis can send the existing output to the client. This is especially true with Pub/Sub clients in case a client is not able to process new messages fast enough.
Redis Cli Connection Refused
Both the conditions will cause the client output buffer to grow and consume more and more memory. For this reason by default Redis sets limits to the output buffer size for different kind of clients. When the limit is reached the client connection is closed and the event logged in the Redis log file.
There are two kind of limits Redis uses:
- The hard limit is a fixed limit that when reached will make Redis closing the client connection as soon as possible.
- The soft limit instead is a limit that depends on the time, for instance a soft limit of 32 megabytes per 10 seconds means that if the client has an output buffer bigger than 32 megabytes for, continuously, 10 seconds, the connection gets closed.
Different kind of clients have different default limits:
- Normal clients have a default limit of 0, that means, no limit at all, because most normal clients use blocking implementations sending a single command and waiting for the reply to be completely read before sending the next command, so it is always not desirable to close the connection in case of a normal client.
- Pub/Sub clients have a default hard limit of 32 megabytes and a soft limit of 8 megabytes per 60 seconds.
- Slaves have a default hard limit of 256 megabytes and a soft limit of 64 megabyte per 60 second.
It is possible to change the limit at runtime using the CONFIG SET command or in a permanent way using the Redis configuration file redis.conf
. See the example redis.conf
in the Redis distribution for more information about how to set the limit.
*Query buffer hard limit
Every client is also subject to a query buffer limit. This is a non-configurable hard limit that will close the connection when the client query buffer (that is the buffer we use to accumulate commands from the client) reaches 1 GB, and is actually only an extreme limit to avoid a server crash in case of client or server software bugs.
*Client timeouts
By default recent versions of Redis don't close the connection with the client if the client is idle for many seconds: the connection will remain open forever.
However if you don't like this behavior, you can configure a timeout, so that if the client is idle for more than the specified number of seconds, the client connection will be closed.
You can configure this limit via redis.conf
or simply using CONFIG SET timeout <value>
.
Note that the timeout only applies to normal clients and it does not apply to Pub/Sub clients, since a Pub/Sub connection is a push style connection so a client that is idle is the norm.
Even if by default connections are not subject to timeout, there are two conditions when it makes sense to set a timeout:
- Mission critical applications where a bug in the client software may saturate the Redis server with idle connections, causing service disruption.
- As a debugging mechanism in order to be able to connect with the server if a bug in the client software saturates the server with idle connections, making it impossible to interact with the server.
Timeouts are not to be considered very precise: Redis avoids to set timer events or to run O(N) algorithms in order to check idle clients, so the check is performed incrementally from time to time. This means that it is possible that while the timeout is set to 10 seconds, the client connection will be closed, for instance, after 12 seconds if many clients are connected at the same time.
*CLIENT command
The Redis client command allows to inspect the state of every connected client, to kill a specific client, to set names to connections. It is a very powerful debugging tool if you use Redis at scale.
CLIENT LIST is used in order to obtain a list of connected clients and their state:
In the above example session two clients are connected to the Redis server. The meaning of a few of the most interesting fields is the following:
- addr: The client address, that is, the client IP and the remote port number it used to connect with the Redis server.
- fd: The client socket file descriptor number.
- name: The client name as set by CLIENT SETNAME.
- age: The number of seconds the connection existed for.
- idle: The number of seconds the connection is idle.
- flags: The kind of client (N means normal client, check the full list of flags).
- omem: The amount of memory used by the client for the output buffer.
- cmd: The last executed command.
See the CLIENT LIST documentation for the full list of fields and their meaning.
Redis Connection Refused
Once you have the list of clients, you can easily close the connection with a client using the CLIENT KILL command specifying the client address as argument.
The commands CLIENT SETNAME and CLIENT GETNAME can be used to set and get the connection name. Starting with Redis 4.0, the client name is shown in the SLOWLOG output, so that it gets simpler to identify clients that are creating latency issues.
Redis Connection Refused Mac Download
*TCP keepalive
Recent versions of Redis (3.2 or greater) have TCP keepalive (SO_KEEPALIVE
socket option) enabled by default and set to about 300 seconds. This option is useful in order to detect dead peers (clients that cannot be reached even if they look connected). Moreover, if there is network equipment between clients and servers that need to see some traffic in order to take the connection open, the option will prevent unexpected connection closed events.