我们希望在我们的应用和服务之间共享ASP.NET会话状态。我们选择Elasticache / redis来实现这一目标。它进展顺利,但我们遇到了僵局。
这是死锁序列:
RedisSessionStateProvider
,在几毫秒内成功获取会话HttpWebRequest
,附加了ASP.NET_SessionId cookie RedisSessionStateProvider
,它尝试从同一个redis实例获取Session,并在~2分钟后超时推测App 1的RedisSessionStateProvider
在包含Session的缓存项上持有(写?)锁。从我的说法中可以看出,我不是雷迪斯大师......
AFAICT Elasticache让您无法看到这样的情况,只有性能图表。并且RedisSessionStateProvider
是封闭源代码,所以我不能在那里捅。
我还试图让RedisSessionStateProvider
记录(通过loggingClassName
参数),但App 1或App 2都没有写入(虽然我调用了Log()
方法)。< / p>
为了证明它是RedisSessionStateProvider
死锁(而不是我们自己的代码死锁),我将App 1切换回使用InProc会话,一切运行正常。
有没有人有任何建议?顺便说一下,我们的会话数据是所有意图和目的都是不可变的,因此确实没有必要将其锁定。
非常感谢, 皮特
编辑:sessionState配置按要求。请注意,较大的operationTimeoutInMilliseconds
值是为了在调试应用程序时不会出现异常。这将在生产中改为~5000。
<sessionState mode="Custom" customProvider="RedisSessionProvider">
<providers>
<add name="RedisSessionProvider"
type="Microsoft.Web.Redis.RedisSessionStateProvider"
host = "ec2-184-73-3-249.compute-1.amazonaws.com"
port = "6379"
ssl = "false"
throwOnError = "true"
retryTimeoutInMilliseconds = "2000"
applicationName = "PE"
connectionTimeoutInMilliseconds = "2000"
operationTimeoutInMilliseconds = "1800000"
</providers>
</sessionState>
答案 0 :(得分:1)
这不是答案,但不适用于评论部分。
在页面asp.net页面执行生命周期的开始,它调用GetItemExclusive从存储中获取会话(在本例中为redis)并对该会话设置锁定,以便其他并行请求在此请求工作时无法修改会话。此锁定的超时时间相当于您可以使用web.config设置的请求超时,如下所示。
<configuration>
<system.web>
<httpRuntime executionTimeout="10"/>
</system.web>
</configuration>
现在,页面执行并根据天气在会话中修改或未修改任何内容,它调用SetAndReleaseItemExclusive或ReleaseItemExclusive来释放锁定。如果此请求由于某种原因而失败,则会根据retryTimeoutInMilliseconds值重试。如果retryTimeoutInMilliseconds与operationTimeoutInMilliseconds非常小或相同,那么它可能根本不会重试。如果SetAndReleaseItemExclusive或ReleaseItemExclusive未成功完成,那么基本上您的会话将被锁定以完成您在上面设置的“executionTimeout”时间,以秒为单位。所有其他请求将被阻止,并且在锁定时将无法访问该会话。锁定将在到期时自动释放。
使用web.config属性loggingClassName和loggingMethodName配置日志记录。升级到上面的包时,可以在web.config注释中找到更多详细信息。您基本上可以提供一个返回TextWriter的公共静态方法。会话状态提供程序和StackExchange.Redis.StrongName都将使用此TextWriter对象来记录详细信息。
这将有助于我们获得有关问题的更多详细信息。请注意,启用日志记录会降低性能。
使用日志记录的示例:
namespace SSPWebAppLatest3
{
public static class Logger
{
public static TextWriter GetLogger()
{
return File.CreateText("C:\\Logger.txt");
}
}
}
的Web.config:
<add name="MySessionStateStore" type="Microsoft.Web.Redis.RedisSessionStateProvider" host="127.0.0.1" accessKey="" ssl="false"
loggingClassName="Logger, SSPWebAppLatest3, Version=1.0.0.0, Culture=neutral ……."
loggingMethodName="GetLogger"/>
请给我一个可重复的测试应用程序,我可以进一步调试它。您也可以像会话状态一样执行,输出缓存提供程序代码现在是开源的。 (https://github.com/Azure/aspnet-redis-providers)