RESP2 and RESP3 are evolutions of the Redis protocol, with RESP3 existing from Redis server version 6 onwards (v7.2+ for Redis Enterprise). The main differences are:
For many users, using RESP3 is a “no-brainer” - it offers significant benefits with no real downsides. However, there are some important things to be aware of, and some
migration work that may be required. In particular, some commands return different result structures in RESP3 mode; for example a jagged (nested) array might become a “map”
(essentially an interleaved flat array). SE.Redis has been updated to handle these cases transparently, but if you are using Execute[Async] or ScriptEvaluate[Async] (or if
you are using an additional library that issues ad-hoc commands or scripts on your behalf) you may need to update your processing code to compensate for this. This is discussed more below.
RESP2 and RESP3 are both supported options (if the server does not support RESP3, RESP2 will always be used). To make full use of the benefits of RESP3, the library is moving in the direction of preferring RESP3. The default behaviour is:
| Library version | Endpoint | Default protocol |
|---|---|---|
| < 2.13 | (any) | RESP2 |
| >= 2.13 and < 3.0 | (non-AMR) | RESP2 |
| >= 2.13 and < 3.0 | AMR | RESP3 |
| > 3.0† | (any) | RESP3 |
† = planned
You can override this behaviour by setting the protocol option in the connection string, or by setting the ConfigurationOptions.Protocol property:
var options = ConfigurationOptions.Parse("someserver");
options.Protocol = RedisProtocol.Resp3; // or .Resp2
var muxer = await ConnectionMultiplexer.ConnectAsync(options);
or
var options = ConfigurationOptions.Parse("someserver,protocol=resp3"); // or =resp2
var muxer = await ConnectionMultiplexer.ConnectAsync(options);
You can use this configuration to explicitly enable RESP3 on earlier library versions, or to explicitly disable RESP3 on later versions, if you encounter issues.
For most users, no additional work will be required, or the additional work may be limited to updating libraries; for example, For example, NRedisStack now fully supports RESP3 for the commands it exposes (search, json, time-series, etc).
Scenarios impacted by RESP3 include:
ScriptEvaluate[Async](...) or related APIs, that either:
redis.setresp(3) API and returns a value from redis.[p]call(...)Execute[Async](string command, ...) APIThis delta is especially pronounced for some of the “modules” in Redis, even those that now ship by default in OSS Redis, including:
FT.SEARCH, FT.AGGREGATE, etc.)TS.RANGE, etc.)JSON.NUMINCRBY, etc.)Note that NRedisStack wraps most of these common modules, and has been updated to understand RESP3; if you are using these modules via NRedisStack, you should update to the latest version; if you are using these modules via ad-hoc commands, you may need to update your processing code to compensate for this, or consider using NRedisStack instead, which will handle the RESP3 conversion for you.
This leaves a small category of users who are currently using the RedisResult type directly (via Execute[Async](...) or ScriptEvaluate[Async](...)).
Firstly, note that it is possible that the structure of the data changes between RESP2 and RESP3; for example, a jagged array might become a map, or a single string value might become an array. You will need to identify these changes (typically via integration tests) and update your code accordingly, ideally with detection code to handle either structure so that the same code works in both REP2 and RESP3.
This is usually combined by using the RedisResult.Resp3Type property to query the type of data returned (integer, string, etc). Historically, you could use the RedisResult.Type property to query the type of data returned (integer, string, etc).
With RESP3, this is extended:
RedisResult.Resp2Type and RedisResult.Resp3Type
Resp3Type property exposes the new semantic data (when using RESP3) - for example, it can indicate that a value is a double-precision number, a boolean, a map, etc (types that did not historically exist)Resp2Type property exposes the same value that would have been returned if this data had been returned over RESP2Type property is now marked obsolete, but functions identically to Resp2Type, so that pre-existing code (for example, that has a switch on the type) is not impacted by RESP3ResultType.MultiBulk is superseded by ResultType.Array (this is a nomenclature change only; they are the same value and function identically)Possible changes required due to RESP3:
ResultType.MultiBulk with ResultType.Array, and usage of RedisResult.Type with RedisResult.Resp2TypeRedisResult.Resp3Type where appropriateAn example of the types of changes required may be seen in the NRedisStack #471 pull-request, which updates result processing for multiple modules (and changes the integration tests to run on RESP2 and RESP3 separately).