No estoy seguro de si preguntas esto aquí o en otras comunidades.(es decir, superusuario o Unix y Linux)pero me quedaré aquí por ahora.
Tengo una aplicación NodeJS acoplada que usa Selenium y está administrada por el tiempo de ejecución PM2. La aplicación se ejecuta en el cuadro DO con1GBMemoria &25GBDisco. La aplicación simplemente extrae datos periódicamente de un sitio web en un intervalo de 2 minutos utilizando Selenium WebDriver. Me encontré con este problema hace un tiempo en el que, si ingresaba por SSH en el cuadro, cualquier comando devolvía:
-bash: bifurcación: reintentar: recurso no disponible temporalmente
Configure una nueva caja DO con monitoreo para medir el uso de la memoria. Mi uso estaba aumentando, así que pensé que tenía una pérdida de memoria en alguna parte. Intenté encontrarlo pero no pude.(sigue buscando). Vi que PM2 tiene unopciónpara reiniciar la aplicación si el uso de la memoria llega a cierto punto. Como precaución, puse esto en800M
(80%). Mi ecosystem.config.js
:
module.exports = {
apps: [
{
name: 'scraper',
script: './index.js',
watch: process.env.NODE !== 'production',
ignore_watch: ['node_modules', 'logs', 'test', 'scripts', '.vscode', '.git'],
out_file: './logs/app.log',
max_memory_restart: '800M',
node_args: '--expose-gc',
env_development: {
NODE_ENV: 'development'
},
env_production: {
NODE_ENV: 'production'
}
}
]
}
Después de mirar un poco más a mi alrededor, vi quePM2 puede causar una pérdida de memoriaal no ejecutar la recolección de basura a fondo, así que incluí los argumentos del nodo --expose-gc
para forzar la ejecución de la recolección de basura en un intervalo de un minuto.(Residencia eneste ejemplo):
exports.generateHeapDumpAndStats = function() {
try {
if (global.gc) {
global.gc()
} else {
logger.info('Garbage collection unavailable. Use "--expose-gc" when launching to enable forced garbage collection')
}
const heapUsed = process.memoryUsage().heapUsed
const heapUsedMb = (heapUsed / 1024 * 1024).toFixed(2)
logger.info(`Program is using ${heapUsedMb} MB of heap`)
} catch (err) {
logger.error(`Error: ${err.message}`)
process.exit(1)
}
}
Pensé que esto se encontraría, ya que incluso si falla la recolección de basura, PM2 se reiniciaría con un uso del 80%. Empecé el contenedor @ aproximadamente22:45 (GMT+1)Y a juzgar por mi gráfico de uso, el contenedor se cortó @02 a.m. Estas son mis gráficas de uso de las últimas 24 horas:
Puede ver que el uso de la memoria ni siquiera se acerca al 80%, entonces, ¿debería reducir mi umbral de reinicio como medida temporal?
Intenté ver el uso de memoria en el cuadro, pero cualquier comando que escribo arroja el error anterior.
¿Vale la pena intentar configurarlo --max_old_space_size
? He visto que un proceso NodeJS intenta asignarse 1,5 GB de memoria que no tengo en este cuadro.
Estoy muy confundido en cuanto a por qué sucede esto. Lamentablemente, los registros del contenedor solo se escriben en un archivo local en la caja, por lo que no puedo acceder a ellos ahora.
Intenté comprobar los contenedores en ejecución y una vez escupió algo útil:
Mi npm start
comando es:
sudo -E pm2-runtime --raw ecosistema.config.js --env producción --solo raspador
Y completo Dockerfile
:
FROM selenium/standalone-chrome
WORKDIR /usr/src/app
RUN curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
RUN sudo apt-get install -y nodejs build-essential firefox
# copy package.json & package-lock.json and install packages
# we do this separate from the application code to better use docker's caching
# `npm install` will be cached on future builds if only the app code changed
COPY package*.json ./
RUN sudo npm install pm2 -g
RUN sudo npm install
# ENV vars dynamically set here by CI
# copy the app
COPY . .
# expose port for express & start
EXPOSE 3000
CMD [ "npm", "start"]
Proporcionaré el código a pedido si es necesario, simplemente no pensé que fuera necesario inicialmente y no quería hacer la pregunta demasiado grande :)
NOTA: Inicialmente publiqué esta pregunta en SO pero me pidieron que la moviera aquí.
EDITAR
Según el comentario de @dirkt, parece que podría estar alcanzando un límite de recursos. ulimit -a
me devuelve:
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 3842
max locked memory (kbytes, -l) 16384
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 3842
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
Entonces el usuario tiene límites de proceso, que es lo que creo que es lo que estoy alcanzando. Sin embargo, no estoy completamente seguro de dónde modificar este valor. ¿Lo configuro unlimited
o simplemente lo elevo a un valor arbitrario? No hay límites establecidos en /etc/security/limits.conf
. He visto algunas formas de alterar el suave/duro.( ulimit
CLI, limits.conf
- user.conf
Me imagino que esto último es irrelevante para mí ya que estoy ejecutando como root
)límites para un usuario. También vale la pena señalar que estoy ejecutando este contenedor acoplable comoroot
(cambiará eso en el futuro)