【问题标题】:StackExchange.Redis - Unexplainable time-out exception issueStackExchange.Redis - 无法解释的超时异常问题
【发布时间】:2021-01-29 15:10:22
【问题描述】:

我们在 .NET Core 3.1 与 Azure Redis 缓存的集成中遇到了问题。 抛出的异常是

执行程序时发生未处理的异常 请求。","@l":"错误","@x":"StackExchange.Redis.RedisTimeoutException: 等待响应超时(出站=1403KiB,入站=5657KiB,15000ms elapsed, timeout is 15000ms), command=EVAL, next: EVAL, inst: 0, qu: 0, qs: 709, aw: True, rs: ReadAsync, ws: Writing, in: 0, 服务器端点:redis-scr-mns-dev.redis.cache.windows.net:6380,mc: 1/1/0,经理:10 个中的 10 个可用,客户端名称:xxxxxxxxxxxx,IOCP: (忙=0,空闲=1000,最小=4,最大=1000),工人: (忙=7,空闲=32760,最小=4,最大=32767), v: 2.1.58.34321 (请取 查看这篇文章,了解可能导致的一些常见客户端问题 超时: https://stackexchange.github.io/StackExchange.Redis/Timeouts)

是的,我已经阅读了这篇文章,我们正在使用 StackExchange.Redis NuGet 包,最新版本可用。我们已经采取的步骤是

  • 使用多个值设置最小线程池计数 (ThreadPool.SetMinThreads(short.MaxValue, short.MaxValue);)
  • 增加 Redis timeout 值从默认的 5 秒到 15 秒(老实说,再高一点也解决不了问题,因为你会进一步阅读 :))

你问的设置是什么?

  • .NET Core 3.1 REST API 在最新的 IIS 上运行,在具有 16GB RAM 的 4 核 Windows 服务器上设置了 3 个工作线程(在监控中看不到任何极端情况关于 CPU 或内存)
  • 已连接到 Azure Redis 缓存。目前正在运行具有高网络带宽和 23GB 内存的Basic C5(之前是较低的,所以我们尝试扩展这个)
  • 最后将请求推送到 Azure 服务总线(没有问题)

批处理进程正在运行并处理几个 10000 个 API 调用(几个 API),其中上述一个因超时异常而与 Redis 缓存崩溃。其他 api 运行正常且未超时,但当前正在连接到不同的 Redis 缓存(只是为了隔离此 api 的行为) 所有 api 和/或批处理程序都使用具有缓存实现的自定义 NuGet 包,因此我们确信这不会是该 1 api 中的实现问题,所有共享代码。

我们如何使用缓存?好吧,通过依赖注入,我们注入了 ISharedCacheStore,它只是我们自己的接口,我们放在 IDistributedCache 之上,以确保只有异步调用可用,以及 RedisCache,它是使用 Redis 的实现(ISharedCacheStore 是为了将来使用其他缓存机制) 我们使用 Microsoft.Extensions.Caching.StackExchangeRedis,版本 3.1.5 并且在启动时注册是

 services.Configure<CacheConfiguration>(options => configuration?.GetSection("CacheConfiguration").Bind(options))
            .AddStackExchangeRedisCache(s =>
                {
                    s.Configuration = connectionString;
                })
            .AddTransient<IRedisCache, RedisCache>()
            .AddTransient<ISharedCacheStore, SharedCacheStore>();

说实话,我们没有想法。我们没有看到 Azure 中的 Redis 缓存实例存在问题,因为当我们遇到超时时,这个实例甚至还没有接近它的顶部。较低定价计划的服务器负载达到约 80%,而较高定价计划的服务器负载甚至没有达到当前计划的 10%。

根据 Insights,我们在运行时每分钟有 4000 次缓存命中,导致大约 10% 的服务器负载。

更新:值得一提的是,批处理和 API 现在是在本地环境中运行,而不是在云端。计划在未来几个月内迁移到云端。 这也适用于其他 api 连接到 Redis 缓存并且不给出问题

比较

  • 另一个 Azure Redis 缓存每分钟获得 45K 次点击,而没有出现任何问题(来自本地)
  • 这个甚至达到了每分钟 10K 次点击的超时标记

【问题讨论】:

    标签: c# .net-core redis stackexchange.redis azure-redis-cache


    【解决方案1】:

    这里有几个可能的事情:

    1. 我不知道EVAL 在做什么; 可能是正在执行的 Lua 造成了阻塞;唯一确定的方法是查看SLOWLOG,但我不知道这是否暴露在 Azure redis 上
    2. 可能是您的有效负载已使可用带宽饱和 - 我不知道您在传输什么
    3. 可能只是网络/套接字停止/中断;它们会发生,尤其是在使用云时 - 并且(相对)高延迟使这特别痛苦
    4. 我们希望启用一个新的可选池(而不是多路复用)模型;这在理论上(概念验证效果很好)可以避免大量积压,这意味着即使套接字失败:只有一个调用受到影响,而不是导致一连串的失败;这方面的限制因素是我们的时间(而且,这需要与 redis 提供商的任何许可影响相平衡;例如,并发连接是否有上限)
    5. 这可能只是库代码中的错误;如果是这样,我们在这里看不到它,但我们不使用与您相同的设置;我们尽我们所能,但很难诊断我们没有看到的问题,这些问题只出现在我们无法轻易复制的其他人的按成本设置中;最终加上:这不是我们的日常工作:(

    我不认为这里有一个简单的“添加这一行,一切都会变得很棒”的答案。这些是非平凡的大规模远程场景,需要大量调查。简单地说:Azure 的人不会为我们的时间付费。

    【讨论】:

    • 嗨,马克,感谢您的快速回复。我会看看你提出的 SLOWLOG 建议。还值得一提的是,今天我们在本地运行 API(在接下来的几个月中将转向云),不幸的是我自己没有网络流量的可视化,但我会联系负责的团队以获得对它的看法。我会在适用的情况下继续更新这篇文章
    • @NicoDegraef 请注意,我不会自动知道您所做的任何编辑,而且 Stack Overflow 可能不是获得持续支持票的最佳场所
    【解决方案2】:

    所以,我们发现了这个问题。 问题在于我们的类的注册,即 AddTransient,如上面的原始代码所示。 将其更改为 AddScoped 时,性能会快很多。甚至想知道它是否可以是单例。 奇怪的是 addtransient 应该增加“连接的客户端”,事实上它确实这样做了,但对可以处理的请求数量也有更大的影响。因为我们在处理过程中从未达到最大连接数限制。

    .AddScoped<IRedisCache, RedisCache>()
            .AddScoped<ISharedCacheStore, SharedCacheStore>();
    

    使用此代码而不是 AddTransient,我们在 4 到 5 分钟的时间内完成了 220 000 次操作而没有问题,而使用旧代码,由于超时异常,我们甚至没有达到 40 000 次操作

    【讨论】:

      猜你喜欢
      • 2019-05-07
      • 2017-08-14
      • 2016-07-13
      • 1970-01-01
      • 2021-03-02
      • 2014-10-23
      • 1970-01-01
      • 2019-01-10
      • 2016-04-11
      相关资源
      最近更新 更多