2010-09-21 59 views
4

我有一個PHP進程正在寫一個文件大約每秒3次,然後幾個PHP進程正在讀取此文件的情況。Fopen文件鎖定在PHP(讀寫器類型的情況)

該文件本質上是一個緩存。我們的網站有一個非常堅持的輪詢,對於不斷變化的數據,我們不希望每個訪問者在每次輪詢時都觸及數據庫,所以我們有一個cron進程,每秒鐘讀取數據庫3次,處理數據,並將其轉儲到輪詢客戶端可以讀取的文件。

我遇到的問題是,有時打開文件寫入文件需要很長時間,有時甚至高達2-3秒。我是,假設發生這種情況是因爲它被讀取鎖定(或某些東西),但我沒有任何確鑿的證明方式,根據我從文檔中理解的內容,PHP不應該是鎖定任何東西 這種情況每2-5分鐘發生一次,所以很常見。

在代碼中,我沒有做任何類型的鎖定,我幾乎不在乎該文件的信息是否被破壞,如果讀取失敗,或者數據在讀取中發生了變化。 但是,如果寫入它需要2秒,本質上,因爲必須發生三秒鐘的過程現在跳過了幾次跳動,所以我很在意。

我在寫這個代碼的文件:

$handle = fopen(DIR_PUBLIC . 'filename.txt', "w"); 
fwrite($handle, $data); 
fclose($handle); 

而且我直接讀它:

file_get_contents('filename.txt') 

(它沒有得到直接提供給客戶作爲一個靜態文件,我得到一個正常的PHP請求,讀取文件,並做了一些基本的東西)

該文件約11kb,所以它不需要很多時間來讀/寫。遠低於1ms。

這是一個典型的日誌條目當問題發生:

如果
Open File: 2657.27 ms 
    Write: 0.05984 ms 
    Close: 0.03886 ms 

不知道它的相關性,但在讀取發生在常規的網絡請求,通過Apache,但寫是一個普通的「命令行」 PHP的執行是由Linux的cron完成的,它不通過Apache。

有什麼想法可能會導致這個大的延遲打開文件?
任何指針,我可以看看,以幫助我查明實際原因?

或者,你可以想一些我可以做的事情來避免這種情況嗎?例如,我希望能夠設置一個50ms的超時時間來打開文件,如果它沒有打開文件,它會跳過,並讓cron的下一次運行來處理它。

再一次,我的首要任務是保持cron三秒鐘的跳動,其他都是次要的,所以任何想法,建議,任何事情都是非常受歡迎的。

謝謝!
丹尼爾

+0

它取決於文件系統如何實現鎖定以及PHP是否尊重它們。如果您以讀取模式打開文件,則不應創建鎖定。但是,您可以用「a」替換「w」(只寫) – halfdan 2010-09-21 10:41:43

+0

要改變追加模式避免鎖定? – 2010-09-21 10:44:43

+0

正在寫入具有不同名稱的文件,然後將常用緩存文件名重命名爲一個選項? – 2010-09-21 10:48:47

回答

3

我能想到的3可能出現的問題:當讀/由下PHP的系統寫入調用而不讓你知道

  • 文件被鎖定。這應該阻止文件最多1/3。你會得到更長的時間。
  • fs緩存啓動一個fsync()並且整個系統阻塞對磁盤的讀/寫操作,直到完成。作爲一種修復方法,您可以嘗試安裝更多內存或升級內核或使用更快的硬盤。「緩存」解決方案不是分佈式的,它每秒多次觸發整個系統中性能最差的硬件。 。這意味着你不能通過增加更多的機器來進一步擴展它,只能通過增加硬盤速度。你應該看看內存緩存或APC,或者甚至共享內存http://www.php.net/manual/en/function.shm-put-var.php

解決方案我能想到的:

  • 把該文件在ramdisk http://www.cyberciti.biz/faq/howto-create-linux-ram-disk-filesystem/。這應該是避免經常碰到磁盤的最簡單的方法,無需其他重大更改。
  • 使用memcache。它在本地使用時速度非常快,可以很好地擴展,被「大」玩家使用。 http://www.php.net/manual/en/book.memcache.php
  • 使用共享內存。它是專爲您在這裏嘗試做...有一個「共享內存區域」...
  • 更改cron調度程序更新更少,也許實現某種事件系統,所以它只會更新緩存必要時,而不是按時間進行
  • 使「寫入」腳本寫入3個不同的文件,並隨機地從其中一個文件讀取「讀取器」。這可能允許在更多文件上「分佈」loking,並且可以減少在寫入文件時某個文件被鎖定的可能性......但是我懷疑它會帶來什麼明顯的好處。
+0

Quamis,非常感謝你的回覆。一些評論:我不是Linux專家,但是如果我正確讀取htop的輸出,它似乎正在使用25%的RAM。我知道這個緩存系統很糟糕。如果這是ASP.Net而不是PHP,我會毫不猶豫地將這些數據存儲在內存中。但是,開始使用memcache或甚至具有多個服務器是非常小的。我知道如果網站繼續增長,這將會產生可擴展性問題,但現在轉向更「嚴肅」的緩存系統沒有多大意義。 – 2010-09-21 13:04:36

+0

我不知道PHP共享內存,我認爲這是不可能與PHP。這看起來確實非常有趣......我將研究這一點。說實話,我沒有memcached的經驗,我想避免必須安裝一個新的系統,因爲我的系統管理員的專業知識。如果我們必須這樣做,但現在,我寧願採取更簡單的方法。非常感謝你!! – 2010-09-21 13:06:10

+0

有一個問題...... PHP的共享內存會在cron進程和Apache PHP進程中工作嗎?我有一個運行5分鐘並結束(並由cron重新啓動)的cron進程,然後Apache PHP進程響應讀取此共享內存的HTTP請求。這會正常工作嗎? – 2010-09-21 13:09:38

0

如果你想保證恆定的低開放時間,你應該使用真的快速解決方案。也許你的操作系統正在做磁盤同步,數據庫文件提交或其他你無法解決的事情。

我建議對這些任務使用memcached,redis甚至mongoDB。你甚至可以編寫自己的緩存守護進程,即使在PHP中(但這是完全不必要的,並且可能會非常棘手)。

如果您完全確定只能通過此文件緩存解決此任務,並且您處於Linux下,請嘗試使用不同的磁盤I/O調度程序,如最後期限,OR(cfq AND reduce PHP process priority到-3/-4)。

+0

說實話,我知道有更好的方法來做到這一點。我繼承了一個很大的代碼庫,並且沒有太多的預算(或者真的需要)來重新構建整個事情。我知道這是一個糟糕的做法,但它應該足夠好,至少在我們的流量水平下很長一段時間。所以我試圖解決這個問題,而不用重寫很多代碼。如果我不能,那麼我會進入更復雜的解決方案。 – 2010-09-21 13:08:02