PM2 არის Node.js-ის პროცესების მენეჯერი: პატარა ფონური daemon, რომელიც გაუშვებს შენს აპლიკაციას, გათიშვისას თავიდან ჩართავს, მის გამოტანილ ტექსტს ლოგ-ფაილებში შეინახავს და რებუტის შემდეგ ყველაფერს უკან დააბრუნებს. სწორად გამოყენებისას ეს ოთხი რამეა - რეპოზიტორიაში მდებარე ecosystem.config.js, ამ ფაილზე გაშვებული pm2 start, pm2-logrotate, რომ ლოგებმა დისკი არ გაავსოს, და pm2 save პლუს pm2 startup, რომ მანქანამ დაიმახსოვროს, რა უნდა გაუშვას. PM2-თან დაკავშირებული პრობლემების უმეტესობა იქიდან მოდის, რომ ამ ოთხიდან ერთ-ერთი გამოტოვებულია, ან PM2 იმ ადგილას გაუშვეს, სადაც შენს პროცესს უკვე სხვა ამოწმებს.
ეს ბოლო პუნქტი განსაზღვრავს, გჭირდება თუ არა PM2 საერთოდ. ჩვეულებრივ virtual ან dedicated სერვერზე აპლიკაციას არაფერი გადატვირთავს, სანამ თავად არ მოაწყობ, და PM2 გონივრული არჩევანია. ჰოსტინგ პანელის container-ში პლატფორმა თავად არის ზედამხედველი, მეორე ზედამხედველი კი მისგან მოხდენილ crash-ებს მალავს - ეს შემთხვევა სრულად განხილულია სტატიაში PM2 და ჰოსტინგ პანელი და აქ არ მეორდება. ეს გზამკვლევი ვარაუდობს, რომ სერვერს თავად მართავ, და აჩვენებს, როგორ უნდა იყოს PM2 იქ მოწყობილი.
რა არის PM2 და როგორ მუშაობს#
PM2 ორი ნაწილისგან შედგება. daemon არის დიდხანს მომუშავე Node პროცესი, რომელსაც შენი აპლიკაციები ეკუთვნის: ის უშვებს მათ, აკვირდება, თავიდან ჩართავს და მათ standard output-სა და standard error-ს ფაილებში წერს. CLI - ბრძანება pm2 - კლიენტია, რომელიც daemon-თან socket-ით ურთიერთობს. როცა pm2 start-ს აკრიფებ, CLI ჩართავს daemon-ს, თუ ის ჯერ არ მუშაობს, სთხოვს აპლიკაციის გაშვებას, გამოსცემს ცხრილს და თავად მთავრდება. აპლიკაცია განაგრძობს მუშაობას, რადგან daemon მუშაობს.
PM2-ის მთელი მდგომარეობა ინახება PM2_HOME-ში, რომელიც ნაგულისხმევად არის ~/.pm2 იმ მომხმარებლისთვის, ვინც გაუშვა. ამ საქაღალდეში დევს ლოგები (~/.pm2/logs), PID ფაილები, daemon-ის საკუთარი ლოგი (~/.pm2/pm2.log) და შენახული პროცესების სია (~/.pm2/dump.pm2). მნიშვნელოვანი შედეგი: daemon თითო მომხმარებელზეა. თუ აპლიკაცია deploy მომხმარებლით გაუშვი და მერე sudo pm2 ls აკრიფე, root-ის daemon-ს ეკითხები, რომელსაც ამ აპლიკაციის შესახებ არაფერი სმენია, და ცარიელ ცხრილს მიიღებ. აირჩიე ერთი მომხმარებელი, ჩვეულებრივ უპრივილეგიო, რომელიც აპლიკაციის საქაღალდის მფლობელია, და არასდროს აურიო.
დაყენება ერთი გლობალური პაკეტია:
$ npm install -g pm2$ pm2 --versionPM2-ის ბრძანებები და კონფიგურაციის გასაღებები წლებია სტაბილურია, მაგრამ ნაგულისხმევი მნიშვნელობები major ვერსიებს შორის ზოგჯერ იცვლება, ამიტომ თუ ამ გზამკვლევის რომელიმე რიცხვი შენთვის მნიშვნელოვანია, შეადარე pm2 --version-ს და შენი ვერსიის ოფიციალურ დოკუმენტაციას.
აპლიკაციის გაშვება: pm2 start, სახელები და interpreter-ები#
მინიმალური ფორმა იღებს სკრიპტს და სახელს. სახელი ყოველთვის მიუთითე; ნაგულისხმევი ფაილის სახელია, ოთხი აპლიკაცია კი, რომელსაც ოთხივეს index ჰქვია, სამართავად უსიამოვნოა.
$ pm2 start dist/server.js --name api$ pm2 start dist/server.js --name api -- --port 3000 # args after -- go to your app$ pm2 start npm --name web -- start # runs "npm start"$ pm2 lspm2 ls (ასევე pm2 list ან pm2 status) თითო პროცესზე თითო სტრიქონს ბეჭდავს: id, სახელი, რეჟიმი (fork ან cluster), restart-ების მთვლელი, სტატუსი, CPU და მეხსიერება. restart-ების მთვლელი სწორედ ის სვეტია, რომელსაც უნდა უყურო. რიცხვი, რომელიც იზრდება მაშინ, როცა deploy-ს არ აკეთებ, ნიშნავს, რომ აპლიკაცია ჩერდება და PM2 მას ჩუმად თავიდან ჩართავს.
npm start-ით გაშვება მუშაობს, მაგრამ PM2-სა და შენს აპლიკაციას შორის npm-ს აყენებს: დამატებული პროცესი, რომელიც მეხსიერებას იყენებს, და დამატებული რგოლი signal-ების გადასაცემად გამორთვისას. როცა შეგიძლია, უმჯობესია PM2 რეალურ entry ფაილზე მიუთითო.
PM2 მხოლოდ JavaScript-ით არ შემოიფარგლება. interpreter-ს ფაილის გაფართოებით ირჩევს - .py იღებს python-ს, .sh იღებს bash-ს, .rb იღებს ruby-ს, .php იღებს php-ს - და შეგიძლია პირდაპირ დააყენო --interpreter-ით. კომპილირებული binary-სთვის ან ყველაფრისთვის, რაც თავად არის გამშვები ფაილი, interpreter არის none:
$ pm2 start worker.py --name worker --interpreter python3$ pm2 start ./bin/server --name go-api --interpreter none$ pm2 start /srv/app/.venv/bin/gunicorn --name web --interpreter none \ -- app:app --bind 127.0.0.1:8000 --workers 2PM2-ში Python-თან დაკავშირებით ორი რამ უნდა იცოდე. ჯერ ერთი, ბევრი თანამედროვე დისტრიბუცია აწვდის python3-ს და არა python-ს, ამიტომ გაფართოებით არჩეული ნაგულისხმევი interpreter-ის-ვერ-პოვნის შეცდომას იძლევა; interpreter პირდაპირ მიუთითე და სასურველია virtualenv-ის საკუთარ binary-ზე, რომ სწორი პაკეტები იყოს path-ში. მეორე, Python standard output-ს buffer-ში აგროვებს, როცა ტერმინალზე არ არის მიერთებული, რაც PM2-ში ნიშნავს, რომ ლოგის სტრიქონები ბლოკებად ჩნდება ან საერთოდ არ ჩანს, სანამ პროცესი არ დასრულდება. გარემოში დააყენე PYTHONUNBUFFERED=1 ან გაუშვი -u-თი. თავად გარემოს აგებაზე წერია Python-ის requirements და virtualenv-ები, მის წინ მდგარ სერვერზე კი FastAPI-ს ან Flask-ის deploy.
ecosystem ფაილი#
ბრძანების ხაზის ფლაგები ვიღაცის shell-ის ისტორიაში ცხოვრობს. ecosystem ფაილი ცხოვრობს რეპოზიტორიაში, მისი გადახედვა შეიძლება და ყველა მანქანაზე ერთნაირად უშვებს. pm2 init simple ჩონჩხს წერს; რეალისტური ასე გამოიყურება:
module.exports = { apps: [ { name: "api", script: "dist/server.js", cwd: "/srv/api", instances: 2, exec_mode: "cluster", max_memory_restart: "400M", node_args: "--max-old-space-size=320", watch: false, time: true, kill_timeout: 10000, env: { NODE_ENV: "development", PORT: 3000 }, env_production: { NODE_ENV: "production", PORT: 3000 }, }, { name: "worker", script: "worker.py", cwd: "/srv/api", interpreter: "/srv/api/.venv/bin/python", exec_mode: "fork", env: { PYTHONUNBUFFERED: "1" }, }, ],};$ pm2 start ecosystem.config.js --env production$ pm2 reload ecosystem.config.js --env production # after a deploy$ pm2 start ecosystem.config.js --only worker # one app from the fileმნიშვნელოვანი გასაღებები და რას აკეთებენ ისინი სინამდვილეში:
| Key | რას აკეთებს |
|---|---|
name | სახელი, რომლითაც სხვა ყველა ბრძანება მიმართავს |
script | Entry ფაილი ან binary, cwd-ის მიმართ |
args | არგუმენტები, რომლებიც შენს აპლიკაციას გადაეცემა |
cwd | სამუშაო საქაღალდე; პირდაპირ მიუთითე |
interpreter | ნაგულისხმევად node; path ან none |
node_args | Node-ის საკუთარი ფლაგები, მაგალითად heap-ის ზომა |
instances | რამდენი პროცესი; max ნიშნავს თითო CPU-ზე ერთს |
exec_mode | fork (ნაგულისხმევი) ან cluster |
env / env_<name> | გარემო, ირჩევა --env <name>-ით |
| Key | რას აკეთებს |
|---|---|
max_memory_restart | პროცესის restart, როცა მეხსიერება ამ ზღვარს გადააჭარბებს, მაგ. 400M |
autorestart | ნაგულისხმევად true; ერთჯერადი სამუშაოებისთვის false |
max_restarts | არასტაბილური restart-ების რაოდენობა ზედიზედ, სანამ PM2 თავს დანებებს |
min_uptime | რამდენხანს უნდა იცოცხლოს პროცესმა, რომ გაშვებულად ჩაითვალოს |
restart_delay | ფიქსირებული პაუზა თითოეულ restart-მდე, ms-ში |
exp_backoff_restart_delay | მზარდი პაუზა restart-ებს შორის, ms-ში |
kill_timeout | ლოდინი stop signal-ის შემდეგ SIGKILL-მდე, ms-ში |
cron_restart | restart cron გამოსახულებით |
time | ლოგის თითოეულ სტრიქონს წინ timestamp ერთვის |
ამ გასაღებებიდან რამდენიმე ცხრილის უჯრაზე მეტ განმარტებას იმსახურებს.
`env` და `env_production`. უბრალო env ბლოკი ყოველთვის გამოიყენება; --env production მასზე env_production-ს ახვევს. ეს გამოსადეგია, მაგრამ საიდუმლოების საცავი არ არის - ecosystem ფაილი რეპოზიტორიაშია. პაროლები და გასაღებები შეინახე რეპოზიტორიის გარეთ მდებარე ფაილში, შემზღუდავი უფლებებით, და ჩატვირთე ecosystem ფაილის თავში (მაგალითად require("dotenv").config({ path: "/etc/api/api.env" })-ით), ან აპლიკაციას თავად ათქმევინე მისი წაკითხვა. რატომაა ეს განსხვავება მნიშვნელოვანი, განმარტებულია სტატიაში გარემოს ცვლადები და საიდუმლოებები.
`max_memory_restart`. PM2 მეხსიერებას ინტერვალით ამოწმებს და არა ყოველ გამოყოფაზე, ამიტომ ეს ნელი leak-ების დასალაგებელი ხელსაწყოა და არა მკაცრი ზღვარი. ის პროცესს ასევე უცებ, მოთხოვნის შუაში გადატვირთავს. დააყენე ის ჩვეულებრივ პიკურ მოხმარებაზე მაღლა და მის ქვემოთ მიუთითე V8 heap-ის ლიმიტი, რომ Node-მა შეცდომა წაკითხვად ფორმაში დაგიბრუნოს, სანამ PM2 ან kernel ჩაერევა - არითმეტიკა, იმის ჩათვლით, თუ რატომ აქვს ყველა cluster worker-ს საკუთარი heap, არის სტატიაში Node-ის მეხსიერების ლიმიტები.
`max_restarts` და `min_uptime`. პროცესი, რომელიც min_uptime-მდე გამოვა, არასტაბილურად ითვლება; ზედიზედ max_restarts არასტაბილური გაშვების შემდეგ PM2 ცდას წყვეტს და პროცესს errored ნიშნავს. დოკუმენტირებული ნაგულისხმევი მნიშვნელობებია 16 restart და 1000 ms. თუ შენს აპლიკაციას მარცხამდე რამდენიმე წამი სჭირდება - მაგალითად მონაცემთა ბაზასთან კავშირს ელოდება - ის არასდროს ჩაითვლება არასტაბილურად და PM2 მას უსასრულოდ გადატვირთავს. exp_backoff_restart_delay: 100 უკეთესი საშუალებაა: პაუზა ყოველ crash-ზე იზრდება და ნულდება, როცა აპლიკაცია გაჩერდება ფეხზე, ამიტომ მკვდარი მონაცემთა ბაზა უსასრულო ციკლში არ გადაიქცევა.
`kill_timeout`. გაჩერებისას PM2 აგზავნის SIGINT-ს და ამდენს ელოდება SIGKILL-მდე. ნაგულისხმევი 1600 ms-ია, რაც ნელ მოთხოვნაზე მოკლეა. თუ შენი აპლიკაცია გამორთვისას კავშირებს ასრულებს, გაზარდე ისე, რომ ყველაზე გრძელ მოთხოვნას დაფაროს, და დარწმუნდი, რომ handler უსმენს როგორც SIGINT-ს, ისე SIGTERM-ს. აპლიკაციის მხარეზე წერია Graceful shutdown და health check-ები.
Cluster რეჟიმი და instances#
exec_mode: "cluster" იყენებს Node-ის cluster მოდულს: PM2 აპლიკაციის რამდენიმე ასლს უშვებს და ისინი ერთ listening port-ს ინაწილებენ, შემომავალი კავშირები კი მათ შორის ნაწილდება. ეს ერთადერთი გზაა, რომ ერთმა Node აპლიკაციამ ერთზე მეტი CPU ბირთვი გამოიყენოს, ფორკინგის თავად წერის გარეშე, და სწორედ ეს აძლევს შესაძლებლობას zero-downtime reload-ებს.
სამი ფაქტი, რომ მოლოდინი სწორი გქონდეს:
- Cluster რეჟიმი მხოლოდ Node-ისთვისაა. Python, Go ან Bun პროცესს port-ის ამ გზით გაზიარება არ შეუძლია. მათთვის fork რეჟიმში
instances-ის 1-ზე მეტი მნიშვნელობა რამდენიმე ასლს უშვებს, რომლებიც ყველა ერთსა და იმავე port-ს ცდილობს, და პირველის გარდა ყველა მარცხდება. გამოიყენე აპლიკაციის სერვერის საკუთარი worker-ები - Gunicorn-ის--workers, Uvicorn-ის--workers- და PM2-ზე დატოვე ერთი instance. - `instances: "max"` მანქანის ლოგიკურ CPU-ებს ითვლის. VDS-ზე ეს შენი vCPU-ების რაოდენობაა, რაც კარგია.
0იგივეს ნიშნავს,-1კი ნიშნავს ერთის გამოკლებით ყველას, ერთ ბირთვს ტოვებს მონაცემთა ბაზისთვის ერთ მანქანაზე. - თითოეული instance აპლიკაციის სრული ასლია. მეხსიერება თითო instance-ზე მრავლდება, მეხსიერებაში შენახული მდგომარეობა არ ნაწილდება და ყველაფერი, რაც აპლიკაციის შიგნით დაგეგმილია, ერთხელ სრულდება თითო instance-ზე. კომპრომისები - sticky session-ები, ოთხჯერ გაშვებული სამუშაოები, worker-ების ზომა იმ ბირთვებზე, რაც რეალურად გაქვს - აღწერილია სტატიის PM2 და ჰოსტინგ პანელი cluster განყოფილებაში.
მომუშავე cluster-ის გაზრდა ან შემცირება restart-ს არ საჭიროებს:
$ pm2 scale api 4$ pm2 scale api +1ცვლილება გრძელდება ecosystem ფაილიდან შემდეგ გაშვებამდე, რომელშიც ჯერ კიდევ წერია instances: 2. თუ სერიოზულად გინდა, ფაილი შეცვალე.
Restart, reload, stop და delete#
ეს ოთხი PM2-ის ყველაზე ხშირად არეული ნაწილია და განსხვავება მხოლოდ გარეგნული არ არის.
| ბრძანება | რა ხდება |
|---|---|
pm2 restart api | ყველა instance-ს კლავს, შემდეგ თავიდან უშვებს |
pm2 reload api | Cluster რეჟიმში: instance-ებს სათითაოდ ცვლის |
pm2 stop api | აჩერებს; სიაში რჩება |
pm2 delete api | აჩერებს და სიიდან შლის |
restart-ს ხვრელი აქვს: წამით არაფერი უსმენს და ამ წამის მოთხოვნები ვერ სრულდება. cluster რეჟიმში reload იწყებს ახალ instance-ს, ელოდება მის მზადყოფნას, შემდეგ ძველს აჩერებს და იმეორებს, სანამ ყველა instance ახალი არ გახდება - ყოველთვის არის რაღაც, რაც კავშირებს იღებს. fork რეჟიმში გასაცვლელი არაფერია და reload უბრალოდ restart-ზე გადადის.
"მზადაა" ნაგულისხმევად ნიშნავს, რომ ახალმა instance-მა listening დაიწყო. თუ აპლიკაციას მომსახურებამდე cache-ის გახურება ან მონაცემთა ბაზის pool-ის გახსნა სჭირდება, უთხარი PM2-ს, რომ აშკარა signal დაელოდოს:
wait_ready: true,listen_timeout: 10000,server.listen(process.env.PORT, () => { if (process.send) process.send("ready");});თუ signal listen_timeout-ში არ მოვიდა, PM2 მაინც გაგრძელებს, ამიტომ გაფუჭებული რელიზი მაინც ცვლის მომუშავეს. Reload მოხერხებულობაა და არა health check; რა სხვა პირობებია საჭირო, რომ deploy მართლაც უხვრელო იყოს, წერია სტატიაში zero-downtime deploy პატარა სერვერზე.
კიდევ ერთი მახე. PM2 გარემოს იმახსოვრებს, როცა პროცესი პირველად იწყება, და მას თავიდან იყენებს. გარემოს ცვლადის შეცვლა და pm2 restart api ძველ მნიშვნელობას ტოვებს. დაამატე --update-env ან გადატვირთე ecosystem ფაილიდან:
$ pm2 reload ecosystem.config.js --env production --update-envდა stop და delete მნიშვნელოვანია შემდეგი განყოფილების გამო: გაჩერებული პროცესი ისევ სიაშია და გაჩერებულად შეინახება; წაშლილი პროცესი მხოლოდ მანამ არ არის, სანამ ძველ dump-ს არ აღადგენ, რომელშიც ის ჯერ კიდევ წერია.
ლოგები და pm2-logrotate#
ყველა პროცესს ორი ფაილი აქვს: ~/.pm2/logs/<name>-out.log standard output-ისთვის და ~/.pm2/logs/<name>-error.log standard error-ისთვის. cluster რეჟიმში თითოეული instance საკუთარ წყვილს წერს, სახელში id-ით, თუ merge_logs: true-ს არ დააყენებ.
$ pm2 logs # all apps, streaming$ pm2 logs api --lines 200 # last 200 lines, then stream$ pm2 logs api --err # error stream only$ pm2 flush api # empty this app's log filesecosystem ფაილში დააყენე time: true, თუ შენი logger თავად არ წერს timestamp-ებს. მათ გარეშე ლოგ-ფაილი მოვლენების სიაა, რომელმაც არ იცის, როდის მოხდა რომელიმე მათგანი.
ნაგულისხმევად ეს ფაილები უსასრულოდ იზრდება. მოლაპარაკე აპლიკაცია, რომელიც წუთში რამდენიმე ასეულ კილობაიტს წერს, პატარა დისკს კვირებში ავსებს, სავსე დისკი კი მონაცემთა ბაზასაც წაიყოლებს. გამოსავალი PM2-ის მოდულია:
$ pm2 install pm2-logrotate$ pm2 set pm2-logrotate:max_size 20M$ pm2 set pm2-logrotate:retain 14$ pm2 set pm2-logrotate:compress true$ pm2 conf pm2-logrotate| პარამეტრი | ნაგულისხმევი | რას აკეთებს |
|---|---|---|
max_size | 10M | ფაილს rotate უკეთებს, როცა ამ ზომას გადააჭარბებს |
retain | 30 | თითო ლოგზე შესანახი rotate-ული ფაილების რაოდენობა |
compress | false | rotate-ულ ფაილებს gzip-ით ათავსებს |
rotateInterval | 0 0 * * * | ასევე rotate ამ cron-ით, ნაგულისხმევად ყოველდღე |
მოდული daemon-ის შიგნით საკუთარ პროცესად მუშაობს და pm2 ls-ში ჩანს, რაც ნორმალურია. პარამეტრები თითო მომხმარებელზეა, PM2-ში ყველაფრის მსგავსად. თუ ლოგების სისტემურ journal-ში შენახვა გირჩევნია, systemd ამას მოდულის გარეშე აკეთებს; იმაზე, თუ რა უნდა იყოს ლოგებში საერთოდ, წერია ლოგები, რომლებიც ღირს შენახვად.
pm2 save და pm2 startup: რებუტის გადატანა#
PM2 თავისით არ იწყება ჩატვირთვისას. ორი ბრძანება ამას ასწორებს და ისინი სხვადასხვა საქმეს აკეთებენ.
pm2 startup აგენერირებს systemd unit-ს, რომელიც შენი მომხმარებლისთვის PM2 daemon-ს ჩატვირთვისას უშვებს. ჩვეულებრივი მომხმარებლით გაშვებისას ის არაფერს აყენებს; ბეჭდავს ბრძანებას, რომელიც დააყენებდა, რადგან unit-ის დაყენებას root სჭირდება:
$ pm2 startup[PM2] To setup the Startup Script, copy/paste the following command:sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u deploy --hp /home/deployდააკოპირე ეს სტრიქონი ზუსტად და გაუშვი. ის წერს და ააქტიურებს unit-ს სახელით pm2-deploy.service (მომხმარებლისთვის deploy). მასში path-ები იმაზეა დამოკიდებული, სად არის Node დაყენებული შენს მანქანაზე, ამიტომ არ გადაიტანო ისინი რომელიმე გაკვეთილიდან.
pm2 save პროცესების მიმდინარე სიას წერს ~/.pm2/dump.pm2-ში. ჩატვირთვისას unit უშვებს daemon-ს და ასრულებს pm2 resurrect-ს, რომელიც იმ ფაილში მყოფ ყველაფერს თავიდან უშვებს. მიმდევრობა ამგვარია:
- გაუშვი ყველაფერი, რაც უნდა მუშაობდეს:
pm2 start ecosystem.config.js --env production. - შეამოწმე:
pm2 ls, ყველაonline, restart-ების მთვლელები ნულზე. - შეინახე:
pm2 save. - ჩატვირთვის unit დააყენე ერთხელ:
pm2 startup, შემდეგ გაუშვი დაბეჭდილიsudoსტრიქონი. - გამოსცადე:
sudo reboot, ისევ შედი,pm2 ls.
მე-5 ნაბიჯს ხალხი გამოტოვებს, რებუტი კი არ არის ის მომენტი, როცა აღმოაჩენ, რომ სია არასდროს შენახულა.
თუ Node-ის path შეიცვლება - მაგალითად nvm-ით ახალი ვერსიის გამო - unit კვლავ ძველ binary-ზე მიუთითებს. გაიმეორე წყვილი: pm2 unstartup systemd, შემდეგ pm2 startup და მისი დაბეჭდილი ბრძანება, შემდეგ pm2 save. თავად PM2 პაკეტის npm install -g pm2-ით განახლების შემდეგ გაუშვი pm2 update, რომ მომუშავე daemon ახალი ვერსიით ჩანაცვლდეს და ძველზე არ დარჩეს.
unit-ს ისე შეამოწმებ, როგორც ნებისმიერს: systemctl status pm2-deploy. თუ სხვა შემთხვევაშიც systemd-ის გამოტანას კითხულობ, ღირს იცოდე, რომ აპლიკაცია შეგიძლია PM2-ის გარეშე საკუთარ unit-ად გაუშვა - ამას ფარავს systemd სერვისები შენი აპლიკაციებისთვის და ერთი პროცესისთვის ის უფრო მსუბუქი ვარიანტია.
მონიტორინგი: pm2 monit, describe და restart-ების მთვლელი#
$ pm2 monit # terminal dashboard: CPU, memory, logs per process$ pm2 describe api # full detail: paths, restarts, uptime, env$ pm2 reset api # zero the restart counterpm2 monit არის ტერმინალის ცოცხალი ხედი პროცესების სიით, თითო პროცესის CPU-თი და მეხსიერებით და ლოგების პანელით. ის გამოსადეგია deploy-ის ან დატვირთვის ტესტის დროს და უსარგებლოა დილის ოთხ საათზე, რადგან რაღაცას მხოლოდ მაშინ აჩვენებს, როცა ვინმე უყურებს. pm2 describe არის ბრძანება პოსტ-მორტემისთვის: ის ბეჭდავს სკრიპტის path-ს, interpreter-ს, ლოგ-ფაილების მდებარეობას, uptime-ს, restart-ების რაოდენობას და არასტაბილურ restart-ებს.
restart-ების მთვლელი შენი ყველაზე იაფი alert-ია. განულე ის მიზანმიმართული deploy-ის შემდეგ (pm2 reset api) და ნებისმიერი არანულოვანი რიცხვი ამის შემდეგ crash-ია, რომელიც შენ არ გამოგიწვევია. თუ მას არავინ უყურებს, პატარა cron სამუშაო, რომელიც pm2 jlist-ს უშვებს, პროცესების სიას JSON-ად ბეჭდავს, და ხმას იღებს, როცა restart_time ან status იცვლება, ათიოდე სტრიქონიანი სკრიპტია და crash-ციკლებს მომხმარებლებზე ბევრად ადრე იჭერს. PM2-ს ასევე აქვს ფასიანი hosted dashboard; ამ გზამკვლევში არაფერს ის არ სჭირდება.
ხშირი შეცდომები#
Watch რეჟიმი production-ში. watch: true აპლიკაციას აგდებს და თავიდან ჩართავს, როცა მისი საქაღალდის რომელიმე ფაილი იცვლება. production-ში ეს ნიშნავს, რომ პროექტის შიგნით ყოველი ლოგის ჩაწერა, ყოველი ატვირთვა, ყოველი cache ფაილი restart-ს იწვევს, restart კი ლოგის სტრიქონს წერს, რაც ახალს იწვევს. development-ის გარეთ დატოვე watch: false. თუ ლოკალურად იყენებ, დაამატე ignore_watch: ["node_modules", "logs", "uploads"].
ორი daemon. ერთი root-ით გაშვებული, ერთი შენი მომხმარებლით, თითოეულს აპლიკაციების ნახევარი აქვს. გაუშვი pm2 ls და sudo pm2 ls ერთხელ და დარწმუნდი, რომ მხოლოდ ერთში არის რამე. შემდეგ მეორეში წაშალე და pm2 kill გაუკეთე.
`pm2 save`-ის დავიწყება. ყველაფერი მუშაობს პირველ რებუტამდე. save გახადე შენი deploy სკრიპტის ნაწილი.
ორი ზედამხედველი. PM2 container-ში, რომლის პლატფორმაც მას უკვე თავიდან უშვებს, ან PM2, რომელიც შენ დაწერილი systemd unit-იდან გაუშვი, მაშინ როცა pm2 startup-მაც დააყენა unit. თითო პროცესზე აირჩიე ერთი ზედამხედველი.
`instances: "max"` მდგომარეობიანი კოდით. მეხსიერებაში შენახული session-ები, Map-ში აღრიცხული WebSocket-ები, აპლიკაციის შიგნით scheduler. ყველაფერი ირღვევა ან მრავლდება, როგორც კი მეორე instance გაჩნდება.
Python-ის ლოგები, რომლებიც არ ჩანს. buffer-ის გარეშე გამოტანა ნაგულისხმევად გამორთულია. PYTHONUNBUFFERED=1.
არგუმენტები არასწორ ადგილას. ბრძანებაში pm2 start server.js --name api -- --port 3000 ყველაფერი ---ის შემდეგ შენს აპლიკაციას გადაეცემა. Node-ის ფლაგები, როგორიცაა --max-old-space-size, node_args-ში ან --node-args-ში უნდა იყოს და არა ორმაგი ტირეს შემდეგ, თორემ ჩუმად იგნორირდება.
`max_memory_restart`-ის გამოსწორებად მიჩნევა. ის leak-ს მალავს იმით, რომ პროცესს შენთვის უცნობი გრაფიკით გადატვირთავს. იპოვე leak.
FAQ#
PM2 უფასოა?
დიახ. პროცესების მენეჯერი open source-ია და ამ გზამკვლევში ყველაფერი მხოლოდ უფასო CLI-სა და უფასო pm2-logrotate მოდულს იყენებს. ფასიანი ნაწილი არჩევითი hosted მონიტორინგის dashboard-ია, რომელიც PM2-ის გასაშვებად არ გჭირდება.
PM2 გამოვიყენო თუ systemd?
სერვერზე ერთი პროცესისთვის systemd უკვე დაყენებულია და საქმეს დამატებითი daemon-ის გარეშე აკეთებს. PM2 ადგილს იმსახურებს, როცა გინდა Node cluster რეჟიმი rolling reload-ებით, ან რამდენიმე პატარა აპლიკაცია ერთი ბრძანებით მართო. ორივე კარგია; ერთი აპლიკაციისთვის ორივეს გაშვება არა.
შეუძლია PM2-ს Python-ის, Go-ს ან shell სკრიპტის გაშვება?
დიახ. interpreter დააყენე Python binary-ზე (სასურველია virtualenv-ის შიგნით), კომპილირებული binary-სთვის none-ზე, ან .sh ფაილებს დაუტოვე ნაგულისხმევი bash. Cluster რეჟიმი და pm2 reload შეფერხების გარეშე მხოლოდ Node-ისთვის მუშაობს, ამიტომ სხვა runtime-ებს ერთი instance და საკუთარი worker მოდელი აქვთ.
სად ინახავს PM2 ჩემს ლოგებს?
იმ მომხმარებლის ~/.pm2/logs-ში, ვინც აპლიკაცია გაუშვა, როგორც <name>-out.log და <name>-error.log. pm2 describe <name> ზუსტ path-ებს ბეჭდავს. დააყენე pm2-logrotate, სანამ ისინი დისკის პრობლემად გადაიქცევა.
რატომ არ დაბრუნდა ჩემი აპლიკაცია რებუტის შემდეგ?
ან pm2 startup არასდროს დაყენებულა, ან pm2 save არ გაშვებულა აპლიკაციის გაშვების შემდეგ, ან ის სხვა მომხმარებლის ქვეშ შეინახა. შეამოწმე systemctl status pm2-<user>, შემდეგ pm2 ls იმ მომხმარებლით, შემდეგ გაუშვი, შეინახე და ისევ გადატვირთე.
გამოვიყენო PM2 ჰოსტინგ პანელზე?
ჩვეულებრივ არა. პანელი უკვე თავიდან უშვებს პროცესს, ინახავს მის გამოტანას და crash-ებს აღრიცხავს, PM2 კი შუაში ამ crash-ებს მალავს. აპლიკაცია პირდაპირ foreground-ში გაუშვი.


