探索用于与 Redis 交互的客户端 API
如前所述,Redis 是一个内存中 NoSQL 数据库,它可跨多个服务器进行复制。 它通常用作缓存,但也可以用作正式数据库甚至消息中转站。
Redis 可以存储各种数据类型和结构。 它支持可发出的各种命令,以检索缓存数据或查询关于缓存本身的信息。 处理的数据始终以键/值对的形式存储。
针对 Redis 缓存执行命令
客户端应用程序通常使用客户端库来构建请求以及针对 Redis 缓存执行命令。 可以直接从 Redis 客户端页获取客户端库列表。 StackExchange.Redis 是面向 .NET 平台的常用高性能 Redis 客户端。 可以通过 NuGet 获取该包,并可以使用命令行或 IDE 将其添加到 .NET 代码。
使用 StackExchange.Redis 连接到 Redis 缓存
回顾前面的课程,我们曾经使用主机地址、端口号和访问密钥连接到 Redis 服务器。 Azure 还为一些 Redis 客户端提供连接字符串,将这些数据一起捆绑成单个字符串。
什么是连接字符串?
连接字符串是单个文本行,其中包含连接和验证 Azure 中的 Redis 缓存时所需的全部信息片段。 连接字符串如下所示(cache-name 和 password-here 字段中应填写实际值):
[cache-name].redis.cache.windows.net:6380,password=[password-here],ssl=True,abortConnect=False
提示
应在应用程序中保护连接字符串。 如果应用程序托管在 Azure 上,请考虑使用 Azure Key Vault 来存储值。
可将此字符串传递到 StackExchange.Redis,以便与服务器建立连接。
请注意末尾有两个附加参数:
- ssl:确保通信加密
- abortConnection:即使服务器当时不可用,也能创建连接
可在该字符串的后面追加其他几个可选参数,以配置客户端库。
创建连接
StackExchange.Redis 中的主连接对象是 StackExchange.Redis.ConnectionMultiplexer
类。 此对象将连接到 Redis 服务器(或服务器组)的过程抽象化。 此对象经过优化,可以有效管理连接,每当访问缓存时,都需要准备好它。
使用静态 ConnectionMultiplexer.Connect
或 ConnectionMultiplexer.ConnectAsync
方法并传入连接字符串或 ConfigurationOptions
对象来创建 ConnectionMultiplexer
实例。
下面是一个简单示例:
using StackExchange.Redis;
...
var connectionString = "[cache-name].redis.cache.windows.net:6380,password=[password-here],ssl=True,abortConnect=False";
var redisConnection = ConnectionMultiplexer.Connect(connectionString);
// ^^^ store and re-use this!!!
创建 ConnectionMultiplexer
后,需要执行三项主要操作:
- 访问 Redis 数据库(本模块主旨)。
- 利用 Redis 的发布者/下标功能(不在本模块范围内)。
- 访问单个服务器以进行维护或监视。
访问 Redis 数据库
Redis 数据库由 IDatabase
类型表示。 可以使用 GetDatabase()
方法检索 Redis 数据库:
IDatabase db = redisConnection.GetDatabase();
提示
从 GetDatabase
返回的对象是一个轻型对象,不需要存储它。 只需将 ConnectionMultiplexer
保持活动状态。
获取 IDatabase
对象后,可以执行与缓存交互的方法。 所有方法都提供同步和异步版本,这些版本返回 Task
对象,因此与 async
和 await
关键字兼容。
下面是在缓存中存储键/值的示例:
bool wasSet = db.StringSet("favorite:flavor", "i-love-rocky-road");
StringSet
方法返回 bool
,指示是已设置 (true
) 还是未设置 (false
) 该值。 然后,可以使用 StringGet
方法检索该值:
string value = db.StringGet("favorite:flavor");
Console.WriteLine(value); // displays: ""i-love-rocky-road""
获取和设置二进制值
回顾前面的课程,Redis 键和值是二进制安全的。 可以使用相同的方法存储二进制数据。 可以使用隐式转换运算符来处理 byte[]
类型,以便可以像平时一样处理数据:
byte[] key = ...;
byte[] value = ...;
db.StringSet(key, value);
byte[] key = ...;
byte[] value = db.StringGet(key);
提示
StackExchange.Redis 使用 RedisKey
类型表示键。 此类提供与 string
和 byte[]
的相互隐藏转换,使我们能够十分轻松地使用文本和二进制键。 值由 RedisValue
类型表示。 与 RedisKey
一样,可以通过隐式转换来传递 string
或 byte[]
。
其他常见操作
IDatabase
接口包含其他几个方法用于处理 Redis 缓存。 还有一些方法可以处理哈希、列表、集和有序集。
下面是用于处理单个键的其他一些常见操作。若要查看完整列表,可以阅读该接口的源代码。
方法 | 说明 |
---|---|
CreateBatch |
创建要作为单个单元发送到服务器、但不一定要作为单个单元进行处理的一组操作。 |
CreateTransaction |
创建要作为单个单元发送到服务器、并在服务器上作为单个单元进行处理的一组操作。 |
KeyDelete |
删除键/值。 |
KeyExists |
返回给定的键是否在缓存中存在的结果。 |
KeyExpire |
针对某个键设置生存时间 (TTL) 过期时间。 |
KeyRename |
重命名某个键。 |
KeyTimeToLive |
返回键的 TTL。 |
KeyType |
返回键中存储的值类型的字符串表示形式。 可返回的不同类型包括:字符串、列表、集、zset 和哈希。 |
执行其他命令
IDatabase
对象包含可用于将文本命令传递给 Redis 服务器的 Execute
和 ExecuteAsync
方法。 例如:
var result = db.Execute("ping");
Console.WriteLine(result.ToString()); // displays: "PONG"
Execute
和 ExecuteAsync
方法返回 RedisResult
对象,该对象是包含以下两个属性的数据保存器:
Type
:返回指示结果类型(“STRING”、“INTEGER”等)的string
。IsNull
:结果为null
时要检测的 true/false 值。
然后,可对 RedisResult
使用 ToString()
来获取实际返回值。
可使用 Execute
执行任何受支持的命令。 例如,可以获取已连接到缓存的所有客户端(“CLIENT LIST”):
var result = await db.ExecuteAsync("client", "list");
Console.WriteLine($"Type = {result.Type}\r\nResult = {result}");
上述命令输出所有连接的客户端:
Type = BulkString
Result = id=9469 addr=16.183.122.154:54961 fd=18 name=DESKTOP-AAAAAA age=0 idle=0 flags=N db=0 sub=1 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 ow=0 owmem=0 events=r cmd=subscribe numops=5
id=9470 addr=16.183.122.155:54967 fd=13 name=DESKTOP-BBBBBB age=0 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=32768 obl=0 oll=0 omem=0 ow=0 owmem=0 events=r cmd=client numops=17
存储更复杂的值
Redis 面向二进制安全的字符串,但你可以通过将对象图序列化为文本格式(通常是 XML 或 JSON)来缓存这些图形。 例如,对于统计信息,我们也许可以创建如下所示的 GameStat
对象:
public class GameStat
{
public string Id { get; set; }
public string Sport { get; set; }
public DateTimeOffset DatePlayed { get; set; }
public string Game { get; set; }
public IReadOnlyList<string> Teams { get; set; }
public IReadOnlyList<(string team, int score)> Results { get; set; }
public GameStat(string sport, DateTimeOffset datePlayed, string game, string[] teams, IEnumerable<(string team, int score)> results)
{
Id = Guid.NewGuid().ToString();
Sport = sport;
DatePlayed = datePlayed;
Game = game;
Teams = teams.ToList();
Results = results.ToList();
}
public override string ToString()
{
return $"{Sport} {Game} played on {DatePlayed.Date.ToShortDateString()} - " +
$"{String.Join(',', Teams)}\r\n\t" +
$"{String.Join('\t', Results.Select(r => $"{r.team } - {r.score}\r\n"))}";
}
}
可以使用 Newtonsoft.Json 库将此对象的实例转换为字符串:
var stat = new GameStat("Soccer", new DateTime(1950, 7, 16), "FIFA World Cup",
new[] { "Uruguay", "Brazil" },
new[] { ("Uruguay", 2), ("Brazil", 1) });
string serializedValue = Newtonsoft.Json.JsonConvert.SerializeObject(stat);
bool added = db.StringSet("event:1950-world-cup", serializedValue);
可以检索该字符串,然后使用相反的过程将它还原为对象:
var result = db.StringGet("event:1950-world-cup");
var stat = Newtonsoft.Json.JsonConvert.DeserializeObject<GameStat>(result.ToString());
Console.WriteLine(stat.Sport); // displays "Soccer"
清理连接
完成 Redis 连接后,可以处置 ConnectionMultiplexer
。 此命令会关闭所有连接,并关闭与服务器的通信:
redisConnection.Dispose();
redisConnection = null;
让我们创建一个应用程序,然后使用 Redis 缓存完成一些工作。
如前所述,Redis 是一个内存中 NoSQL 数据库,它可跨多个服务器进行复制。 它通常用作缓存,但也可以用作正式数据库甚至消息中转站。
Redis 可以存储各种数据类型和结构。 它支持可发出的各种命令,以检索缓存数据或查询关于缓存本身的信息。 处理的数据始终以键/值对的形式存储。
针对 Redis 缓存执行命令
客户端应用程序通常使用客户端库来构建请求以及针对 Redis 缓存执行命令。 可以直接从 Redis 客户端页获取客户端库列表。 redis 包是适合 JavaScript 的常用 Redis 客户端,可通过 npm install redis
将它添加到项目中。
使用 redis 包连接到 Redis 缓存
通过 RedisClient
类可实现与 Redis 缓存的交互。 在大多数情况下,最好使用样本代码创建一个 RedisClient
,它会连接到 Azure 中的 Redis 缓存:
const client = redis.createClient(
port, // the port number, 6380 by default
hostname, // <resourceName>.redis.cache.windows.net
{
password: accessKey, // the primary or secondary access key
tls: { servername: hostname }
}
);
在多数情况下,应避免创建多个 RedisClient
。 可在代码中需要 Redis 的任何位置传递和使用 RedisClient
的单个实例。
使用 Redis 数据库
Redis 命令表示为 RedisClient
上的方法,其名称与命令本身相同。 以下示例展示了缓存中新值的存储:
client.set("myKey", "myValue"); // executes "set myKey myValue" on the cache
RedisClient
上的所有命令方法都是异步的,并且支持能提供结果的可选回调参数。 redis
包并非开箱即可支持承诺(因此,也不支持 async
/await
或带 .then()
的链接)。 要通过 RedisClient
使用 async
/await
或 .then()
,最简单的方法是通过 bluebird
包的 promisifyAll
函数一次性向整个客户端添加承诺支持:
var redis = require("redis");
var Promise = require("bluebird");
Promise.promsifyAll(redis);
promisifyAll
函数会将 XXXAsync
版本的所有命令方法添加到 RedisClient
实例,从而能够支持使用异步方法,如以下示例所示:
var result = await client.setAsync("myKey", "myValue");
动态执行命令
可以使用 sendCommand()
(或带有 bluebird 的 sendCommandAsync()
)以动态的方式发送命令,将任何字符串作为命令发送到缓存。 例如,应用可能会提示将命令直接发送到缓存,或者 Redis 可能会引入 redis
包不支持的新命令。 必须以数组的形式发送命令参数。
// Add a key/value pair
var result = await client.sendCommandAsync("set", ["myKey", "myValue"]);
清理连接
完成 Redis 连接后,应使用 quit()
将其关闭(使用 bluebird 时,采用 quitAsync()
):
await client.quitAsync();
让我们创建一个应用程序,然后使用 Redis 缓存完成一些工作。