Azure Redis 缓存使用注意事项与排查问题文档整理
StackExchange.Redis 使用名为 synctimeout
的配置设置进行同步操作,该设置的默认值为 1000 毫秒。 如果同步调用未在规定时间内完成,StackExchange.Redis 客户端会引发类似于以下示例的超时错误。
System.TimeoutException: Timeout performing MGET 2728cc84-58ae-406b-8ec8-3f962419f641, inst: 1,mgr: Inactive, queue: 73, qu=6, qs=67, qc=0, wr=1/1, in=0/0 IOCP: (Busy=6, Free=999, Min=2,Max=1000), WORKER (Busy=7,Free=8184,Min=2,Max=8191)
此错误消息中包含的指标可以指出问题的原因和可能的解决方法。 下表包含有关错误消息指标的详细信息。
错误消息指标 | 详细信息 |
---|---|
inst | 在上一个时间片中:发出了 0 个命令 |
mgr | 套接字管理器正在执行 socket.select ,也就是说,它在请求 OS 指示一个需要执行某些操作的套接字;大致说来:读取器并没有主动从网络读取内容,因为它认为不需执行任何操作 |
队列 | 总共有 73 个正在进行的操作 |
qu | 正在进行的操作中,有 6 个操作位于未发送队列中,尚未写入到出站网络 |
qs | 正在进行的操作中,有 67 个操作已发送给服务器,但尚未得到响应。 响应可能为 Not yet sent by the server 或 sent by the server but not yet processed by the client. |
qc | 正在进行的操作中,有 0 个操作已经有回复,但尚未标记为完成,因为正在完成循环中进行等待 |
wr | 存在活动的写入器(这意味着系统不会忽略这 6 个尚未发送的请求)字节/活动写入器 |
位于 | 没有活动的读取器,NIC 字节/活动读取器上没有可供读取的字节 |
有关线程池增长的重要详细信息
CLR 线程池具有两种类型的线程 —“辅助角色”和“I/O 完成端口”(又称为 IOCP)线程。
- 对于诸如处理
Task.Run(…)
或ThreadPool.QueueUserWorkItem(…)
方法这类事务,使用辅助角色线程。 需要在后台线程上进行工作时,CLR 中的各种组件也会使用这些线程。 - 进行异步 IO(例如从网络进行读取)时,使用 IOCP 线程。
线程池按需提供新的辅助角色线程或 I/O 完成线程(没有任何限制),直到它达到每种线程类型的“最小值”设置。 默认情况下,最小线程数设置为系统上的处理器数。
一旦现有(忙碌)线程数达到“最小”线程数,线程池便会将插入新线程的速率限制为每 500 毫秒一个线程。 通常,如果系统中出现需要 IOCP 线程的突发工作,则它会非常快速地处理该工作。 但是,如果突发工作多于配置的“最小值”设置,则在处理某些工作时会出现一定的延迟,因为线程池会等待发生以下两种情况之一。
- 一个现有线程释放,以便处理工作。
- 在 500 毫秒内没有任何现有线程释放,因此会创建一个新线程。
基本上,这意味着忙碌线程数大于最小线程数,在应用程序处理网络流量之前可能需要付出 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 线程有 6 个忙碌线程,而系统配置为允许最少 4 个线程。 在这种情况下,客户端可能会遇到两个 500 毫秒延迟,因为 6 > 4。
请注意,如果 IOCP 或辅助角色线程受到限制,则 StackExchange.Redis 可以会超时。
建议
考虑到此信息,我们强烈建议客户将 IOCP 和辅助角色线程的最小配置值设置为大于默认值。 我们无法提供有关此值应是多少的通用指导,因为一个应用程序的合适值对于另一个应用程序会太高/低。 此设置还可能会影响复杂应用程序其他部分的性能,因此每个客户需要按照其特定需求来微调此设置。 开始时设置为 200 或 300 会比较好,随后可进行测试并根据需要进行调整。
如何配置此设置:
-
在 ASP.NET 中,可在 web.config 中的
<processModel>
配置元素下使用“minIoThreads”配置设置。如果在 Azure 网站内部运行,则此设置不会通过配置选项进行公开。 但是,应该仍然能够通过 global.asax.cs 中的 Application_Start 方法以编程方式配置此设置置(请参阅下文)。备注
此配置元素中指定的值是按核心设置。 例如,如果使用 4 核计算机,并且希望 minIOThreads 设置在运行时为 200,则使用
<processModel minIoThreads="50"/>
。 -
在 ASP.NET 外部,可使用 ThreadPool.SetMinThreads(…) API。
启用服务器 GC,以便在使用 StackExchange.Redis 时在客户端上获取更多吞吐量
启用服务器 GC 可以在使用 StackExchange.Redis 时优化客户端并提供更好的性能和吞吐量。 有关服务器 GC 以及如何启用它的详细信息,请参阅以下文章:
Azure Redis 缓存的 ASP.NET 会话状态提供程序
https://docs.microsoft.com/zh-cn/azure/redis-cache/cache-aspnet-session-state-provider
Redis 缓存的 ASP.NET 输出缓存提供程序
https://docs.microsoft.com/zh-cn/azure/redis-cache/cache-aspnet-output-cache-providerAzure
将 Spring Boot Initializer 应用配置为使用云中的 Redis 和 Azure Redis 缓存
https://docs.microsoft.com/zh-cn/java/azure/spring-framework/configure-spring-boot-initializer-java-app-with-redis-cache
Redis 缓存常见问题
https://docs.microsoft.com/zh-cn/azure/redis-cache/cache-faq
如何排查 Azure Redis 缓存问题
https://docs.microsoft.com/zh-cn/azure/redis-cache/cache-how-to-troubleshoot#client-side-troubleshooting
StackExchange.Redis 最佳做法
https://docs.microsoft.com/zh-cn/azure/redis-cache/cache-faq#stackexchangeredis-best-practices
有关线程池增长的重要详细信息(CLR 线程池具有两种类型的线程 —“辅助角色”和“I/O 完成端口”(又称为 IOCP)线程)
https://docs.microsoft.com/zh-cn/azure/redis-cache/cache-faq#stackexchangeredis-best-practices
StackExchange.Redis 超时异常
https://docs.microsoft.com/zh-cn/azure/redis-cache/cache-how-to-troubleshoot#stackexchangeredis-timeout-exceptions
如何为高级 Azure Redis 缓存配置 Redis 群集功能
https://docs.microsoft.com/zh-cn/azure/redis-cache/cache-how-to-premium-clustering
https://gist.github.com/JonCole/e65411214030f0d823cb
https://docs.microsoft.com/zh-cn/dotnet/standard/garbage-collection/fundamentals
https://docs.microsoft.com/zh-cn/azure/redis-cache/cache-faq#important-details-about-threadpool-growth
https://blog.marsen.me/2016/11/21/aspdotnet_threadpool_and_redis/