The central object in StackExchange.Redis is the `ConnectionMultiplexer` class in the `StackExchange.Redis` namespace; this is the object that hides away the details of multiple servers. Because the `ConnectionMultiplexer` does a lot, it is designed to be **shared and reused** between callers. You should not create a `ConnectionMultiplexer` per operation. It is fully thread-safe and ready for this usage. In all the subsequent examples it will be assumed that you have a `ConnectionMultiplexer` instance stored away for re-use. But for now, let's create one. This is done using `ConnectionMultiplexer.Connect` or `ConnectionMultiplexer.ConnectAsync`, passing in either a configuration string or a `ConfigurationOptions` object. The configuration string can take the form of a comma-delimited series of nodes, so let's just connect to an instance on the local machine on the default port (6379):
The central object in StackExchange.Redis is the `ConnectionMultiplexer` class in the `StackExchange.Redis` namespace; this is the object that hides away the details of multiple servers. Because the `ConnectionMultiplexer` does a lot, it is designed to be **shared and reused** between callers. You should not create a `ConnectionMultiplexer` per operation. It is fully thread-safe and ready for this usage. In all the subsequent examples it will be assumed that you have a `ConnectionMultiplexer` instance stored away for re-use. But for now, let's create one. This is done using `ConnectionMultiplexer.Connect` or `ConnectionMultiplexer.ConnectAsync`, passing in either a configuration string or a `ConfigurationOptions` object. The configuration string can take the form of a comma-delimited series of nodes, so let's just connect to an instance on the local machine on the default port (6379):
@@ -14,7 +14,7 @@ Note that `ConnectionMultiplexer` implements `IDisposable` and can be disposed w
...
@@ -14,7 +14,7 @@ Note that `ConnectionMultiplexer` implements `IDisposable` and can be disposed w
A more complicated scenario might involve a master/slave setup; for this usage, simply specify all the desired nodes that make up that logical redis tier (it will automatically identify the master):
A more complicated scenario might involve a master/slave setup; for this usage, simply specify all the desired nodes that make up that logical redis tier (it will automatically identify the master):
The object returned from `GetDatabase` is a cheap pass-thru object, and does not need to be stored. Note that redis supports multiple databases (although this is not supported on "cluster"); this can be optionally specified in the call to `GetDatabase`. Additionally, if you plan to make use of the asynchronous API and you require the [`Task.AsyncState`][2] to have a value, this can also be specified:
The object returned from `GetDatabase` is a cheap pass-thru object, and does not need to be stored. Note that redis supports multiple databases (although this is not supported on "cluster"); this can be optionally specified in the call to `GetDatabase`. Additionally, if you plan to make use of the asynchronous API and you require the [`Task.AsyncState`][2] to have a value, this can also be specified:
Note that the `String...` prefix here denotes the [String redis type](http://redis.io/topics/data-types), and is largely separate to the [.NET String type][3], although both can store text data. However, redis allows raw binary data for both keys and values - the usage is identical:
Note that the `String...` prefix here denotes the [String redis type](http://redis.io/topics/data-types), and is largely separate to the [.NET String type][3], although both can store text data. However, redis allows raw binary data for both keys and values - the usage is identical:
```C#
```csharp
byte[]key=...,value=...;
byte[]key=...,value=...;
db.StringSet(key,value);
db.StringSet(key,value);
...
...
...
@@ -71,13 +71,13 @@ Using redis pub/sub
...
@@ -71,13 +71,13 @@ Using redis pub/sub
Another common use of redis is as a [pub/sub message](http://redis.io/topics/pubsub) distribution tool; this is also simple, and in the event of connection failure, the `ConnectionMultiplexer` will handle all the details of re-subscribing to the requested channels.
Another common use of redis is as a [pub/sub message](http://redis.io/topics/pubsub) distribution tool; this is also simple, and in the event of connection failure, the `ConnectionMultiplexer` will handle all the details of re-subscribing to the requested channels.
```C#
```csharp
ISubscribersub=redis.GetSubscriber();
ISubscribersub=redis.GetSubscriber();
```
```
Again, the object returned from `GetSubscriber` is a cheap pass-thru object that does not need to be stored. The pub/sub API has no concept of databases, but as before we can optionally provide an async-state. Note that all subscriptions are global: they are not scoped to the lifetime of the `ISubscriber` instance. The pub/sub features in redis use named "channels"; channels do not need to be defined in advance on the server (an interesting use here is things like per-user notification channels, which is what drives parts of the realtime updates on [Stack Overflow](http://stackoverflow.com)). As is common in .NET, subscriptions take the form of callback delegates which accept the channel-name and the message:
Again, the object returned from `GetSubscriber` is a cheap pass-thru object that does not need to be stored. The pub/sub API has no concept of databases, but as before we can optionally provide an async-state. Note that all subscriptions are global: they are not scoped to the lifetime of the `ISubscriber` instance. The pub/sub features in redis use named "channels"; channels do not need to be defined in advance on the server (an interesting use here is things like per-user notification channels, which is what drives parts of the realtime updates on [Stack Overflow](http://stackoverflow.com)). As is common in .NET, subscriptions take the form of callback delegates which accept the channel-name and the message:
Separately (and often in a separate process on a separate machine) you can publish to this channel:
Separately (and often in a separate process on a separate machine) you can publish to this channel:
```C#
```csharp
sub.Publish("messages","hello");
sub.Publish("messages","hello");
```
```
...
@@ -98,19 +98,19 @@ Accessing individual servers
...
@@ -98,19 +98,19 @@ Accessing individual servers
For maintenance purposes, it is sometimes necessary to issue server-specific commands:
For maintenance purposes, it is sometimes necessary to issue server-specific commands:
```C#
```csharp
IServerserver=redis.GetServer("localhost",6379);
IServerserver=redis.GetServer("localhost",6379);
```
```
The `GetServer` method will accept an [`EndPoint`](http://msdn.microsoft.com/en-us/library/system.net.endpoint(v=vs.110).aspx) or the name/value pair that uniquely identify the server. As before, the object returned from `GetServer` is a cheap pass-thru object that does not need to be stored, and async-state can be optionally specified. Note that the set of available endpoints is also available:
The `GetServer` method will accept an [`EndPoint`](http://msdn.microsoft.com/en-us/library/system.net.endpoint(v=vs.110).aspx) or the name/value pair that uniquely identify the server. As before, the object returned from `GetServer` is a cheap pass-thru object that does not need to be stored, and async-state can be optionally specified. Note that the set of available endpoints is also available:
```C#
```csharp
EndPoint[]endpoints=redis.GetEndPoints();
EndPoint[]endpoints=redis.GetEndPoints();
```
```
From the `IServer` instance, the [Server commands](http://redis.io/commands#server) are available; for example:
From the `IServer` instance, the [Server commands](http://redis.io/commands#server) are available; for example:
```C#
```csharp
DateTimelastSave=server.LastSave();
DateTimelastSave=server.LastSave();
ClientInfo[]clients=server.ClientList();
ClientInfo[]clients=server.ClientList();
```
```
...
@@ -131,7 +131,7 @@ The synchronous usage is already shown in the examples above. This is the simple
...
@@ -131,7 +131,7 @@ The synchronous usage is already shown in the examples above. This is the simple
For asynchronous usage, the key difference is the `Async` suffix on methods, and (typically) the use of the `await` language feature. For example:
For asynchronous usage, the key difference is the `Async` suffix on methods, and (typically) the use of the `await` language feature. For example:
The fire-and-forget usage is accessed by the optional `CommandFlags flags` parameter on all methods (defaults to none). In this usage, the method returns the default value immediately (so a method that normally returns a `String` will always return `null`, and a method that normally returns an `Int64` will always return `0`). The operation will continue in the background. A typical use-case of this might be to increment page-view counts:
The fire-and-forget usage is accessed by the optional `CommandFlags flags` parameter on all methods (defaults to none). In this usage, the method returns the default value immediately (so a method that normally returns a `String` will always return `null`, and a method that normally returns an `Int64` will always return `0`). The operation will continue in the background. A typical use-case of this might be to increment page-view counts:
Because there are lots of different ways to configure redis, StackExchange.Redis offers a rich configuration model, which is invoked when calling `Connect` (or `ConnectAsync`):
Because there are lots of different ways to configure redis, StackExchange.Redis offers a rich configuration model, which is invoked when calling `Connect` (or `ConnectAsync`):
This will connect to a single server on the local machine using the default redis port (6379). Additional options are simply appended (comma-delimited). Ports are represented with a colon (`:`) as is usual. Configuration *options* include an `=` after the name. For example:
This will connect to a single server on the local machine using the default redis port (6379). Additional options are simply appended (comma-delimited). Ports are represented with a colon (`:`) as is usual. Configuration *options* include an `=` after the name. For example:
@@ -98,7 +98,7 @@ Automatic and Manual Configuration
...
@@ -98,7 +98,7 @@ Automatic and Manual Configuration
In many common scenarios, StackExchange.Redis will automatically configure a lot of settings, including the server type and version, connection timeouts, and master/slave relationships. Sometimes, though, the commands for this have been disabled on the redis server. In this case, it is useful to provide more information:
In many common scenarios, StackExchange.Redis will automatically configure a lot of settings, including the server type and version, connection timeouts, and master/slave relationships. Sometimes, though, the commands for this have been disabled on the redis server. In this case, it is useful to provide more information:
A slightly unusual feature of redis is that you can disable and/or rename individual commands. As per the previous example, this is done via the `CommandMap`, but instead of passing a `HashSet<string>` to `Create()` (to indicate the available or unavailable commands), you pass a `Dictionary<string,string>`. All commands not mentioned in the dictionary are assumed to be enabled and not renamed. A `null` or blank value records that the command is disabled. For example:
A slightly unusual feature of redis is that you can disable and/or rename individual commands. As per the previous example, this is done via the `CommandMap`, but instead of passing a `HashSet<string>` to `Create()` (to indicate the available or unavailable commands), you pass a `Dictionary<string,string>`. All commands not mentioned in the dictionary are assumed to be enabled and not renamed. A `null` or blank value records that the command is disabled. For example:
```C#
```csharp
varcommands=newDictionary<string,string>{
varcommands=newDictionary<string,string>{
{"info",null},// disabled
{"info",null},// disabled
{"select","use"},// renamed to SQL equivalent for some reason
{"select","use"},// renamed to SQL equivalent for some reason
...
@@ -150,7 +150,7 @@ Twemproxy
...
@@ -150,7 +150,7 @@ Twemproxy
[Twemproxy](https://github.com/twitter/twemproxy) is a tool that allows multiple redis instances to be used as though it were a single server, with inbuilt sharding and fault tolerance (much like redis cluster, but implemented separately). The feature-set available to Twemproxy is reduced. To avoid having to configure this manually, the `Proxy` option can be used:
[Twemproxy](https://github.com/twitter/twemproxy) is a tool that allows multiple redis instances to be used as though it were a single server, with inbuilt sharding and fault tolerance (much like redis cluster, but implemented separately). The feature-set available to Twemproxy is reduced. To avoid having to configure this manually, the `Proxy` option can be used:
```C#
```csharp
varoptions=newConfigurationOptions
varoptions=newConfigurationOptions
{
{
EndPoints={"my-server"},
EndPoints={"my-server"},
...
@@ -176,7 +176,7 @@ ReconnectRetryPolicy can be linear (default), exponential or a custom retry poli
...
@@ -176,7 +176,7 @@ ReconnectRetryPolicy can be linear (default), exponential or a custom retry poli
Examples:
Examples:
```C#
```csharp
config.ReconnectRetryPolicy=newExponentialRetry(5000);// defaults maxDeltaBackoff to 10000 ms
config.ReconnectRetryPolicy=newExponentialRetry(5000);// defaults maxDeltaBackoff to 10000 ms
//retry# retry to re-connect after time in milliseconds
//retry# retry to re-connect after time in milliseconds
StackExchange.Redis represents keys by the `RedisKey` type. The good news, though, is that this has implicit conversions to and from both `string` and `byte[]`, allowing both text and binary keys to be used without any complication. For example, the `StringIncrement` method takes a `RedisKey` as the first parameter, but *you don't need to know that*; for example:
StackExchange.Redis represents keys by the `RedisKey` type. The good news, though, is that this has implicit conversions to and from both `string` and `byte[]`, allowing both text and binary keys to be used without any complication. For example, the `StringIncrement` method takes a `RedisKey` as the first parameter, but *you don't need to know that*; for example:
```C#
```csharp
stringkey=...
stringkey=...
db.StringIncrement(key);
db.StringIncrement(key);
```
```
or
or
```C#
```csharp
byte[]key=...
byte[]key=...
db.StringIncrement(key);
db.StringIncrement(key);
```
```
Likewise, there are operations that *return* keys as `RedisKey` - and again, it simply works:
Likewise, there are operations that *return* keys as `RedisKey` - and again, it simply works:
```C#
```csharp
stringsomeKey=db.KeyRandom();
stringsomeKey=db.KeyRandom();
```
```
...
@@ -41,13 +41,13 @@ Values
...
@@ -41,13 +41,13 @@ Values
StackExchange.Redis represents values by the `RedisValue` type. As with `RedisKey`, there are implicit conversions in place which mean that most of the time you never see this type, for example:
StackExchange.Redis represents values by the `RedisValue` type. As with `RedisKey`, there are implicit conversions in place which mean that most of the time you never see this type, for example:
```C#
```csharp
db.StringSet("mykey","myvalue");
db.StringSet("mykey","myvalue");
```
```
However, in addition to text and binary contents, values can also need to represent typed primitive data - most commonly (in .NET terms) `Int32`, `Int64`, `Double` or `Boolean`. Because of this, `RedisValue` provides a lot more conversion support than `RedisKey`:
However, in addition to text and binary contents, values can also need to represent typed primitive data - most commonly (in .NET terms) `Int32`, `Int64`, `Double` or `Boolean`. Because of this, `RedisValue` provides a lot more conversion support than `RedisKey`:
```C#
```csharp
db.StringSet("mykey",123);// this is still a RedisKey and RedisValue
db.StringSet("mykey",123);// this is still a RedisKey and RedisValue
...
...
inti=(int)db.StringGet("mykey");
inti=(int)db.StringGet("mykey");
...
@@ -57,14 +57,14 @@ Note that while the conversions from primitives to `RedisValue` are implicit, ma
...
@@ -57,14 +57,14 @@ Note that while the conversions from primitives to `RedisValue` are implicit, ma
Note additionally that *when treated numerically*, redis treats a non-existent key as zero; for consistency with this, nil responses are treated as zero:
Note additionally that *when treated numerically*, redis treats a non-existent key as zero; for consistency with this, nil responses are treated as zero:
```C#
```csharp
db.KeyDelete("abc");
db.KeyDelete("abc");
inti=(int)db.StringGet("abc");// this is ZERO
inti=(int)db.StringGet("abc");// this is ZERO
```
```
If you need to detect the nil condition, then you can check for that:
If you need to detect the nil condition, then you can check for that:
```C#
```csharp
db.KeyDelete("abc");
db.KeyDelete("abc");
varvalue=db.StringGet("abc");
varvalue=db.StringGet("abc");
boolisNil=value.IsNull;// this is true
boolisNil=value.IsNull;// this is true
...
@@ -72,7 +72,7 @@ bool isNil = value.IsNull; // this is true
...
@@ -72,7 +72,7 @@ bool isNil = value.IsNull; // this is true
or perhaps more simply, just use the provided `Nullable<T>` support:
or perhaps more simply, just use the provided `Nullable<T>` support:
```C#
```csharp
db.KeyDelete("abc");
db.KeyDelete("abc");
varvalue=(int?)db.StringGet("abc");// behaves as you would expect
varvalue=(int?)db.StringGet("abc");// behaves as you would expect
```
```
...
@@ -97,7 +97,7 @@ Scripting
...
@@ -97,7 +97,7 @@ Scripting
Because of this, the `ScriptEvaluate` method accepts two separate input arrays: one `RedisKey[]` for the keys, one `RedisValue[]` for the values (both are optional, and are assumed to be empty if omitted). This is probably one of the few times that you'll actually need to type `RedisKey` or `RedisValue` in your code, and that is just because of array variance rules:
Because of this, the `ScriptEvaluate` method accepts two separate input arrays: one `RedisKey[]` for the keys, one `RedisValue[]` for the values (both are optional, and are assumed to be empty if omitted). This is probably one of the few times that you'll actually need to type `RedisKey` or `RedisValue` in your code, and that is just because of array variance rules:
@@ -106,7 +106,7 @@ var result = db.ScriptEvaluate(TransferScript,
...
@@ -106,7 +106,7 @@ var result = db.ScriptEvaluate(TransferScript,
The response uses the `RedisResult` type (this is unique to scripting; usually the API tries to represent the response as directly and clearly as possible). As before, `RedisResult` offers a range of conversion operations - more, in fact than `RedisValue`, because in addition to being interpreted as text, binary, primitives and nullable-primitives, the response can *also* be interpreted as *arrays* of such, for example:
The response uses the `RedisResult` type (this is unique to scripting; usually the API tries to represent the response as directly and clearly as possible). As before, `RedisResult` offers a range of conversion operations - more, in fact than `RedisValue`, because in addition to being interpreted as text, binary, primitives and nullable-primitives, the response can *also* be interpreted as *arrays* of such, for example:
Latency sucks. Modern computers can churn data at an alarming rate, and high speed networking (often with multiple parallel links between important servers) provides enormous bandwidth, but... that damned latency means that computers spend an awful lot of time *waiting for data* and that is one of the several reasons that continuation-based programming is becoming increasingly popular. Let's consider some regular procedural code:
Latency sucks. Modern computers can churn data at an alarming rate, and high speed networking (often with multiple parallel links between important servers) provides enormous bandwidth, but... that damned latency means that computers spend an awful lot of time *waiting for data* and that is one of the several reasons that continuation-based programming is becoming increasingly popular. Let's consider some regular procedural code:
```C#
```csharp
stringa=db.StringGet("a");
stringa=db.StringGet("a");
stringb=db.StringGet("b");
stringb=db.StringGet("b");
```
```
...
@@ -42,7 +42,7 @@ Because of this, many redis clients allow you to make use of *pipelining*; this
...
@@ -42,7 +42,7 @@ Because of this, many redis clients allow you to make use of *pipelining*; this
For example, to pipeline the two gets using procedural (blocking) code, we could use:
For example, to pipeline the two gets using procedural (blocking) code, we could use:
```C#
```csharp
varaPending=db.StringGetAsync("a");
varaPending=db.StringGetAsync("a");
varbPending=db.StringGetAsync("b");
varbPending=db.StringGetAsync("b");
vara=db.Wait(aPending);
vara=db.Wait(aPending);
...
@@ -56,7 +56,7 @@ Fire and Forget
...
@@ -56,7 +56,7 @@ Fire and Forget
A special-case of pipelining is when we expressly don't care about the response from a particular operation, which allows our code to continue immediately while the enqueued operation proceeds in the background. Often, this means that we can put concurrent work on the connection from a single caller. This is achieved using the `flags` parameter:
A special-case of pipelining is when we expressly don't care about the response from a particular operation, which allows our code to continue immediately while the enqueued operation proceeds in the background. Often, this means that we can put concurrent work on the connection from a single caller. This is achieved using the `flags` parameter:
@@ -71,7 +71,7 @@ Pipelining is all well and good, but often any single block of code only wants a
...
@@ -71,7 +71,7 @@ Pipelining is all well and good, but often any single block of code only wants a
For this reason, the only redis features that StackExchange.Redis does not offer (and *will not ever offer*) are the "blocking pops" ([BLPOP](http://redis.io/commands/blpop), [BRPOP](http://redis.io/commands/brpop) and [BRPOPLPUSH](http://redis.io/commands/brpoplpush)) - because this would allow a single caller to stall the entire multiplexer, blocking all other callers. The only other time that StackExchange.Redis needs to hold work is when verifying pre-conditions for a transaction, which is why StackExchange.Redis encapsulates such conditions into internally managed `Condition` instances. [Read more about transactions here](Transactions). If you feel you want "blocking pops", then I strongly suggest you consider pub/sub instead:
For this reason, the only redis features that StackExchange.Redis does not offer (and *will not ever offer*) are the "blocking pops" ([BLPOP](http://redis.io/commands/blpop), [BRPOP](http://redis.io/commands/brpop) and [BRPOPLPUSH](http://redis.io/commands/brpoplpush)) - because this would allow a single caller to stall the entire multiplexer, blocking all other callers. The only other time that StackExchange.Redis needs to hold work is when verifying pre-conditions for a transaction, which is why StackExchange.Redis encapsulates such conditions into internally managed `Condition` instances. [Read more about transactions here](Transactions). If you feel you want "blocking pops", then I strongly suggest you consider pub/sub instead:
```C#
```csharp
sub.Subscribe(channel,delegate{
sub.Subscribe(channel,delegate{
stringwork=db.ListRightPop(key);
stringwork=db.ListRightPop(key);
if(work!=null)Process(work);
if(work!=null)Process(work);
...
@@ -96,7 +96,7 @@ Concurrency
...
@@ -96,7 +96,7 @@ Concurrency
It should be noted that the pipeline / multiplexer / future-value approach also plays very nicely with continuation-based asynchronous code; for example you could write:
It should be noted that the pipeline / multiplexer / future-value approach also plays very nicely with continuation-based asynchronous code; for example you could write:
@@ -12,7 +12,7 @@ This works *particularly* well if messages are generally unrelated.
...
@@ -12,7 +12,7 @@ This works *particularly* well if messages are generally unrelated.
For safety, **the default is sequential**; however, it is strongly recommended that you use concurrent processing whenever possible. This is a simple change:
For safety, **the default is sequential**; however, it is strongly recommended that you use concurrent processing whenever possible. This is a simple change:
It should also be noted that many common scenarios (in particular: key/hash existence, like in the above) have been anticipated by Redis, and single-operation
It should also be noted that many common scenarios (in particular: key/hash existence, like in the above) have been anticipated by Redis, and single-operation
atomic commands exist. These are accessed via the `When` parameter - so our previous example can *also* be written as:
atomic commands exist. These are accessed via the `When` parameter - so our previous example can *also* be written as: