2011-07-24 10 views
6

tengo 2 colecciones: A (3.8M docs) y B (1,7 millones docs)MongoDB - PHP - MongoCursorException 'Cursor no encontrado'

Tengo un script PHP que corro de la cáscara que:

  1. bucles sobre cada registro de una
  2. ~ 60% de las veces, lo hace un findOne en B (usando _id)
  3. hace algo de matemáticas básicas, creando una matriz PHP

una vez que el bucle en todos los documentos en una se realiza:

4) bucle sobre php array

5) upsert en colección C

durante (1), I consistentemente sale: error fatal PHP: no detectada excepción 'MongoCursorException' con el mensaje 'el cursor no se encontró' el último artículo procesado era # 8187 de 3872494.

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

Correr de nuevo, sin ningún cambio en el código, a excepción echaron en el artículo # 19826/3872495

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

Y una vez más, # 8181/387249

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

Sí, me doy cuenta de que puedo (y probablemente debería) detectar la excepción ... pero ... ¿Por qué es incluso ser arrojado? Especialmente a tiempos/profundidades tan diferentes en la base de datos.

Si ayuda, mi configuración es una réplica de 3 nodos (2 + arb). Tomé el secundario sin conexión y lo intenté con solo la ejecución principal. Los mismos resultados (diferente número de resultados procesados ​​y veces, pero siempre arroja la excepción del Cursor no encontrado).

+0

¿Esto fue finalmente un problema de tiempo de espera del cursor? Gracias – mils

Respuesta

0

Podría ser un problema de límite de memoria. Intente experimentar proporcionando más memoria y vea si los resultados varían, lo que puede hacer con la opción -d: php -d memory_limit = 256M yourscript.php

Eso es una gran cantidad de documentos, y parece que está haciendo una gran variedad de objetos. También hay varias funciones php como memory_get_usage() que puede usar para perfilar su asignación de memoria en tiempo de ejecución, así como para depurar extensiones como xdebug o lo que zend proporciona.

9

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

Sí, esto es definitivamente lo primero que debe hacer. ¿Hay docenas de razones legítimas para que ocurra una excepción? Diablos, ¿qué crees que sucede cuando la primaria se desconecta y se vuelve inalcanzable?

... why is it even being thrown?

Hay un par de razones posibles, pero vamos directo al código de error que está viendo.

  • Los documentos oficiales de PHP son here.
  • Cita de esa página: El controlador estaba tratando de obtener más resultados de la base de datos, pero la base de datos no tenía un registro de la consulta. Esto generalmente significa que el cursor agotó el tiempo de espera en el servidor ...

El conductor MongoDB PHP tiene dos tiempos de espera diferentes:

  • de espera de conexión
  • cursor tiempo de espera

Usted está golpeando un tiempo de espera del cursor. Puede conectarse a la base de datos, pero su consulta se está "quedando sin tiempo".

arreglos posibles:

  1. extender el cursor timeout. O puede configurarlo a cero y hacer que dure para siempre.
  2. Haga este trabajo por lotes. Obtenga los primeros 1000 _ids de A, trátelos y luego marque que ya lo hizo. A continuación, obtenga los próximos 1000 _ids mayores que su última ejecución y así sucesivamente.

Sugeriría # 2 junto con el manejo de la excepción. Incluso si esto no resuelve completamente el problema, lo ayudará a aislar y mitigar el problema.

+1

tiempo de espera del cursor resuelto mi problema (tiempo de espera después de 2k registros recuperados) –

4

Sé que es tarde y puede que esta no sea su solución, pero puede intentar usar immortal(). Como señaló VP de Gates, this page describe la excepción.

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).

que pensé que había puesto toda la descripción de otros que llegan a esta página y desde tiempo de espera() e inmortal() son diferentes. timeout() establece la cantidad de tiempo para esperar una respuesta. immortal() niega que el cursor muera debido a la inactividad.