2014-09-03 63 views
17

這是我們在過去幾周面臨的問題。PHP中的隨機會話數據丟失

1 /我們的設置

  • PHP 5.4 + MySQL的
  • 2專用服務器使用分佈式緩存
  • 3應用程序,負載平衡
  • 會話在2個服務器之間複製這些運行服務器:
    • 一個自定義開發的應用程序,使用默認的PHP會話設置
    • 另一個定製developped應用程序,使用不同的會話設置(cookie名稱,路徑)
    • 一個WordPress的CMS

2 /問題

,我們第一次出現的問題應用。

我們的一些用戶報告說,他們有時會在幾分鐘後斷開連接(當會話設置爲最後3小時時)。它可能會在同一天發生幾次,然後幾天沒有斷開,但問題總是會回來。 到目前爲止,受影響的用戶比例很小,但我希望在它「傳播」給其他用戶之前解決此問題。

這個問題似乎在應用程序的不同地方發生,但我們已經確定了3個scenarii大多數錯誤的發生:

  • 一些涉及提交表單($ _SESSION變量修改)
  • 其他只是涉及打開一個彈出頁面,沒有修改會話數據

我們試圖重現用戶描述的不同情景:有時我們能夠,但大多數時候我們不能有任何公關這使得它很難調試。

其他說明:

  • 問題是最近,這個應用程序已經運行了數年沒有任何問題。
  • 它似乎不涉及我們的服務器負載,因爲問題仍然發生在暑假期間,當我們的交通不便時
  • 它一次隻影響一個會話/用戶:所有其他用戶登錄同時當斷開時不會遇到此問題上的所有不同的瀏覽器
  • 問題發生(IE,火狐,Chrome)

3 /技術分析

中,用戶重定向添加到頁面「您的會話已過期,或者您無權查看」。當這個頁面被加載時,我們得到一個帶有$ _SESSION變量轉儲的技術郵件。

當會話以正常方式到期時,我們得到的電子郵件顯示$ _SESSION變量爲空(正常行爲)。 當意外的斷開連接發生時,有趣的是$ _SESSION不完全是空的:在數組包含的〜20個元素中,只剩下一個(總是相同)。

所以這意味着會話沒有過期,但沒有足夠的數據來「標識」用戶,因此顯示「無權限」頁面。作爲發生這種情況的確認,我們可以檢查memcached,此會話仍保留一些數據。

這些都是潛在的問題會導致到目前爲止,我們已經確定,而我們所做的,以排除他們:

  • Memcached的指示70等80%的自由空間之間,所以我們不認爲這是問題。
  • 我們刪除了Memcached並返回使用會話文件的NFS共享目錄:問題實際上變得更糟。這將指向一個應用程序錯誤,因爲NFS寫入數據較慢,會話丟失會更頻繁地發生。
  • 我們瀏覽了所有討論PHP會話數據丟失的論壇(包括SO),並相應地檢查了我們的代碼。代碼庫很大,但我們使用自動化工具和腳本來避免丟失文件。
    • session_start()在每個頁面的開頭被調用。
    • exit()時每頭後調用(「位置...」)
    • register_globals被關閉
  • 我們已經測試了我們2個其他應用程序和有問題的一個之間可能interractions,雖然他們不不共享任何代碼,數據庫或會話處理。沒有在那裏確定。
  • 我們分析了斷開連接時間的訪問日誌,以檢查行爲模式:這裏也沒有運氣。

所以我們不知道是什麼原因導致這個問題,因爲它似乎是隨機發生的,所以我的問題是:

  • 問題可能來自於我們的代碼:難道我們錯過了什麼檢查?這些解決方案似乎不太可能,因爲代碼大部分時間都適用於所有用戶,但我仍在考慮這一點。
  • 問題可能來自另一個應用程序/進程,它將「清空」部分會話變量數組。我們也檢查了其他應用程序的代碼,但沒有發現任何可能導致此問題的內容。 如果另一個進程正在這樣做,爲什麼它只會清空一些會話而不是所有會話?

感謝您的幫助。

+3

問題的出現是否與PHP升級一致? – 2014-09-03 11:27:56

+0

我碰到過這個問題的機會......我們在Memcached服務器上出現隨機會話丟失的問題。 PHP應用程序,運行PHP 5.3的兩臺服務器負載均衡。我們還有一個專門的數據庫服務器,安裝了Memcached。某些用戶的會話在登錄後2分鐘過期。其他人可以整天無需註銷。 – 2014-09-03 11:34:39

+0

您是否考慮過不使用Memcached,而是在您的服務器之間使用共享會話目錄,並且只使用基於PHP的本地文件會話。假設你使用php.ini來定義memcached會話,這將是任何簡單的切換,只需創建一個共享卷,將其掛載到所有服務器(fstab進行自動掛載)並切換session.save_path =「/ path/to/mount」 ,如果問題仍然存在,它可能是您的應用程序,否則可能是PHP/Memcache不能很好地一起玩。 – 2014-09-03 11:36:40

回答

1

我不認爲你會得到一個明確的答案你的問題。有太多可能的原因,你沒有顯示任何代碼。

不過,我的猜測是你有memcached.sess_locking關閉,或者如果你有一個自定義的會話實現 - 它根本沒有實現鎖定。
最終,這導致了兩個同時發生的HTTP請求之間的爭用情況。

我的猜測是基於經常看到的不好的建議來關閉鎖定或儘快釋放它們,以獲得更高的性能。

+0

我在我的控制器上完成後,我總是釋放我的鎖,我通常沒有任何需要鎖定超出身份驗證的會話控制器(處理登錄和註銷)。其他任何事情都可以是安全的,因爲它知道它正在做的事情不會更新會話。當然,這需要我明確調用'SessionManager :: Dispose()'釋放它(引擎內部調用'session_write_close()'並確保任何調用'__set'的日誌記錄錯誤並拋出異常。 – scragar 2014-09-09 17:08:22

+0

你正在做的就是@scragar。關閉會話*是正確的事情,問題在於當會話仍處於活動狀態時釋放鎖定。 – Narf 2014-09-10 07:14:17

+0

我們檢查:會話鎖定已激活 – Yann 2014-09-25 07:52:14

0

如果此問題「突然」出現,請檢查已更改的內容。你有沒有在應用程序上做任何工作?如果是這樣的話,檢查提交的代碼(你談到了自動化工具,所以我期望有一個存儲庫,可以準確查找代碼更改)。 你有沒有改變服務器上的任何東西?像升級軟件一樣,升級/更換硬件,更改其他兩個應用程序? 有一件事想起來,你檢查了用於緩存的驅動器嗎?它可能是文件系統的一個損壞部分。這將解釋隨機用戶部分。

我幾件事情我總是爲:

  • 嘗試確定首次出現的時刻儘可能準確。在我的工作中,偶爾會觸發某人說:「當我更改/更新/創建這個或那個時可能需要做的事情」,所以這可能會有所幫助。另一方面,有時需要幾天,幾周甚至更長的時間才能得到注意,所以如果沒有出現,就要開始擴大這個時間範圍。
  • 您已經有幾個場景,找到這些中的公因子。如果他們不共享任何代碼,請停止在那裏尋找。如果他們在那裏共享代碼搜索。當然,在這裏共享(部分)可能會幫助我們幫助您進行搜索。
  • 做一個有組織的搜索。我通常會在主要應用程序上執行主應用程序檢查(當我創建應用程序時甚至更好)。一位同事會檢查可能影響它的周邊應用程序。在你的情況下,這2個其他應用程序最後,我們的系統管理員將檢查服務器上新安裝或更新的軟件,他還將與我們的網絡人員檢查是否有任何硬件方面或網絡相關的改變(對於其他人可能是託管提供商)。
0

它可以像使用會話和呼叫或者session_name()session_id()不同的值,重疊使用默認會話設置您的自定義應用程序WordPress插件一樣簡單。

由於WordPress本身並不使用會話,所以插件通常是從釋放會話的角度編寫的。我只是在一個WordPress測試網站上進行了一次搜索,發現了一個插件庫中使用的會話,一個用於在頁面上放置背景圖片的插件,一個購物車插件以及一個我正在編寫的插件,用於從一個上傳文件管理頁面到另一個。