本文提供关于如何管理 Azure 托管 Redis 的常见问题解答。
在几乎所有 Redis 用例中,都建议使用 TLS 作为最佳做法。 为了向后兼容,包含了不使用 TLS 进行连接的选项。
- 将
AbortConnect
设置为 false,并使 ConnectionMultiplexer 自动重新连接。 - 使用一个生存期长的
ConnectionMultiplexer
实例,而不是为每个请求新建连接。 - 具有较小值的 Redis 工作性能最佳,因此请考虑将较大数据分成多个密钥。 有关详细信息,请参阅最佳做法开发。
- 配置 ThreadPool 设置 以避免超时。
- 将默认 connectTimeout 至少设置为 5 秒。 出现网络故障时,此间隔可以给 StackExchange.Redis 留出足够的时间来重新建立连接。
- 请注意与正在运行的不同操作相关的性能成本。 例如,
KEYS
命令是 O(n) 操作,应当避免。 redis.io 站点具有关于其支持的每个操作的时间复杂性的详细信息。 选择每个命令以查看每个操作的复杂程度。
- 请记住,Redis 是 内存中 数据存储区。 有关详细信息,请参阅排查 Azure 托管 Redis 中的数据丢失问题,了解可能发生数据丢失的情况。
- 开发系统以便处理由于修补和故障转移引起的连接故障。
- 请参阅使用 Azure 托管 Redis 进行性能测试,获取在 Azure 托管 Redis 上运行自己的性能测试的示例基准和说明。
- 对于某些需要较长时间才能完成的 Redis 命令,除非完全了解这些命令的结果,否则请避免使用这些命令。 例如,请勿在生产中运行 KEYS 命令。 它可能需要很长时间才能返回,具体时间取决于键数。 每个 Redis 分片都是单线程的,每次只处理一个命令。 如果在 KEYS 后面发出了其他命令,则这些命令只会在处理完 KEYS 命令后才会得到处理。 redis.io 站点具有关于其支持的每个操作的时间复杂性的详细信息。 选择每个命令以查看每个操作的复杂程度。
- 键大小 - 应使用小键/值还是大键/值? 这取决于方案。 如果方案需要较大的键,则可调整 ConnectionTimeout,然后重试值并调整重试逻辑。 从 Redis 服务器的角度来看,值越小,性能就越好。
- 这些考量并不意味着不能在 Redis 中存储较大值,只是要注意以下事项。 延迟较高。 如果采用一个较大的数据集和一个较小的数据集,则可以使用多个 ConnectionMultiplexer 实例。 使用一组不同的超时和重试值配置每个值,如前面的 StackExchange.Redis 配置选项执行的作 部分中所述。
- 启用缓存诊断,以便 可以监视 缓存的运行状况。 可以在 Azure 门户中查看指标,也可以使用所选的工具下载和查看这些指标。
- 请参阅使用 Azure 托管 Redis 进行性能测试,获取在 Azure 托管 Redis 上运行自己的性能测试的示例基准和说明。
CLR ThreadPool 有两种类型的线程 - 辅助角色 和 I/O 完成端口 (IOCP) 线程。
- 对于诸如处理
Task.Run(…)
或ThreadPool.QueueUserWorkItem(…)
方法这类事务,请使用辅助角色线程。 需要在后台线程上进行工作时,CLR 中的各种组件也会使用这些线程。 - 进行异步 IO(例如从网络进行读取)时,使用 IOCP 线程。
线程池按需提供新的辅助角色线程或 I/O 完成线程(没有任何限制),直到它达到每种线程类型的“最小值”设置。 默认情况下,最小线程数设置为系统上的处理器数。
一旦现有(忙碌)线程数达到“最小”线程数,ThreadPool 便会将注入新线程的速率限制为每 500 毫秒一个线程。 通常,如果系统中出现需要 IOCP 线程的突发工作,则它会快速处理该工作。 但是,如果突发多于配置的“最小值”设置,则在处理某些工作时会出现一定的延迟,因为线程池会等待发生以下两种情况之一:
- 一个现有线程释放,以便处理工作。
- 在 500 毫秒内没有任何现有线程释放,并会创建一个新线程。
基本上,当忙碌线程数大于 Min 线程时,在应用程序处理网络流量之前,可能会支付 500 毫秒的延迟。 此外,当现有线程保持空闲状态的时间超过 15 秒时,系统会清理它,并且这种增长和收缩的循环可能会重复。
如果我们考虑一个来自 StackExchange.Redis(内部版本 1.0.450 或更高版本)的示例错误消息,会看到它现在会打印线程池统计信息。 请参阅本文后面的 IOCP 和辅助角色详细信息。
System.TimeoutException: Timeout performing GET MyKey, inst: 2, mgr: Inactive,
queue: 6, qu: 0, qs: 6, qc: 0, wr: 0, wq: 0, in: 0, ar: 0,
IOCP: (Busy=6,Free=994,Min=4,Max=1000),
WORKER: (Busy=3,Free=997,Min=4,Max=1000)
如示例中所示,可以看到,对于 IOCP 线程,有六个繁忙线程,系统配置为允许四个最小线程。 在这种情况下,客户端可能会遇到两个 500 毫秒延迟,因为 6 > 4。
备注
如果 IOCP 或辅助角色线程受到限制,则 StackExchange.Redis 可以会超时。
建议客户将 IOCP 和 WORKER 线程的最小配置值设置为大于默认值的值。 我们无法就此值提供一刀切的指南,因为一个应用程序的合适值对于另一个应用程序来说可能太高或太低。 此设置还可能会影响复杂应用程序的其他部分的性能。 每个客户都需要根据自己的特定需求微调此设置。 开始时设置为 200 或 300 会比较好,随后可进行测试并根据需要进行调整。
如何配置此设置:
建议在 .NET Framework 和 .NET Core 应用程序中使用 ThreadPool.SetMinThreads (...) 方法以编程方式更改此设置。
例如,在 NET Framework 中,在方法中Global.asax.cs
Application_Start
对其进行设置:
```csharp
private readonly int minThreads = 200;
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
ThreadPool.SetMinThreads(minThreads, minThreads);
}
```
如果使用 .NET Core,请将其设置在 Program.cs
调用之前 WebApplication.CreateBuilder()
:
```csharp
const int minThreads = 200
ThreadPool.SetMinThreads(minThreads, minThreads);
var builder = WebApplication.CreateBuilder(args);
// rest of application setup
```
备注
此 方法指定的值是全局设置,将影响整个 AppDomain。 例如,如果有一台具有四个核心的计算机,并且希望在运行时将每个 CPU 设置为 minWorkerThreads
minIoThreads
50 个,请使用 ThreadPool.SetMinThreads(200, 200)
。
还可以通过使用minIoThreads
配置元素下的minWorkerThreads
或<processModel>
Machine.config
来指定最小线程设置。
Machine.config
通常位于 %SystemRoot%\Microsoft.NET\Framework\[versionNumber]\CONFIG\
。
不建议以这种方式设置最小线程数,因为它是系统范围的设置。 如果这样做,则必须重启应用程序池。
备注
此配置元素中指定的值是按核心设置。 例如,如果你有一台四核计算机,并且希望设置 minIoThreads
在运行时为 200,请使用 <processModel minIoThreads="50">
。
启用服务器 GC 可以在使用 StackExchange.Redis 时优化客户端并提供更好的性能和吞吐量。 有关服务器 GC 以及如何启用它的详细信息,请参阅以下文章:
不同的 SKU 可能有不同的客户端连接、内存和带宽限制。 虽然每个缓存大小最多允许一些连接,但与 Redis 的每个连接都有与之关联的开销。 此类开销的一个示例是,由于 TLS/SSL 加密而导致的 CPU 和内存使用。 给定缓存大小的最大连接限制假定轻负载缓存。 如果连接开销的负载加上客户端操作的负载超出了系统容量,那么即使未超出当前缓存大小的连接限制,缓存也可能会遇到容量问题。
有关每个层级的不同连接限制的详细信息,请参阅 Azure 托管 Redis 定价。
- 了解其他 Azure 托管 Redis 常见问题解答。