作者:人民总动员 | 来源:互联网 | 2022-12-08 19:14
我们有一个在Azure App Service上运行的.NET 4.6.1 ASP.NET Web窗体应用程序.我说Web Forms,但该应用程序还包含Web Api 2,以及两个WebJob项目,每个项目执行几个任务.
我们使用StackExchange.Redis进行缓存.我们还将Redis用于SessionState.我提到这一点,因为问题始于Redis连接的建立,除非我们重新启动ASP.NET应用程序,否则它们不会死亡.我们使用Lazy模式重新传输ConnectionMultiplexer.本地测试确认连接确实在各个请求中共享.
我们对Redis配置充满信心,开始关注与ASP.NET应用程序相关的指标.线程计数反映了我们的Redis客户端图.问题是,我不知道什么是正常的线程数.但我希望他们能在几天内处理/消失/死亡.没有积累.
我们广泛使用Async/Await,但我们通常不直接处理线程.最后一行可能听起来有点幼稚,抱歉不知道怎么回事.我们倾向于在工作日看到最忙碌的时间,夜间活动最少.
我们不知所措,我们做错了什么?我是对的,我们是否应该看到线程数量下降而网站上的活动减少了?也许我已经说了一些你可以指出并说"你到底在做什么?"的东西,那就太好了.我真正追求的是对我们可能负责这些线程构建以及我们如何管理它的建议.
更新03/08
第二个图像中的线表由SUM聚合.如果将聚合更改为MIN,MAX或AVG,则会看到更合理的线程计数,它表明线程正确处理.对于网络应用来说,这显然是一个很大的缓解.
我假设,虽然我的谷歌搜索没有设法确认它,SUM表示自上次应用程序重新启动以来创建的线程总数.如果我在这个假设中是正确的,那么Web应用程序线程数的SUM与AVG Redis客户端计数相匹配的事实证实了我们最初的怀疑,即我们的连接多路复用器不仅不共享连接,它们也不会被关闭操作完成.
这是我们的Redis类,它与interweb上的其他1000个示例相同,至少据我所知:
Imports System.Configuration
Imports StackExchange.Redis
Public Class RedisCache
Private Shared ReadOnly Property LazyConnection As New Lazy(Of ConnectionMultiplexer)(Function()
Dim cacheCOnnection= ConfigurationManager.AppSettings("CacheConnection")
Dim multiplexer = ConnectionMultiplexer.Connect(cacheConnection.ToString())
multiplexer.PreserveAsyncOrder = False
Return multiplexer
End Function)
Public Shared ReadOnly Property Connection As ConnectionMultiplexer
Get
Return LazyConnection.Value
End Get
End Property
Public Shared ReadOnly Property UseCache As Boolean
Get
Return ConfigurationManager.AppSettings("CacheConnection") IsNot Nothing
End Get
End Property
End Class
正如我已经提到的,我们也使用Redis作为会话状态,我们有一个非常基本的配置:
有没有人有什么想法延长这些客户的生命?
更新03/08第二部分
我一直在考虑如何缩小这个问题.最简单的起点是"它是Cache,Session还是Redis整体?" 为此,我们将启动一个额外的Redis服务器,在下一个版本中,它将具有指向它的Cache或Session State.希望其中一个服务器会表现出我们试图修复的相同行为,而另一个服务器表现出来,嗯,更好.两者的前者将是我们集中努力的地方.
在我们的测试环境中,我所做的另一件小事是创建一个测试属性,它以与Connection
属性相同的方式生成一个新的GUID :
Private Shared ReadOnly Property LazyGuid As New Lazy(Of Guid)(Function() Guid.NewGuid())
Public Shared ReadOnly Property Guid As Guid
Get
Return LazyGuid.Value
End Get
End Property
然后我创建了一些来自Web应用程序各个部分,新GUID属性以及现有Redis代码的调用:
Public Async Function GetGuid() As Task(Of Tuple(Of String, String))
Return New Tuple(Of String, String)(RedisCache.Guid.ToString(), If(RedisCache.UseCache, RedisCache.Connection.ClientName, Nothing))
End Function
Public Async Function PostForGuid() As Task(Of Tuple(Of String, String))
Return New Tuple(Of String, String)(RedisCache.Guid.ToString(), If(RedisCache.UseCache, RedisCache.Connection.ClientName, Nothing))
End Function
Public Function GetSyncGuid() As Tuple(Of String, String)
Return New Tuple(Of String, String)(RedisCache.Guid.ToString(), If(RedisCache.UseCache, RedisCache.Connection.ClientName, Nothing))
End Function
上面的示例以及嵌入在ASPX页面中的一些调用跨多个会话(和时区)产生了相同的结果.所以目前我强烈怀疑这个错误RedisSessionStateProvider
或者至少是我们对它的使用.
更新13/08
首先,我在测试服务器上运行了两个Redis实例大约一周.一个接受Session请求,另一个接受来自上面的RedisCache类的请求.两人都坐在15-20连接.
这个更新的要点虽然如此.我有想法在生产Redis上运行CLIENT LIST.由于客户端数量约为1.3k,我设法获取了850个客户端行的样本.
在整个样本中,有一个客户端有最后一个GET命令,其余的是UNSUBSCRIBE或INFO.年龄范围从5000秒到65,000秒.空闲时间范围为0到60秒.据我所知,UNSUBSCRIBE命令与StackExchange.Redis对pub/sub功能的处理有关,据我所知,我没有使用它.
为什么这些客户保持活跃并成倍增长?
id=1367825 addr=*** fd=45 name=*** age=465516 idle=56 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 ow=0 owmem=0 events=r cmd=info numops=7680
id=1319911 addr=*** fd=611 name=*** age=489772 idle=48 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 ow=0 owmem=0 events=r cmd=info numops=8082
id=1409149 addr=*** fd=477 name=*** age=444591 idle=34 flags=N db=0 sub=1 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 ow=0 owmem=0 events=r cmd=unsubscribe numops=7328
id=1319912 addr=*** fd=508 name=*** age=489772 idle=38 flags=N db=0 sub=1 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 ow=0 owmem=0 events=r cmd=unsubscribe numops=8072
id=2169495 addr=*** fd=954 name=*** age=59035 idle=56 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 ow=0 owmem=0 events=r cmd=info numops=984
id=2169496 addr=*** fd=955 name=*** age=59035 idle=56 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 ow=0 owmem=0 events=r cmd=info numops=984
id=1219863 addr=*** fd=557 name=*** age=540498 idle=38 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 ow=0 owmem=0 events=r cmd=info numops=8917
id=1032642 addr=*** fd=594 name=*** age=635373 idle=56 flags=N db=0 sub=1 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 ow=0 owmem=0 events=r cmd=unsubscribe numops=10474
更新14/08
一个潜在的积极发展.我在Github上记了一张票.听起来像我们症状的问题已在2.0中修复.永远不会死的客户