Buff! Por fin lo hemos solucionado.
Nos hemos pasado varios días buscando por qué al insertar millones de registros en MongoDB nos acaba cascando siempre. Después de insertar varios millones acababa por rechazar cualquier nueva inserción de un documento mostrando el siguiente error en los logs para cada intento:
ERROR: mmap() failed for ...
len: .... errno:12 Cannot allocate memory
El momento en el que casca dependía de la máquina en la que lo probáramos. El error es muy fácil de reproducir, basta con insertar una cantidad elevada de registros y esperar.
Por ejemplo, el siguiente código en PHP provoca el error (inserta los registros en una hipotética colección “test” en la base de datos “TESTDB” en un servidor MongoDB con la autentificación de usuario activada y nombre de usuario y clave de acceso “mongodb”):
$mng_host = "localhost";
$mng_user = "mongodb";
$mng_password = "mongodb";
// Open a connections to MongoDB
$mngcon = new Mongo("mongodb://".$mng_user.":".$mng_password."@".$mng_host);
$collection = $mngcon->TESTDB->test;
$entries = 50000000;
for ($i = 1; $i <= $entries; $i++) {
$document = array(
'_id' => $i,
'datetime' => new MongoDate(time()),
);
$collection->insert($document);
if ($i % 1000 == 0) {
printf ("%d (of %s) entries saved in MongoDB\n", $i, $entries);
}
}
?>
Hemos probado el mismo código en Python para descartar que pudiera deberse a problemas con el driver de PHP y también ha fallado.
MongoDB va reservando memoria RAM para utilizarla como caché. Haciendo pruebas en distintas máquinas la conclusión a la que hemos llegado es que llega un momento en el que el sistema operativo no le deja reservar más y falla.
La solución, aportada por el crack de la administración de sistemas Alejandro Gándara Álvarez, ha consistido en indicar al sistema operativo que no limite el tamaño del proceso en memoria. Para ello hay que ejecutar el siguiente comando de consola antes de arrancar el servicio
ulimit -v unlimited
Después de haberlo hecho hemos podido insertar decenas de millones de registros sin problema alguno.
Hemos establecido el tamaño máximo del proceso en memoria a ilimitado con el comando ulimit imitando lo que se hace en máquinas con servidores Oracle. El efecto colateral de ésto es que el proceso consumirá toda la memoria que necesite, no dejando espacio para otros procesos. Es una medida pensada para máquinas cuyos recursos están dedicados únicamente a la instancia MongoDB.
Comentarios
Alejandro Gándara Álvarez#
Gran Post!!!, ja ja ja. Sigue así Ciges
Miguel Angel Cortez#
Maravilloso articulo!! GRACIAS
Añadir comentarios ...