排查 Azure Cache for Redis 延迟和超时问题

未能及时收到响应的 Azure Cache for Redis 客户端操作可能会导致高延迟或触发超时异常。 本文介绍如何排查可能导致高延迟和超时的常见问题。

某个操作可能会在各个阶段遇到问题或超时。 问题的源有助于确定原因和缓解措施。 本文分为客户端和服务器端问题。

客户端问题

服务器端问题

客户端故障排除

以下客户端问题可能会影响延迟和性能,并导致超时。

最大客户端连接数

超过缓存最大范围的客户端连接请求可能会失败。 处理重复的重新连接尝试时,客户端连接数过多还可能导致服务器负载过高。

客户端连接数过多可能表示客户端代码中存在连接泄漏。 连接可能没有被重用或正确关闭。 查看用于连接的客户端代码。

如果高连接都是合法且必需的客户端连接,则可能需要将缓存升级到具有更高连接限制的大小。 检查 连接客户端的最大聚合指标 是否接近或高于缓存大小允许的最大连接数。 有关每个客户端连接的大小调整的详细信息,请参阅 Azure Cache for Redis 性能

客户端主机上的 CPU 使用率高

高客户端 CPU 使用率表示系统无法跟上分配给它的工作。 即使缓存快速发送响应,客户端也可能无法快速处理响应。 最好将客户端 CPU 保持在小于 80%。

缓解客户端 CPU 使用率较高的问题:

  • 调查 CPU 峰值的原因。
  • 将客户端升级到具有更多 CPU 容量的大型虚拟机(VM)大小。

使用 Azure 门户中提供的指标或通过 VM 上的性能计数器监视客户端的系统范围的 CPU 使用率。 检查指标 错误(类型:无响应Clients),以确定您的客户端主机是否能够及时处理来自 Redis 服务器的响应。

请注意不要监视进程 CPU,因为单个进程的 CPU 使用率较低,但系统范围的 CPU 可能很高。 注意与超时相对应的 CPU 使用率峰值。 高 CPU 也可能导致错误消息中的in: XXX值变高timeoutException。 有关示例,请参阅 流量突发和线程池配置 部分。

StackExchange.Redis 1.1.603 及更高版本在 local-cpu 错误消息中包括了 timeoutException 指标。 请确保使用 最新版本的 StackExchange.Redis NuGet 包,因为定期修复 bug 以使代码对超时更具抵抗力。 有关详细信息,请参阅 调查 timeout StackExchange.Redis 中的异常

大型键值

可以使用 redis-cli --bigkeys 命令检查缓存中的大键。 有关 redis-cli、Redis 命令行接口的详细信息,请参阅 Redis CLI

若要缓解问题:

  • 增加 VM 的大小以获取更高的带宽功能。 提高客户端或服务器 VM 上的带宽可以缩短较大响应的数据传输时间。 将两个 VM 上的当前网络使用情况与当前 VM 大小的限制进行比较。 仅服务器或客户端上的更多带宽可能不够。

  • 增加应用程序使用的连接对象数。 使用轮询方法通过不同的连接对象发出请求。 有关使用多个键和较小值的信息,请参阅考虑使用更多键和较小的值

Redis 客户端上的内存压力

客户端的内存压力可能导致延迟处理缓存响应的性能问题。 出现内存压力时,系统可能会将数据分页到磁盘。 此页面错误导致系统显著减慢。

检测客户端上的内存压力:

  • 监视 VM 上的内存使用情况,确保不会超过可用内存。
  • 监视客户端的 Page Faults/Sec 性能计数器。 在正常运行期间,大多数系统会出现某些页面错误。 如果页面错误中存在与请求超时相关的峰值,可能表示出现了内存压力。

若要缓解客户端上的高内存压力,

  • 调查内存使用模式以减少客户端上的内存消耗。
  • 将客户端 VM 升级到可提供更多内存的更大大小。

客户端主机的网络带宽限制

根据它们的体系结构,客户端计算机可能对网络带宽可用性有限制。 如果客户端因网络容量超载而超过可用带宽,数据在客户端的处理速度就没有服务器发送的快。 这种情况下会导致超时。

若要缓解此问题,请减少网络带宽消耗,或者将客户端 VM 大小提高到可以提供更大网络容量的大小。 有关详细信息,请参阅请求或响应大小过大

RedisSessionStateProvider retryTimeout

如果使用 RedisSessionStateProvider,请确保正确设置 retryTimeoutretryTimeoutInMilliseconds 值应大于 operationTimeoutInMilliseconds 值。 如果不是这样,则不会重试。

在以下示例中,retryTimeoutInMilliseconds 设置为 3000

<add 
    name="AFRedisCacheSessionStateProvider"
    type="Microsoft.Web.Redis.RedisSessionStateProvider"
    host="enbwcache.redis.cache.chinacloudapi.cn"
    port="6380"
    accessKey="..."
    ssl="true"
    databaseId="0"
    applicationName="AFRedisCacheSessionState"
    connectionTimeoutInMilliseconds = "5000"
    operationTimeoutInMilliseconds = "1000"
    retryTimeoutInMilliseconds="3000"
>

有关详细信息,请参见:

基于 Linux 的客户端应用程序的 TCP 设置

由于 Linux 中的乐观 TCP 设置,在 Linux 上托管的客户端应用程序可能会遇到连接问题。 有关详细信息,请参阅 Linux 托管客户端应用程序的 TCP 设置

流量突增和线程池配置

流量激增时,如果 ThreadPool 设置不佳,则可能导致对 Redis 服务器已发送但尚未在客户端上使用的数据的处理出现延迟。 检查 错误(类型:无响应客户端) 指标,以确认您的客户端是否可以应对瞬间流量高峰。 可以 配置线程池设置,以确保线程池在突发场景中快速扩展。

可以使用 StackExchange.Redis 中的 timeoutException 消息进一步调查。

    System.timeoutException: timeout performing EVAL, inst: 8, mgr: Inactive, queue: 0, qu: 0, qs: 0, qc: 0, wr: 0, wq: 0, in: 64221, ar: 0,
    IOCP: (Busy=6,Free=999,Min=2,Max=1000), WORKER: (Busy=7,Free=8184,Min=2,Max=8191)

前面的异常演示了几个问题。

  • IOCP 节和 WORKER 节中,Busy 值大于 Min 值,这意味着 ThreadPool 设置需要调整。
  • 该值 in: 64221 指示在客户端的内核套接字层收到 64,221 个字节,但应用程序未读取。 这种差异通常意味着应用程序(例如 StackExchange.Redis)不会像服务器发送数据一样快速从网络读取数据。

StackExchange.Redis 1.1.603 及更高版本在 local-cpu 错误消息中包括了 timeoutException 指标。 请确保使用 最新版本的 StackExchange.Redis NuGet 包,因为定期修复 bug 以使代码对超时更具抵抗力。 了解更多信息,请参阅 StackExchange.Redis 中超时异常的研究

服务器端故障排除

以下服务器端问题可能会影响性能并导致超时。

内存使用率较高

服务器上的内存压力可能导致延迟请求处理的各种性能问题。 出现内存压力时,系统会将数据分页到磁盘,这会导致系统明显减慢速度。

内存压力的一些可能原因是,缓存填充的数据接近其最大容量,或者 Redis 服务器内存碎片较高。

当负载模式存储大小差异较高的数据时,例如,当数据分布在 1 KB 和 1 MB 大小之间时,可能会发生碎片。 从现有内存中删除 1 KB 密钥时,1 MB 键无法容纳到空间中,从而导致碎片化。 同样,如果删除 1-MB 密钥,则添加的 1.5 MB 密钥无法容纳到现有的回收内存中。 此未使用的可用内存会导致碎片化。

如果缓存出现碎片并在高内存压力下运行,则系统将执行故障转移以尝试恢复驻留集大小(RSS)内存。 Redis 公开了两个统计信息,used_memoryused_memory_rss,通过 INFO 命令来帮助你识别此问题。 还可以 在 Azure 门户中查看这些指标

如果 used_memory_rss 值是 used_memory 指标的 1.5 倍,内存中便会出现碎片。 若出现以下情况,碎片可能会导致问题:

  • 内存使用率接近缓存的最大内存限制。
  • used_memory_rss 指标高于最大内存限制,可能会导致内存中页面出错。

可以采取多项措施来帮助保持内存使用的健康状态。

有关内存管理的详细信息,请参阅 内存管理的最佳做法

高服务器负载

高服务器负载意味着 Redis 服务器繁忙,无法跟上请求,导致超时或响应缓慢。 为缓解服务器负载高的情况,首先应调查原因,例如高内存压力导致的长时间运行的命令。

可以从 Azure 门户 监视服务器 负载等指标。 若要检查服务器负载指标,请从缓存页上的左侧导航菜单中选择“监视”下的“见解”,然后查看“服务器加载”图。 或在左侧导航菜单中的“监视”下选择“指标”,然后在“指标”下选择“服务器负载”。

监视与超时相关的服务器负载使用量峰值。 针对服务器负载指标创建警报,以便尽早收到潜在影响通知。

服务器负载中的峰值

在 C0 和 C1 缓存中,服务器负载可能会出现短暂的峰值,这并不是由于请求增加,而是在 VM 上运行的内部 Defender 扫描导致的。 在这些层上,当内部的 Defender 扫描发生时,请求面临更高的延迟。

C0 层和 C1 层上的缓存仅使用单个核心来处理多任务,将负责内部 Defender 扫描和 Redis 请求的工作整合在一起。 如果内部 Defender 扫描的额外延迟会对 C1 缓存上的生产工作负荷产生负面影响,则可以扩展到具有多个 CPU 核心(如 C2)的更高层产品/服务。 有关详细信息,请参阅 选择正确的层

有关客户端连接数快速更改的详细信息,请参阅 “避免客户端连接峰值”。

规模化

可以横向扩展到更多分片,以跨多个 Redis 进程分配负载,或者纵向扩展到具有更多 CPU 核心的更大的缓存。 缩放作占用大量 CPU 和内存,因为它们可能涉及围绕节点移动数据以及更改群集拓扑。 有关详细信息,请参阅 Azure Redis 缓存规划常见问题解答缩放

长时间运行的命令

某些 Redis 命令的执行开销比其他命令高。 Redis 命令 文档显示每个命令的时间复杂性。 Redis 命令处理是单线程的。 运行时间较长的任何命令都可以阻止其后面的其他命令。

查看你向 Redis 服务器发出的命令,以了解其性能影响。 例如,在不知道这是一个大 O 复杂度操作(O(N))的情况下,KEYS 命令经常被使用。 若要减少 CPU 峰值,可以使用 SCAN 来避免KEYS

可以在控制台中运行以下 Redis 命令,以调查运行时间长且耗费资源的命令。

  • 客户端列表

    CLIENT LIST 命令以人类可读格式返回有关客户端连接服务器的信息和统计信息。

  • 信息

    INFO 命令返回有关服务器的信息和统计信息,其格式对于计算机来说,分析简单且易于人类阅读。 此 CPU 部分可用于调查 CPU 使用率。 一个 server_load100 (最大值)表示 Redis 服务器一直处于忙碌状态,在处理请求时永远不会空闲。

    以下示例演示命令的 INFO 输出:

    # CPU
    used_cpu_sys:530.70
    used_cpu_user:445.09
    used_cpu_avg_ms_per_sec:0
    server_load:0.01
    event_wait:1
    event_no_wait:1
    event_wait_count:10
    event_no_wait_count:1
    
  • 显示器

    MONITOR 是一个调试命令,用于流式传输 Redis 服务器处理的每个命令。 MONITOR 可以帮助你了解数据库的动态。 此命令要求很高,可能会对性能产生负面影响并降低性能。

  • SLOWLOG

    Redis 慢速日志是记录超过指定执行时间的查询的系统。 执行时间不包括 I/O作,例如与客户端通信或发送回复,但仅包含实际执行命令所需的时间。

    SLOWLOG 命令读取并重置 Redis 慢查询日志,还可用于调查客户端上长时间运行的命令。 可以使用 SLOWLOG GET 监视和记录针对 Redis 服务器执行的昂贵命令。

网络带宽限制

不同的缓存大小具有不同的网络带宽容量。 如果服务器超过可用带宽,则数据不会尽快发送到客户端。 客户端请求可能会超时,因为服务器无法以足够快的速度将数据推送到客户端。

可以在 Azure 门户中监视缓存读取缓存写入指标,以查看使用的服务器端带宽量。 针对这些指标创建警报,以便尽早收到潜在影响通知。

缓解网络带宽用量即将达到最大容量的情况:

服务器维护

计划内或计划外维护可能会导致客户端连接中断。 异常的数目和类型取决于当缓存关闭其连接时,请求在代码路径中所处的位置。

如果 Azure Redis 缓存出现故障切换,来自故障节点的所有客户端连接都会转移到仍在运行的节点。 由于连接增加,服务器负载可能会急剧上升。 可以尝试重启客户端应用程序,以便在两个节点之间重新创建并重新分布所有客户端连接。

在发生故障转移时发送请求但未收到响应的操作可能会遭遇异常timeout 。 对关闭的连接对象发出的新请求将收到连接异常,直到重新连接成功为止。

若要检查在发生 timeout 异常期间 Azure Redis 缓存是否发生故障转移,请检查 错误 指标。 在缓存的 Azure 门户页上,在左侧导航菜单中的“监视”下选择“指标”。 然后创建一个新图表来测量 Errors 指标,按 ErrorType 拆分。 创建此图表后,会看到故障转移计数。 有关故障转移的详细信息,请参阅 Azure Cache for Redis 的故障转移和修补

有关因服务器维护而缓解问题的详细信息,请参阅以下文章: