-
Notifications
You must be signed in to change notification settings - Fork 1
Connection management
- Per connection management.
- Connection pools.
- Shared commander pool.
- Exclusive commander pool.
- Shared subscriber pool.
- Command Routing.
- Simple example.
- Simple example with subscription.
- Exclusive example.
- Mixed example.
vtortola.RedisClient API has two fundamental parts:
-
RedisClient
class handles the connection management. Usually you have one instance across all your AppDomain (or two instances if you have master/slave). It is a thread safe object, that usually is cached for the extend of your application lifetime. -
IRedisChannel
interface is used to execute commands. Channels are short lived, cheap to create, non-thread safe objects that represent virtual connections to Redis. Channels provide seamless access to commander and subscriber connections, analyze commands and decide how to route them through the three connection pools (multiplexed, exclusive and subscription).
Connections run initialization routines automatically right after connecting (or reconnecting).
- Commander connections: Check for the existence of the required procedures and deploy the ones that do not exist.
- Subscriber connections: Reestablish all the subscriptions of the channels that were operating through that connection if any.
They automatically reconnect in case of disconnection. RedisClient
has a constructor overload the accepts a collection of IPEndPoint
rather than a single one. Connections start by using the first one and in case of SocketException
they choose the next endpoint in rota basis.
var endpoints = new []
{
new IPEndPoint(IPAddress.Parse("10.0.0.1"), 6379),
new IPEndPoint(IPAddress.Parse("10.0.0.2"), 6379);
}
_client = new RedisClient(endpoints))
await _client.ConnectAsync(CancellationToken.None).ConfigureAwait(false);
There is possibility of running pre-initialization commands that will be executed even before than the initialization routines. For example, if the Redis instance requires authentication you must execute AUTH <password>
in first place.
var options = new RedisClientOptions();
var authCommand = new PreInitializationCommand("auth @password", new { password = "yourpassword" });
options.InitializationCommands.Add(authCommand);
Multiple parameters of the connections can be tweaked throw the configuration options.
The client uses three connection pools:
- Shared commander pool.
- Exclusive commander pool.
- Shared subscriber pool.
Which pool is selected for which command is done transparently by the channel.
It is a pool of TCP connections that are shared across all channels. When a command needs to be executed, first TCP idle connection or the one with less load is selected to execute the command and handle the result to the caller. Commands from multiple channels can be executed safely through the same TCP connection thanks to multiplexing and pipelining, so thousands of channels may be operating through a handful of TCP connections seamlessly.
The shared commander pool is configured through RedisClientOptions.MultiplexPoolOptions.CommandConnections
, where an integer indicates how many connections you want to keep in the shared commander pool.
This is the faster commander pool.
Read more about available options.
####Exclusive commander pool It is a pool of TCP connections from which a connection can be selected for exclusive use, and return it when the use is done. There are situations where some commands, or sequence of commands, require to be executed in a individual connection. Channels are able of identifying these situations, hold a exclusive connection, and return to multiplex mode when done. Situations where an exclusive connection is used are:
- The use or blocking operations, like
BRPOP
,BLPOP
andBRPOPLPUSH
. When the command returns the connection is returned to the exclusive pool. - Leaving open a transaction with
MULTI
. WhenEXEC
orDISCARD
is executed, the connection will be returned to the exclusive pool. - Leaving open a watch with
WATCH
. WhenEXEC
,DISCARD
orUNWATCH
is executed, the connection will be returned to the exclusive pool.
Obviously the exclusive pool is less performant than the shared pool. The most of the times you will use the exclusive pool is because you need optimistic concurrency using WATCH
like in this example. A way to prevent this is the use of LUA scripts, that in vtortola.RedisClient is done through procedures is preferred.
The shared commander pool is configured through RedisClientOptions.ExclusivePoolOptions
, where two integers control the maximum and minimum number of connections you want to have in the shared pool.
Read more about available options.
It is another pool of TCP connections that are shared across all channels like the shared commander pool that also uses multiplexing and pipelining. The statements that contains Redis commands about subscription management are executed in the first TCP idle subscriber connection or the one with less load.
The channel holds this subscriber connection as its assigned subscriber connection for further subscription commands. Each subscriber connection manages which channels have subscriptions on going and is able to route the MESSAGE
and PMESSAGE
messages to the appropriate ones. One important feature of the subscriber connections, is that it aggregates the subscriptions of the channels it has been assigned too.
Read more about subscribing to topics.
Depending on the structure of your command, statements can be routed to different connections seamlessly. A channel will route each statement to the appropriate connection and return a command execution result when all commands have been executed in their respective connections, so you always get a complete result.
The exclusive pool is disabled by default, since the aim of this component is to use procedures instead of WATCH
or multiple round trips to the server. However, if you need to enable it, just give values to the exclusive pool options.
Note: for the sake of the examples, parameter binding is not being used, but performance wise is very unrecomended to use it this way. Read more about parameter binding.
In this simple command, both statements will be sent to the shared commander pool. Remember that although they travel one after the other in the same connection, still Redis may interpolate other commands between them, so remember to use MULTI
if you want to execute them like a single unit.
channel.Execute(@"
incr keyA
incr keyB
");
In this example, first statement will be executed in the shared commander pool, the second will be executed in the shared subscriber pool. Also, the channel with remember the selected subscriber connection and will use it from now until IRedisChannel.Dispose()
is called.
channel.Execute(@"
incr keyA
subscribe topicB
");
This command will get a exclusive connection, execute the command and release it back to the pool when the command returns.
var result = channel.Execute("brpop listA");
This command will get a exclusive connection, execute the command and release it back to the pool when the command returns.
// Uses shared commander pool
channel.Execute("incr counter");
// Because the unclosed `WATCH`, a connection from the exclusive
// pool is used. The channel will hold it until it can be released.
var result = channel.Execute(@"
WATCH mykey
GET mykey");
if(result[1].GetString() != expectedValue)
{
// Command is executed in the held exclusive connection.
// After execution, connection is returned to the pool.
channel.Execute("UNWATCH");
}
else
{
// Command is executed in the held exclusive connection.
// Because the final `EXEC` the connection is returned
// back to the exclusive pool.
result = channel.Execute(@"
MULTI
SET mykey 'whatever value you want'
INCR ops
EXEC");
}
// Again the shared commander pool is used
channel.Execute("incr another:counter");