Ich bin mir nicht sicher, ob ich das hier oder in anderen Communities frage(dh SuperUser oder Unix&Linux)aber ich bleibe vorerst hier.
Ich habe eine dockerisierte NodeJS-App, die Selenium verwendet und von der PM2-Laufzeit verwaltet wird. Die App läuft auf der DO-Box mit1 GBErinnerung &25 GBFestplatte. Die App dient lediglich dazu, in regelmäßigen Abständen von 2 Minuten mithilfe von Selenium WebDriver Daten von einer Website abzurufen. Ich bin vor einiger Zeit auf dieses Problem gestoßen: Wenn ich mich per SSH mit der Box verbunden habe, gibt jeder Befehl Folgendes zurück:
-bash: fork: retry: Ressource vorübergehend nicht verfügbar
Richten Sie eine neue DO-Box mit Überwachung ein, um die Speichernutzung zu messen. Meine Nutzung stieg langsam an, also dachte ich, ich hätte irgendwo ein Speicherleck. Ich habe versucht, es zu finden, konnte es aber nicht(Immer noch am suchen)Ich habe gesehen, dass PM2 eineMöglichkeitum die App neu zu starten, wenn der Speicherverbrauch einen bestimmten Punkt erreicht. Als Vorsichtsmaßnahme habe ich dies auf800M
(80 %). Mein 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'
}
}
]
}
Als ich mich ein wenig umsah, sah ich, dassPM2 kann einen Speicherverlust verursachenindem ich die Garbage Collection nicht gründlich ausführe, also habe ich die Knotenargumente eingefügt, --expose-gc
um die Garbage Collection im Intervall von einer Minute zwangsweise auszuführen(bezogen aufdieses Beispiel):
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)
}
}
Ich dachte, das wäre in Ordnung, denn selbst wenn die Garbage Collection fehlschlägt, würde PM2 bei 80 % Auslastung neu gestartet. Ich startete den Container bei ungefähr22:45 Uhr (GMT +1)& meinem Nutzungsdiagramm nach zu urteilen, ist der Container ausgeschnitten @2:00 Uhr. Dies sind meine Nutzungsdiagramme der letzten 24 Stunden:
Sie können sehen, dass die Speichernutzung nicht einmal annähernd 80 % erreicht. Sollte ich also als vorübergehende Maßnahme meinen Neustartschwellenwert senken?
Ich habe versucht, die Speichernutzung auf der Box selbst anzuzeigen, aber jeder Befehl, den ich eingebe, gibt den oben genannten Fehler aus.
Lohnt es sich, dass ich versuche, es einzustellen --max_old_space_size
? Ich habe gesehen, dass ein NodeJS-Prozess versucht, sich selbst 1,5 GB Speicher zuzuweisen, die ich auf dieser Box nicht habe.
Ich bin sehr verwirrt, warum das passiert. Leider werden die Protokolle des Containers nur in eine lokale Datei auf der Box geschrieben, sodass ich jetzt nicht darauf zugreifen kann.
Ich habe versucht, die laufenden Container zu prüfen und es hat einmal etwas Nützliches zurückgegeben:
Mein npm start
Befehl ist:
sudo -E pm2-runtime --raw ecosystem.config.js --env Produktion --only Scraper
Und komplett 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"]
Ich werde bei Bedarf auf Anfrage Code bereitstellen, dachte aber zunächst nicht, dass es nötig wäre und wollte die Frage nicht zu umfangreich werden lassen :)
NOTIZ: Ich habe diese Frage ursprünglich auf SO gepostet, wurde aber gebeten, sie hierher zu verschieben
BEARBEITEN
Gemäß dem Kommentar von @dirkt sieht es so aus, als ob ich möglicherweise an ein Ressourcenlimit stoße. ulimit -a
Gibt mir Folgendes zurück:
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
Der Benutzer hat also Prozessgrenzen, und ich denke, das ist es, was ich erreiche. Ich bin mir jedoch nicht ganz sicher, wo ich diesen Wert ändern soll und ob ich ihn auf unlimited
einen beliebigen Wert setzen oder einfach erhöhen soll? In sind keine Grenzen festgelegt /etc/security/limits.conf
. Ich habe einige Möglichkeiten gesehen, die Soft-/Hard-Parameter zu ändern.( ulimit
CLI, limits.conf
, user.conf
– ich nehme an, dass Letzteres für mich irrelevant ist, da ich als arbeite root
)Grenzen für einen Benutzer. Es ist auch erwähnenswert, dass ich diesen Docker-Container alsroot
(wird sich in Zukunft ändern)