Gunicorn: يأكل Gunicorn المزيد من الذاكرة في Django

تم إنشاؤها على ١ مايو ٢٠١٦  ·  31تعليقات  ·  مصدر: benoitc/gunicorn

في مشروع django ، أستخدم Gunicorn كخادم تطبيق. يعمل التطبيق في الأيام القليلة الماضية بسلاسة لساعات قليلة بعد تعليق هذا التطبيق. يستخدم Gunicorn المزيد من الذاكرة ، نظرًا لاستخدام وحدة المعالجة المركزية هذه التي تجاوزت 95٪ وتم تعليق التطبيق.

هنا هو تكوين Gunicorn الخاص بي أثناء بدء التطبيق.
قاعدة جونيكورن. wsgi: التطبيق
- ربط = 0.0.0.0: 8000
--pid = السجلات / المشروع / gunicorn.log
--access-logfile = logs / project / access.log
- عمال = 7
- فئة العامل = gevent
- Error-logfile = logs / project / error8.log
- المهلة = 4500
- التحميل المسبق

الرجاء مساعدتي في هذه القضية.

Feedback Requested

التعليق الأكثر فائدة

فقط قم بتعيين max-requests وقم بتنظيف عملية العامل بعد فترة ، وهذا يجب أن يغطي أي تسرب للذاكرة لديك

ال 31 كومينتر

ربما تحتاج إلى تقليل العمال ، جرب هذه الصيغة 2 * وحدات المعالجة المركزية + 1 ، ربما يكون الخادم الخاص بك عبارة عن جهاز وحدة معالجة مركزية واحدة ، لذا قم بتعيينها على 3 آمن.

أي سجل للمشاركة؟ كيف تتكاثر؟ لا تستخدم gunicorn في حد ذاتها الكثير من ذاكرة الوصول العشوائي أو وحدة المعالجة المركزية. أيضًا لماذا تقوم بتحميل التطبيق مسبقًا؟

@ syaiful6 حاليا يتم معالجة 4 وحدات المعالجة المركزية على الخادم. وفقا لكم لا بد لي من تعيين - عمال = 4 أليس كذلك؟

benoitc في الوقت الذي تم فيه تسجيل دخول 12 إلى 15 مستخدمًا في النظام وقاموا ببعض النشاط ، استحوذ برنامج Gunicorn على المزيد من الذاكرة بسبب استخدام وحدة المعالجة المركزية أكثر وتم تعليق النظام.

هل هناك وات ري إعادة إنتاج المشكلة؟ لا يستخدم Gunicorn في حد ذاته الكثير من وحدة المعالجة المركزية ، فمن المرجح أن يكون هناك شيء ما في تطبيقك هو الذي يتسبب في حدوث المشكلة.

صدم.

فقط قم بتعيين max-requests وقم بتنظيف عملية العامل بعد فترة ، وهذا يجب أن يغطي أي تسرب للذاكرة لديك

لا يوجد جواب منذ أن قام المصدر بإغلاق الإصدار في ذلك الوقت.

hardiksanchawat ، يجب ألا تستخدم التحميل المسبق حتى تحتاج حقًا إلى استخدام التحميل المسبق ، والذي قد يكون أحد الأسباب. كما تم الإعجاب بواسطة @ diwu1989 ، يمكنك استخدام إعداد الطلبات القصوى لمنع أي تسرب للذاكرة.

لقد استضفنا تطبيق الويب الخاص بنا (Angular CLI: 1.7.3 ، Node: 9.5.0 ، Django 2.0.3) على طبقة AWS المجانية من Ubuntu (14.04.5 LTS) VM. نحن نستخدم ELB (Elastic Load Balancers) مع Nginx-1.4.6 و Gunicorn-19.7.1

عندما نحاول استخدام الوصول إلى تطبيقنا من متصفح ، فإن استخدام ذاكرة Gunicorn فجأة يزداد بشكل كبير:

طبيعي:
PID USER PR NI VIRT RES SHR S٪ CPU٪ MEM TIME + COMMAND
16248 أوبونتو 20 0313.1 م 94.6 م 9.3 م 15.6 9.5 0: 00.71 جونيكورن

أثناء استخدام التطبيق:
PID USER PR NI VIRT RES SHR S٪ CPU٪ MEM TIME + COMMAND
16235 أوبونتو 20 0684.9 م 315.8 م 11.1 م R 61.4 31.8 0: 04.51 جونيكورن
يوجد أدناه تكوين gunicorn الخاص بنا (/etc/init/gunicorn.conf):

وصف "معالجة خادم تطبيق Gunicorn myproject"

تبدأ في مستوى التشغيل [2345]
وقف على مستوى التشغيل [! 2345]

إعادة
سيتويد أوبونتو
setgid بيانات شبكة الاتصالات العالمية
chdir / الصفحة الرئيسية / ubuntu / المشروع /

exec ./env/bin/gunicorn --max- طلبات 1 - العمال 3 - ربط unix: /home/ubuntu/project/django-ng.sock config. wsgi: التطبيق

لقد قمنا بالفعل بتعيين الحد الأقصى للطلبات على 1 والعاملين كـ 3. هل يمكن لشخص ما أن يخبرني بما يحدث؟

satendrapratap لست متأكدًا من وجود خطأ. قد تضطر إلى إنشاء ملف تعريف لتطبيقك ، ولكن من المحتمل أيضًا أن تكون هذه عملية Python على جهاز بسعة 1 غيغابايت ولديك ثلاثة عمال. قد يكون من الطبيعي. من الصعب القول.

نعم. ما هو ملف التعريف الذي يجب أن نستخدمه للملف الشخصي؟

نفس الكود يعمل بشكل جيد مع "python3 manager.py runserver" ولا نرى أي زيادة في الذاكرة المستخدمة خلال فترة زمنية أو دفعة واحدة. على الأرجح لا توجد تسربات للذاكرة وإلا لكان هناك زيادة في استهلاك الذاكرة في هذه الحالة أيضًا.

كيف يمكن أن يساعد التنميط في الواقع؟ هل تقول إننا بحاجة إلى تحسين الكود لجعله يستهلك ذاكرة أقل؟

ولكن من الممكن أيضًا أن تكون هذه عملية Python على جهاز بسعة 1 جيجابايت ولديك ثلاثة عمال.

ما مقدار الذاكرة التي تستغرقها عملية Python في وقت التشغيل؟ في حالتنا ، يأخذ gunicorn ما يصل إلى 500-600 ميجابايت مع طلب واحد كحد أقصى ، وإذا زدناه إلى 2 ، فإن الوصول إلى التطبيق يؤدي أحيانًا إلى حدوث خطأ في الذاكرة.

سيساعدك التنميط satendrapratap إذا كان هناك مكان يمكنك من خلاله تقليل استخدام ذاكرة التطبيق الخاص بك.

من المفيد أيضًا معرفة ما إذا كان Gunicorn يستخدم ذاكرة أكثر مما ينبغي ، أو إذا كان هناك تسرب مع Gunicorn لا يحدث مع خادم التشغيل.

لقد أجريت للتو بعض الاختبارات السريعة للحد الأدنى من التطبيقات حيث يبدو أنها صغيرة مثل 20-30 ميغا بايت للعامل ، ولكن بالنسبة للتطبيق الحقيقي ، فإنه يعتمد كثيرًا على التطبيق والإطار.

أنا مهتم بأي مقارنة بين Gunicorn و runserver يمكنك تقديمها.

في حالتنا ، يأخذ gunicorn ما يصل إلى 500-600 ميجابايت مع طلب واحد كحد أقصى ، وإذا زدناه إلى 2 ، فإن الوصول إلى التطبيق يؤدي أحيانًا إلى حدوث خطأ في الذاكرة.

لاحظ أن Python لديها مُخصص الذاكرة الخاص بها ولا تعيد كتل الذاكرة المخصصة مسبقًا إلى نظام التشغيل ، لذا فإن زيادة استخدام الذاكرة لا تعني دائمًا وجود تسرب للذاكرة.

هل ترى نفس استخدام الذاكرة على جميع عناوين URL أم مجرد عنوان URL محدد (/ products / all على سبيل المثال)؟

أود أيضًا أن أقترح نشر تطبيق Django بسيط (نفس قاعدة البيانات وتكوين Gunicorn ؛ نموذج واحد واثنين من طرق العرض) لمعرفة ما إذا كان Gunicorn هو سبب استخدام الذاكرة العالية.

من المفيد أيضًا معرفة ما إذا كان Gunicorn يستخدم ذاكرة أكثر مما ينبغي ، أو إذا كان هناك تسرب مع Gunicorn لا يحدث مع خادم التشغيل.

سنحاول بالتأكيد التنميط. هل يمكنك اقتراح ملف تعريف لاستخدامه في مثل هذا السيناريو؟

لقد أجريت للتو بعض الاختبارات السريعة للحد الأدنى من التطبيقات ويبدو أنها صغيرة مثل 20-30 ميغا بايت للعامل ،

لدينا 3 عمال ، وبينما لا يتم استخدام التطبيق ، فإنه يستهلك حوالي 96 ميجابايت:

ubuntu @: ~ $ sudo python3 ps_mem.py
خاص + مشترك = ذاكرة الوصول العشوائي المستخدمة البرنامج

136.0 كيلو بايت + 9.0 كيلو بايت = 145.0 كيلو بايت حمض
180.0 كيلوبايت + 24.0 كيلوبايت = 204.0 كيلوبايت atd
220.0 KiB + 38.0 KiB = 258.0 KiB مغرور جسر udev
240.0 كيلوبايت + 34.0 كيلوبايت = 274.0 كيلوبايت كرون
236.0 KiB + 39.0 KiB = 275.0 KiB جسر مقبس مبتدئ
288.0 KiB + 39.5 KiB = 327.5 KiB جسر ملفات مبتدئ
604.0 كيلوبايت + 50.0 كيلوبايت = 654.0 كيلوبايت systemd-udevd
544.0 KiB + 147.0 KiB = 691.0 KiB systemd-logind
684.0 KiB + 58.0 KiB = 742.0 KiB dbus-daemon
940.0 KiB + 56.0 KiB = 996.0 KiB rsyslogd
1.0 ميجابايت + 131.5 كيلوبايت = 1.2 ميجابايت غيتي (7)
896.0 كيلو بايت + 400.5 كيلو بايت = 1.3 ميجا بايت sudo
1.4 MiB + 73.0 KiB = 1.5 MiB init
2.5 ميجا بايت + 39.5 كيلوبايت = 2.6 ميجا بايت لكل عميل
2.3 ميجابايت + 1.5 ميجابايت = 3.8 ميجابايت nginx (5)
2.5 ميجا بايت + 1.8 ميجا بايت = 4.3 ميجا بايت sshd (3)
6.4 ميجا بايت + 176.5 كيبي بايت = 6.6 ميجا بايت باش
50.1 ميجا بايت + 83.0 كيلو بايت = 50.2 ميجا بايت mysqld

87.8 MiB + 7.8 MiB = 95.5 MiB gunicorn (4)

171.4 ميغا بايت

ubuntu @: ~ $
ps_mem.py: https://raw.githubusercontent.com/pixelb/ps_mem/master/ps_mem.py

تمتلك Python أداة تخصيص الذاكرة الخاصة بها ولا تعيد كتل الذاكرة المخصصة مسبقًا إلى نظام التشغيل ، لذا فإن زيادة استخدام الذاكرة لا تعني دائمًا وجود تسرب للذاكرة.

حسنًا ، لكن هل هناك أي طريقة في لعبة بيثون يمكننا أن نطلب فيها تحرير الذاكرة غير المستخدمة؟

هل ترى نفس استخدام الذاكرة على جميع عناوين URL أم مجرد عنوان URL محدد (/ products / all على سبيل المثال)؟

يبدو أن استخدام الذاكرة مشابهًا (وليس فرقًا كبيرًا) لعناوين url المختلفة:
URL للحصول على بعض البيانات الصغيرة:
19181 أوبونتو 20 0553.8 م 281.4 م 10.0 م ص 32.6 28.4 0: 01.21 جونيكورن
19191 أوبونتو 20 0 97.8 م 34.1 م 2.9 م 7.7 3.4 0: 00.23 جونيكورن

URL للحصول على مزيد من البيانات:
19196 أوبونتو 20 0 97.8 م 34.1 م 2.9 م جنوبي 7.3 3.4 0: 00.22 جونيكورن
19191 أوبونتو 20 0564.0 م 296.1 م 10.0 م 56.2 29.8 0: 01.92 جونيكورن
19198 أوبونتو 20 0 97.8 م 34.1 م 2.9 م 7.7 3.4 0: 00.23 جونيكورن

URL يجعل كود الخادم يقوم ببعض المعالجة ، هيكلة البيانات ثم إرسالها مرة أخرى:
19208 أوبونتو 20 0 97.8 م 34.1 م 2.9 م 7.7 3.4 0: 00.23 جونيكورن
19196 أوبونتو 20 0686.4 م 319.3 م 11.2 م 79.6 32.2 0: 05.20 جونيكورن
19206 أوبونتو 20 0313.1 م 94.8 م 9.4 م 16.6 9.6 0: 00.74 جونيكورن

أود أيضًا أن أقترح نشر تطبيق Django بسيط (نفس قاعدة البيانات وتكوين Gunicorn ؛ نموذج واحد واثنين من طرق العرض) لمعرفة ما إذا كان Gunicorn هو سبب استخدام الذاكرة العالية.

سأحاول ذلك ، لكن من الواضح أكثر أو أقل من النقطة السابقة (مقارنة استهلاك الذاكرة لزيارات url المختلفة) أن استهلاكها لذاكرة مماثلة حتى بالنسبة لخدمة الراحة البسيطة ضرب

كيف يتأثر استهلاك الذاكرة بزيادة العاملين وطلبات الحد الأقصى؟ أطلب هذا لأن الحد الأقصى للطلب = 1 لن يتم استخدامه في حالة الإنتاج وسيتعين علينا ضبطه والعاملين أيضًا.

إذن ، مقدار الذاكرة المطلوبة عادةً للتطبيق الصغير المنشور مع Gunicorn و Nginx (20-30 خدمة أخرى ، فقط 4-5 منها تقوم ببعض المعالجة على الخادم بينما الباقي يأخذ البيانات من قاعدة البيانات ويرسلها مرة أخرى إلى المستخدم ، ضرب ما لا يقل عن 10000 مستخدم في وقت واحد)؟

حسنًا ، لكن هل هناك أي طريقة في لعبة بيثون يمكننا أن نطلب فيها تحرير الذاكرة غير المستخدمة؟

ستحتاج إلى كتابة مخصص ذاكرة مخصصة باستخدام Python C API ولكن هذه مهمة غير تافهة ولا أعتقد أنها ضرورية.

URL للحصول على بعض البيانات الصغيرة:
19181 أوبونتو 20 0553.8 م 281.4 م 10.0 م ص 32.6 28.4 0: 01.21 جونيكورن

الجدول صعب قليلا للقراءة. أظن أن العمود الأول هو PID ، والثاني هو مالك العملية ، ولكن يصعب تخمين الباقي. هل يمكنك إضافة أسماء الأعمدة أيضًا؟

على أي حال ، فإن زيادة استخدام الذاكرة من ~ 90 ميجابايت إلى ~ 500 ميجابايت تعد أكثر من اللازم. أعتقد أننا سنحصل بالفعل على الكثير من التقارير المماثلة إذا قدمنا ​​مثل هذا التسرب الضخم للذاكرة الآن :) (تم إصدار Gunicorn 19.7.1 منذ أكثر من عام.)

PID USER PR NI VIRT RES SHR S٪ CPU٪ MEM TIME + COMMAND

قد لا يكون مقيم 300MiB غير متوقع ، لكنني لا أعرف. إنها Python و ORM ، لكنني لست مستخدمًا كثيفًا لـ Django ولم أقم بتوصيف هذه الأشياء من قبل ، بنفسي.

بالنسبة إلى 10000 مستخدم ، بناءً على معدل الطلب ، قد تحتاج إلى أكثر من t2.micro. ومع ذلك ، سنبذل قصارى جهدنا لمساعدتك في استكشاف الأخطاء وإصلاحها. إن وجود nginx في المقدمة لطلبات الانتظار إلى Gunicorn سيساعد بالتأكيد.

ما مقدار الذاكرة التي يشغلها نفس التطبيق عند طلب عناوين URL على خادم runserver؟

نحن نستخدم t2.micro الذي يحتوي على 1 غيغابايت من ذاكرة الوصول العشوائي. إعدادنا كما يلي:

CLIENT           |      AWS SERVER
                 |
                 |                     angular app, static files
                 |                    /
Web App<-------->| <----->ELB<--->nginx
                 |                    \
                 |                     gunicorn <-----> Backend Python Code
                 |

تهيئة nginx:

server {
listen 80 default_server;

server_name myapp.com www.myapp.com;

charset     utf-8;

# max upload size
# client_max_body_size 75M;
client_max_body_size 0;

# send all non-media requests to the Django server.
location ~ ^/(myapp|admin) {
    proxy_pass http://unix:/home/ubuntu/project/django-ng.sock; # for a file socket
    include proxy_params;
}

location /static  {
    alias /home/ubuntu/project/static/;
}

location / {
    root /home/ubuntu/deploy/angularapp;
    index index.html index.htm;

    try_files $uri $uri/ /index.html;
}
}

التكوين gunicorn:

description "Gunicorn application server handling myproject"

start on runlevel [2345]
stop on runlevel [!2345]

respawn
setuid ubuntu
setgid www-data
chdir /home/ubuntu/project/

exec ./env/bin/gunicorn --max-requests 1 --workers 3 --bind unix:/home/ubuntu/project/django-ng.sock config.wsgi:application

ما مقدار الذاكرة التي يشغلها نفس التطبيق عند طلب عناوين URL على خادم runserver؟

باستخدام "python3 manager.py runserver" على الجهاز المحلي:

PID USER PR NI VIRT RES SHR S٪ CPU٪ MEM TIME + COMMAND
بدء التطبيق:
1158 براتاب 20 0900.4 م 260.8 م 24.5 م جنوب 0.0 3.2 1: 52.17 بيثون 3
1156 براتاب 20 0 80.9 م 30.8 م 30.2 م جنوب 0.0 0.4 0: 00.50 بيثون 3
1158 براتاب 20 0900.4 م 260.8 م 24.5 م جنوب 0.0 3.2 1: 52.17 بيثون 3
1158 براتاب 20 0900.4 م 263.7 م 24.9 م جنوب 37.0 3.3 1: 53.28 بيثون 3

أول دخول إلى تطبيق الويب للقيام ببعض المعالجة:
1158 براتاب 20913.4 م 294.0 م 25.0 م 106.6 3.6 1: 56.48 بيثون 3
1158 براتاب 20 0935.9 م 345.1 م 25.0 م جنوب 109.6 4.3 1: 59.77 بيثون 3
1158 براتاب 20 0938.9 م 349.2 م 25.0 م جنوب 26.6 4.3 2: 00.57 بيثون 3
1158 براتاب 20 0938.9 م 349.2 م 25.0 م جنوب 14.3 4.3 2: 01.00 بيثون 3
1158 براتاب 20 0938.9 م 349.2 م 25.0 م جنوب 10.0 4.3 2: 04.00 بيثون 3
1158 براتاب 20 0938.9 م 349.2 م 25.0 م جنوب 8.0 4.3 2: 04.24 بيثون 3
1156 براتاب 20 0 80.9 م 30.8 م 30.2 م جنوب 0.0 0.4 0: 00.50 بيثون 3
1158 براتاب 20 0938.9 م 349.2 م 25.0 م جنوب 10.3 4.3 2: 04.55 بيثون 3
1156 براتاب 20 0 80.9 م 30.8 م 30.2 م جنوب 0.0 0.4 0: 00.50 بيثون 3
1158 براتاب 20 0938.9 م 349.2 م 25.0 م جنوب 11.0 4.3 2: 04.88 بيثون 3
1158 براتاب 20 0938.9 م 349.2 م 25.0 م جنوب 7.7 4.3 2: 05.11 بيثون 3

الوصول الثاني إلى تطبيق الويب للقيام ببعض المعالجة:
1158 pratap 20940.4m 351.0m 25.0m R 8.3 4.3 2: 14.01 python3
1158 براتاب 20940.4 م 351.0 م 25.0 م جنوب 6.0 4.3 2: 14.19 بيثون 3
1158 براتاب 20940.4 م 351.0 م 25.0 م جنوب 10.0 4.3 2: 14.49 بيثون 3
1158 براتاب 20940.4 م 351.0 م 25.0 م جنوب 9.7 4.3 2: 14.78 بيثون 3
1156 براتاب 20 0 80.9 م 30.8 م 30.2 م جنوب 0.0 0.4 0: 00.50 بيثون 3
1158 براتاب 20940.4 م 351.0 م 25.0 م جنوب 5.7 4.3 2: 14.95 بيثون 3
1156 براتاب 20 0 80.9 م 30.8 م 30.2 م جنوب 0.0 0.4 0: 00.50 بيثون 3
1158 براتاب 20940.4 م 351.0 م 25.0 م S 9.0 4.3 2: 15.22 بيثون 3
1158 براتاب 20940.4 م 351.0 م 25.0 م جنوب 9.7 4.3 2: 15.51 بيثون 3
1158 براتاب 20940.4 م 351.0 م 25.0 م S 9.3 4.3 2: 15.79 بيثون 3

ثالث الوصول إلى تطبيق الويب للقيام ببعض المعالجة:
1158 براتاب 20 0942.4 م 353.7 م 25.0 م جنوب 47.3 4.4 2: 17.21 بيثون 3
1158 براتاب 20 0942.4 م 353.7 م 25.0 م S 9.3 4.4 2: 17.49 بيثون 3
1158 براتاب 20 0942.4 م 353.7 م 25.0 م جنوب 9.7 4.4 2: 17.78 بيثون 3
1158 براتاب 20 0942.4 م 353.7 م 25.0 م R 8.3 4.4 2: 18.03 بيثون 3
1158 براتاب 20 0942.4 م 353.7 م 25.0 م جنوب 7.3 4.4 2: 18.25 بيثون 3
1158 براتاب 20 0942.4 م 353.7 م 25.0 م 11.0 4.4 2: 19.93 بيثون 3
1158 براتاب 20 0942.4 م 355.1 م 25.0 م جنوب 26.3 4.4 2: 20.72 بيثون 3
1158 براتاب 20 0943.7 م 355.4 م 25.0 م جنوب 62.3 4.4 2: 22.59 بيثون 3

بمقارنة هذه القياسات بالتعليق السابق مع إحصائيات ذاكرة Gunicorn ، يبدو أنه لا توجد مشكلة مع Gunicorn هنا. هل أنا مخطئ في القراءة؟

tilgovi أنا أعمل حاليًا على مشكلة مماثلة وأردت إضافة نتائجي في حالة ما إذا كان ذلك مفيدًا.
لدي ذاكرة وصول عشوائي 2 جيجا بايت Ubuntu16 VM وتشغيل Python3 ، تطبيق الويب Flask. نظرًا لاستخدام بعض مكتبات البرمجة اللغوية العصبية ، فإن استخدام الذاكرة الأولية مرتفع.
يمكنك الاطلاع على الرسم البياني لاستخدام الذاكرة لآخر 30 يومًا أدناه. في الواقع ، بدأ منذ٪ 33 ، 3 أشهر وما زال مستمراً في الزيادة (بالأمس قمت بالترقية إلى الإصدار الأخير من gunicorn وغيره ، وهذا هو سبب انخفاض الرسم البياني وأعلى.)
عدد العمال 2.
لا أستطيع أن أقول إن سبب ذلك هو يونيكورن بالضبط ولكن عندما أنشر كل بضعة أيام وأعيد تشغيل الخدمة وأعيد تشغيل جهاز VM من وقت لآخر ، أتوقع أن يبدأ كل شيء من حوالي 33٪ مرة أخرى (إذا كان ذلك بسبب الكود الخاص بي أو أي حزمة). لكنها تواصل حيث تركت.

لذلك أفترض أن شيئًا ما يقوم بتخزين الأشياء مؤقتًا ولا تتركها مع إعادة التشغيل / إعادة التشغيل.

هل هناك أي طريقة يمكنني من خلالها مراقبة سبب زيادة الذاكرة تحت gunicorn حيث يمكنني رؤية٪ 60 فقط من الذاكرة يتم استهلاكها بواسطة gunicorn.

image

tilgovi ، راجعنا التفاصيل ويبدو أنه لا يمكن مقارنة نتائج gunicorn و runserver لاستهلاك الذاكرة لأننا قمنا بتكوين gunicorn للطلبات القصوى 1 والتي ستعيد تشغيل العامل بعد كل طلب لذلك لن نتمكن حقًا من معرفة ما إذا كانت الذاكرة زيادة أم لا لمكالمات خدمة الراحة اللاحقة.

لذا قم بتعيين الحد الأقصى للطلب على 100 ، والعاملين 3 وحاولوا تجربتنا مرة أخرى. في حالة الخمول استخدام ذاكرة gunicorn جيد:
PID USER PR NI VIRT RES SHR S٪ CPU٪ MEM TIME + COMMAND
25678 أوبونتو 20 0 644632 34868 10824 جنوب 0.0 26.6 0: 02.94 جونيكورن
25680 أوبونتو 20 0100136 34876 2992 جنوب 0.0 3.4 0: 00.23 جونيكورن
25677 أوبونتو 20 0100132 34868 2992 جنوبًا 0.0 3.4 0: 00.24 جونيكورن
25673 أوبونتو 20 064836 18368 3948 جنوب 0.0 1.8 0: 00.17 جونيكورن

لكننا نستخدم تطبيق الويب ، ثم يستهلك العامل مزيدًا من الذاكرة (ربما لهيكل بيانات Python وما إلى ذلك) وبعد تقديم الطلب لا يعود مرة أخرى (ربما لأن Python لديها مخصص ذاكرة خاص بها ولا تعيد كتل الذاكرة المخصصة مسبقًا إلى نظام التشغيل ولكن قد تستخدم هذه الذاكرة لمزيد من طلبات خدمة الراحة) لاستهلاك الذاكرة العادي البالغ 34868:

PID USER PR NI VIRT RES SHR S٪ CPU٪ MEM TIME + COMMAND
25678 أوبونتو 20 0 644632 270432 10824 S 0.0 26.6 0: 02.94 جونيكورن
25680 أوبونتو 20 0100136 34876 2992 جنوب 0.0 3.4 0: 00.23 جونيكورن
25677 أوبونتو 20 0100132 34868 2992 جنوبًا 0.0 3.4 0: 00.24 جونيكورن
25673 أوبونتو 20 064836 18368 3948 جنوب 0.0 1.8 0: 00.17 جونيكورن

ولكن عند البدء في استخدام تطبيق الويب ، يتم اختيار العمال بشكل عشوائي وعندما يتم اختيار العامل الثالث لخدمة الطلب (بعد أن يكون العاملان الآخران قد خدموا بالفعل ذاكرة 270428 كيلو بايت لكل منهما) ، ثم يحاول نظامنا تخصيص ذاكرة غير متوفرة ما يكفي وتحطم العامل وإعادة تشغيله. لذلك يبدو أنه لا يمكننا تصحيح استهلاك الذاكرة بشكل صحيح إلا إذا كانت لدينا ذاكرة كافية متاحة لنا التطبيق بعدد كافٍ من المرات دون تعطل العمال وإعادة التشغيل. عندها فقط يمكننا تحديد ما إذا كانت الذاكرة المستخدمة تزداد على مدار فترة زمنية (تسرب) أو تعود إلى الحالة الأولى حيث يستهلك العامل الذاكرة لنفسه ولتخصيص الثعبان (وهو وضع طبيعي).

تعطل العامل دون استكمال الطلب بسبب قلة الذاكرة المتوفرة:
PID USER PR NI VIRT RES SHR S٪ CPU٪ MEM TIME + COMMAND
25677 أوبونتو 20 0 636968 331944 4 R 5.2 32.7 0: 02.30 جونيكورن
25678 أوبونتو 20 0 644632 259684 0 جنوب 0.0 25.6 0: 02.95 جونيكورن
25680 أوبونتو 20 0 644636 259668 0 جنوب 0.3 25.6 0: 02.97 جونيكورن
1094 mysql 20 0 689704 49144 0 جنوب 0.0 4.8 16: 22.92 mysqld
25673 أوبونتو 20 064836 14428 0 جنوب 0.6 1.4 0: 00.23 جونيكورن

سامحني ، ما زلت لا أفهم تمامًا. يبدو أن Gunicorn يستخدم 300 ميغا بايت تقريبًا. يتمثل الاختلاف الوحيد في طلبات الحد الأقصى في أنه من المرجح أن يكون لديك جميع العمال الثلاثة الذين يستهلكون 300 ميغا بايت لكل منهم ، بدلاً من العامل الوحيد الذي يتعامل مع الطلب حاليًا.

من ناحية أخرى ، يستخدم runserver أيضًا حوالي 300 ميغا بايت لكل عملية.

يبدو أن المثيل الخاص بك ليس كبيرًا بما يكفي لتشغيل ثلاثة عمال ولا يهم ما إذا كنت تستخدم runserver أو gunicorn.

إذا كنت ترغب في التعامل مع المزيد من الطلبات المتزامنة ، فستحتاج إلى استخدام نوع عامل غير متزامن بدلاً من بدء عدة عمال.

هل هناك أي شيء آخر أنا مفقود؟

أعتقد أنك محق تمامًا ولا يفوتك شيء. في الواقع ، كانت المشكلة أن وثائق Gunicron تشير إلى عدد المستخدمين من العمال كـ 2 * N + 1 ولأننا كان لدينا نواة واحدة لذلك استخدمنا 3 عمال.

الآن لا يوجد شيء مذكور حول الطريقة التي يتم استخدام هؤلاء العمال بها. يبدو أنه تمت جدولتهم بواسطة نظام التشغيل ولا تعرف أبدًا أي عامل سيتعامل مع الطلب الوارد. إذن ما كان يحدث في البداية هو أن ذاكرةنا محدودة ، والتي استغرقت nginx وعمليات النظام الأخرى جزءًا منها ، ثم كان من المفترض أن يستخدم العمال بقية الذاكرة (800 ميجابايت تقريبًا). نظرًا لأننا قمنا بتكوين 3 عمال ، لذلك بافتراض أن كل عامل يأخذ 300 ميجابايت ، فإن الثلاثة معًا سيستهلكون 900 ميجابايت وهو غير متاح ، لذلك عندما يتعامل العامل الثالث (الذي لا تعرفه أبدًا لأنه وفقًا لجدولة نظام التشغيل) مع الطلب (بعد قام عاملان آخران بالتعامل بالفعل واستهلاك إجمالي 600 ميجابايت) ثم لا يحتوي النظام على ذاكرة كافية وتعطل العمال. حدث هذا بشكل عشوائي لذلك قمنا بتكوين max-request على أنه 1 والذي كان يعيد تشغيل العامل بعد كل طلب وتحرير أي ذاكرة مخصصة لتطبيق python الخاص بنا. وبهذه الطريقة تم التغلب على تعطل العامل ولكن النظام أصبح بطيئًا واعتقدنا أن عامله يأخذ فجأة ذاكرة ضخمة ويبطئ النظام ولم نتمكن حتى من تصحيحه في كل مرة يتم فيها إعادة تشغيل العامل. لتصحيح الأمر أكثر ، كان علينا أن يكون لدينا طلب كبير بما يكفي لخدمة المزيد من الطلبات دون إعادة تشغيل العامل ، لكن هذا لم يكن ممكنًا لأننا إذا سمحنا بمزيد من الطلبات مع 3 عمال (يمكن أن يستغرق كل منهم 300 ميجابايت تقريبًا) في نظام 1 جيجابايت ، فإن العامل كان تحطمت وكنا نفقد الذاكرة.

ولكن بينما جعلنا عدد العمال 1 ، فإن النظام يتصرف بشكل أو بآخر مثل خادم التشغيل. حتى الآن نحن لا نخرج من الذاكرة والنظام سريع أيضا.

لذا فإن ما تعلمناه هو أن القاعدة العامة لإنشاء عاملين 2 * N + 1 هي مجرد منطق غامض حيث تحتاج إلى التفكير في الذاكرة أيضًا.

لنفترض أن كل عامل gunicorn يأخذ ذاكرة 'W' وأن ذاكرة النظام الإجمالية هي 'T' وأن N = 1 نواة.

لذلك حسب اقتراح الحد الأدنى لعدد العمال = 2 * 1 + 1 = 3

افترض الآن أن التطبيق الخاص بك يأخذ ذاكرة "A".

لذا فإن الذاكرة الإجمالية مطلوبة مع عامل واحد فقط يتعامل مع جميع الطلبات R = W * 3 + A

طالما أن T أكثر كافيًا من R ، فإن كل شيء على ما يرام ولكن المشكلة تأتي عندما نفترض أن نظام التشغيل يقوم بجدولة عمال آخرين لخدمة المزيد من الطلبات ، ثم يستهلك كل عامل ذاكرة W + A على الأقل. لذلك في الواقع ، يجب أن تكون ذاكرة النظام المطلوبة لجهاز gunicorn مع 3 عمال أكثر من (W + A) * 3 لتجنب حدوث تعليق عشوائي أو عدم وجود ردود عشوائية أو استجابات عشوائية للطلبات السيئة (على سبيل المثال ، يتم استخدام nginx كوكيل عكسي ، فلن تحصل على أي استجابة إذا تعطل عامل gunicorn بسبب قلة الذاكرة ، وبالتالي سوف يستجيب nginx برسالة طلب سيئ)

لذلك نحن بحاجة إلى توخي الحذر أثناء تكوين gunicorn والنظر في كل من عدد النواة والذاكرة.

أعتقد أن وثائق Gunicorn على http://docs.gunicorn.org/en/stable/settings.html
يجب ذكر استهلاك الذاكرة أيضًا أثناء تكوين العمال.

المنطق ليس بهذا الغموض ؛) وجود 2 * نوى + 1 يسمح بموازنة جيدة للحمل بين العمال. من الصحيح أيضًا أن كل عامل معزول وسيقوم بتحميل التطبيق بشكل مستقل ثم يستهلك بعض الذاكرة.

إذا كنت ترغب في تقليل حجم العمال على جهاز محدود ، يمكنك استخدام الإعداد --preload الذي سيحمّل رمز التطبيق مسبقًا ومشاركته بين العامل.

نقطة جيدة أيضًا يجب أن يكون لدينا جزء عن الذاكرة في صفحة التصميم هذه.

من المؤكد أن gunicorn يأكل الكثير من المذكرات أكثر مما ينبغي ، لقد قمت مؤخرًا بالتبديل إلى uwsgi لحفظ الذاكرة المفقودة ..

@ tyan4g gunicorn نفسها لا تستخدم الكثير من الذاكرة ، فهي لا تخزن مؤقتًا ولها بصمة ذاكرة منخفضة جدًا لتطبيق بيثون. ما يستخدم ذاكرة الوصول العشوائي بشكل عام هو التطبيق واستخدامه. يتم عزل جميع العمال ولا يتم مشاركة الذاكرة افتراضيًا. يتبع uwsgi نهجًا مشابهًا لذلك لا ينبغي أن يؤثر على الذاكرة كثيرًا. لاحظ أن استخدام gthread أو أي عامل غير متزامن آخر يسمح لك بتقليل عدد العمال إذا لزم الأمر.

كما أنني أجد أن عملية العامل زادت بشكل مفاجئ. بمرور الوقت ، نواجه تسرب الذاكرة. ثم أقوم بتكوين gunicorn باستخدام max-request ، ثم تم حل المشكلة. أريد أن أعرف السبب المحتمل لمقابلة تسريب الذاكرة عندما أبدأ gunicorn بدون max_request params. إصدار gunicorn هو 19.7.0 استخدمته.

benoitc هل يمكنك المساعدة في إعطائي مجموعة من الأفكار؟

@ v-wiil ، ربما تحتاج إلى التحقيق في هذا الأمر بنفسك وفتح مشكلة جديدة إذا كنت تعتقد أن هناك تسربًا في Gunicorn.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات