2011-07-24 43 views
6

我有2個集合:A(3.8M文檔)和B(1.7M文檔)的MongoDB - PHP - MongoCursorException '遊標未發現'

我有一個PHP腳本,我從shell運行:

  1. 遍歷中的時刻A
  2. 〜60%的每個記錄,它在B中的findOne(使用_id)
  3. 做一些基本的數學,創建一個php陣列

一旦在所有文檔循環完成:PHP的致命錯誤:

4)環比PHP數組

5)UPSERT到收集℃持續(1),我一直得到

未捕獲例外「MongoCursorException」有消息「遊標未發現」 處理的最後一個項目是#8187的3872494.

real 1m25.478s 
user 0m0.076s 
sys  0m0.064s 

再次運行它,在代碼中沒有變化,除了拿到項目#拋出3872495分之19826

real 3m19.144s 
user 0m0.120s 
sys  0m0.072s 

再次,#387249分之8181

real 1m31.110s 
user 0m0.036s 
sys  0m0.048s 

是的,我知道我可以(並且可能應該)捕捉到了異常......但爲什麼它甚至被拋出?特別是在數據庫中這種不同的經過時間/深度。

如果有幫助,我的設置是一個3節點副本集(2 + arb)。我把輔助線路脫機,並嘗試只是主要運行。相同的結果(處理的結果數量和次數不同,但始終引發未找到Cursor異常)。

+0

這是否最終是一個遊標超時問題?謝謝 – mils

回答

0

這可能是內存限制問題。嘗試嘗試提供更多的內存並查看結果是否有所不同,您可以使用-d選項進行嘗試:php -d memory_limit = 256M yourscript.php

這是很多文檔,聽起來像是你製作相當大量的對象。還有各種各樣的php函數,比如memory_get_usage(),可以用來在運行時分析內存分配,以及調試xdebug或zend提供的擴展。

9

Yes, I realize that I can (and probably should) catch the exception...

是的,這絕對是第一件要做的事。有幾十個合法的原因會發生異常?嘿,當小學離線並且變得無法到達時,你認爲會發生什麼?

... why is it even being thrown?

有幾個潛在的原因,但我們直接切到你看到的錯誤代碼。

  • 官方PHP文檔是here
  • 引自該頁:驅動程序試圖從數據庫中獲取更多結果,但數據庫沒有查詢記錄。這通常意味着光標超時在服務器端...

MongoDB的PHP驅動程序有兩個不同的超時:

  • 連接超時
  • 光標超時

你打光標超時。您可以連接到數據庫,但是您的查詢「耗盡時間」。

可能的修正:

  1. 擴展光標timeout。或者你可以將它設置爲零並使其永遠持續。
  2. 分批完成這項工作。從A獲得第一個1000 _ids,處理它們,然後標記你已經這樣做了。然後獲得比你上次運行更大的下一個1000 _ids等等。

我會建議#2,並處理異常。即使這些不能完全解決問題,它也會幫助您隔離和緩解問題。

+1

遊標超時解決了我的問題(取出2k個記錄後超時) –

4

我知道這是晚了,這可能不是你的解決方案,但你可以嘗試使用immortal()。正如蓋茨VP指出的,this page描述了這個例外。

The driver was trying to fetch more results from the database, but the database did not have a record of the query. This usually means that the cursor timed out on the server side: after a few minutes of inactivity, the database will kill a cursor (see MongoCursor::immortal() for information on preventing this).

我想我會發布其他人的整個描述到達此頁面,因爲timeout()和immortal()是不同的。 timeout()設置等待響應的時間量。 immortal()由於不活動而拒絕光標死亡。