C# StackExchange.Redis-无法解释的超时异常问题

C# StackExchange.Redis-无法解释的超时异常问题,c#,.net-core,redis,stackexchange.redis,azure-redis-cache,C#,.net Core,Redis,Stackexchange.redis,Azure Redis Cache,我们在.NET Core 3.1与Azure Redis缓存的集成中遇到问题。 引发的异常是 执行时发生未处理的异常 请求“,“@l:”错误“,“@x:”StackExchange.Redis.RedisTimeoutException: 等待响应超时(出站=1403KB,入站=5657KiB,15000ms 已过,超时为15000ms),命令=EVAL,下一步:EVAL,指令:0,qu: 0,qs:709,aw:True,rs:ReadAsync,ws:Writing,in:0, server

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

执行时发生未处理的异常 请求“,“@l:”错误“,“@x:”StackExchange.Redis.RedisTimeoutException: 等待响应超时(出站=1403KB,入站=5657KiB,15000ms 已过,超时为15000ms),命令=EVAL,下一步:EVAL,指令:0,qu: 0,qs:709,aw:True,rs:ReadAsync,ws:Writing,in:0, serverEndpoint:redis-scr-mns-dev.redis.cache.windows.net:6380,mc: 1/1/0,经理:10人中的10人可用,客户名称:XXXXXXXXXX,IOCP: (忙=0,空闲=1000,最小=4,最大=1000),工作者: (忙=7,闲=32760,最小=4,最大=32767),v:2.1.58.34321 请参阅本文,了解一些可能导致错误的常见客户端问题 超时: )

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

  • 使用多个值设置最小线程池计数(threadpool.SetMinThreads(short.MaxValue,short.MaxValue);)
  • 将Redistimeout值从默认的5秒增加到15秒(老实说,再高一点也解决不了这个问题,因为您将进一步阅读:)
您询问的设置是什么

  • .NET Core 3.1RESTAPI在最新的IIS上运行,在具有16GB RAM的4核windows服务器上具有3个工作线程设置(在cpu或内存监控方面没有看到任何极端情况)
  • 已连接到Azure Redis缓存。目前正在运行一个基本C5,具有高网络带宽和23GB内存(以前是较低的,所以我们尝试扩展这个)
  • 最后将请求推送到Azure服务总线(没有问题)
一个批处理进程正在运行和处理10000个API调用(多个API),其中上面提到的一个调用在超时异常的情况下对Redis缓存崩溃。其他api正常运行且未超时,但当前正在连接到不同的Redis缓存(只是为了隔离此api的行为) 所有api和/或批处理程序都使用具有缓存实现的自定义NuGet包,因此我们确信这不会是该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>();
services.Configure(选项=>configuration?.GetSection(“缓存配置”).Bind(选项))
.AddStackExchangeDiscache(s=>
{
s、 配置=连接字符串;
})
.AddTransient()
.AddTransient();
老实说,我们没有主意了。我们认为Azure中的Redis缓存实例没有问题,因为当我们得到超时时,这个实例甚至还没有接近顶部。在较低的定价计划中,服务器负载达到约80%,而在较高的定价计划中,服务器负载甚至没有达到当前计划的10%

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

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

比较

  • 另一个Azure Redis缓存在没有任何问题的情况下(从内部部署)每分钟获得45K点击率
  • 这一次击中了暂停标志nog,甚至达到了每分钟10公里的命中率

    • 这里有两种可能的情况:

    • 我不知道那
      EVAL
      在做什么;可能是正在执行的Lua导致阻塞;唯一确定的方法是查看
      SLOWLOG
      ,但我不知道这是否在Azure redis上公开
    • 可能是您的有效负载正在饱和可用带宽-我不知道您正在传输什么
    • 它可能只是一个网络/插座暂停/中断;这种情况会发生,尤其是在云计算环境下,而且(相对)高的延迟使得这种情况特别痛苦
    • 我们希望启用一个新的可选池(而不是多路复用)模型;这在理论上(概念验证非常有效)可以避免大量积压,这意味着即使套接字出现故障:只影响一个调用,而不是导致级联故障;限制这一点的因素是我们的时间(而且,这需要与redis提供商的任何许可影响相平衡;例如,并发连接是否有上限)
    • 它可能只是库代码中的一个bug;如果是这样,我们在这里看不到它,但是我们没有使用与您相同的设置;我们尽我们所能,但很难诊断我们看不到的问题,这些问题只出现在其他人的成本设置中,我们无法轻易复制;最后加上:这不是我们的日常工作:(

    • 我不认为这里有一个简单的“添加这一行,一切都会变得很好”的答案。这些都是非琐碎的远程场景,需要大量调查。而且很简单:Azure人员不会为我们的时间付费。

      因此,我们发现了这个问题。 这个问题存在于类的注册中,如上面的原始代码所示。 将其更改为AddScoped时,性能要快得多
      .AddScoped<IRedisCache, RedisCache>()
              .AddScoped<ISharedCacheStore, SharedCacheStore>();