RedisSessionStateProvider

RedisSessionStateProvider

我们希望在我们的应用程序和服务之间共享ASP.NET session 状态。我们选择Elasticache / redis来实现这一目标。一切顺利,但我们陷入了僵局。

这是死锁序列:

  • 用户导航到App 1
  • 服务的页面
  • 应用程序1使用RedisSessionStateProvider,在几毫秒内成功获取 session
  • 应用程序1向应用程序2生成HttpWebRequest,并附加了ASP.NET_SessionId cookie
  • App 2还使用RedisSessionStateProvider,它尝试从相同的redis实例获取 session ,并在大约2分钟后超时

  • 大概是应用1的RedisSessionStateProvider在包含 session 的缓存项上持有(写?)锁。如您所见,我不是Redis专家...

    AFAICT Elasticache无法让您看到这种情况,只是性能图。 RedisSessionStateProvider是开源的,所以我不能在那儿戳。

    我还尝试获取RedisSessionStateProvider记录(通过loggingClassName参数),但是App 1或App 2都没有写入任何内容(尽管我的Log()方法被调用)。

    为了证明这是RedisSessionStateProvider死锁(而不是我们自己的代码死锁),我将App 1切换回使用InProc session ,并且一切正常。

    有没有人有什么建议?顺便说一句,我们的Session数据在所有意图和目的上都是不可变的,因此确实不需要锁定它。

    非常感谢,
    皮特

    编辑:根据要求的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>
    

    最佳答案



    在页面asp.net页面执行生命周期开始时,它将调用GetItemExclusive,它从存储中获取 session (在本例中为redis)并锁定该 session ,以便其他并行请求无法在此请求工作时修改 session 。该锁定具有与您可以使用web.config设置的请求超时等效的超时,如下所示。

    <configuration>
      <system.web>
        <httpRuntime executionTimeout="10"/>
      </system.web>
    </configuration>
    

    现在,页面将执行,并根据天气情况在 session 中进行了任何修改或未修改的操作,它调用SetAndReleaseItemExclusive或ReleaseItemExclusive来释放锁定。如果此请求由于某种原因失败,它将根据retryTimeoutInMilliseconds值重试。如果retryTimeoutInMilliseconds与operationTimeoutInMilliseconds很小或相同,则它可能根本不重试。如果SetAndReleaseItemExclusive或ReleaseItemExclusive未成功完成,则基本上您的 session 将锁定您在上面设置的“executionTimeout”的完整时间(以秒为单位)。所有其他请求都将被阻止,并且在 session 被锁定时将无法访问。锁到期时将自动释放。

    使用web.config属性loggingClassName和loggingMethodName来配置日志记录。升级到以上软件包时,您可以在web.config注释中找到更多详细信息。您基本上可以提供一个公共(public)的静态方法,该方法返回TextWriter。 session 状态提供程序和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"/>
    

    请寄给我一个可重现的测试应用程序,以便进一步调试它。您还可以执行与 session 状态相同的操作,并且输出缓存提供程序代码现在是开源的。 (https://github.com/Azure/aspnet-redis-providers)

    关于asp.net - RedisSessionStateProvider Elasticache死锁,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30082609/

    10-09 17:36