2015-05-06 86 views
1

我們希望在我們的應用程序和服務之間共享ASP.NET會話狀態。我們選擇了Elasticache/redis來實現這一點。它進展順利,但我們遇到了一個僵局。RedisSessionStateProvider Elasticache死鎖

這裏的僵局序列:

  • 用戶導航到
  • 應用1使用RedisSessionStateProvider病死豬1提供的頁面,成功地獲取在幾毫秒內會話
  • 應用程序1,使一個HttpWebRequest到App 2 ,連接了ASP.NET_SessionId cookie
  • 應用2還使用RedisSessionStateProvider,它嘗試從相同的redis實例中獲取Session並在〜2分鐘後超時

推測應用程序1的RedisSessionStateProvider在包含會話的緩存項目上持有(寫入?)鎖定。正如你從我的說法,你可以告訴我,我不是redis大師...

AFAICT Elasticache讓你沒有看到像這樣的情況,只是表現y圖。而且RedisSessionStateProvider是封閉的,所以我不能在那裏捅。

我也試着讓RedisSessionStateProvider登錄(通過loggingClassName參數),但沒有任何應用程序1或應用程序2寫入(我的Log()方法被稱爲雖然)。

爲了證明它是RedisSessionStateProvider死鎖(而不是我們自己的代碼死鎖),我將App 1切換回使用InProc會話,並且一切運行良好。

有沒有人有任何建議?順便說一句,我們的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> 
+0

剛剛嘗試https://github.com/welegan/RedisSessionProvider,它沒有把/任何東西放到redis上。任何人看到這個? – sming

+0

你能否提供app1和app2的web.config設置? –

+0

@SiddharthChatrola他們太久無法發佈。你只想要部分? – sming

回答

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

+0

嗨Siddharth,謝謝你的信息。我要fork並添加一個布爾型配置屬性「TakeWriteLock」,看看它是如何發生的。再次感謝。 – sming

+0

嗨Siddharth,我實現了TakeWriteLock選項,現在正在從Microsoft.Web.Redis.StackExchangeClientConnection.Eval(從Microsoft.Web.Redis.RedisConnectionWrapper.TryUpdateAndReleaseLockIfLockIdMatch調用)獲取NRE,而且我的redis深度有點超出。 .. – sming

+0

可以請你在微軟公司的azurecache上與我們分享可複製的應用程序嗎?我們可以從那裏調試 –