RE:NODE

აპლიკაციები12 წუთის საკითხავი

Django-ს production-ზე გაშვება: settings, static ფაილები, gunicorn

Django პროექტის გაშვება: DEBUG და ALLOWED_HOSTS, gunicorn worker-ები, collectstatic და WhiteNoise, მიგრაციები, proxy ჰედერები და დაცული cookie-ები.

0 მკითხველი

Django პროექტი production-ზე ხუთი ცვლილებით მიდის, დანარჩენს კი ხელს არ ვახლებთ: DEBUG გამორთული, ALLOWED_HOSTS დაყენებული, secret key, რომელიც გარემოდან მოდის, static ფაილები, რომლებიც იქ არის შეგროვებული, სადაც web სერვერს მათი წაკითხვა შეუძლია, და gunicorn runserver-ის ნაცვლად. დანარჩენ უმეტესობაზე Django თავადაც გეტყვის, თუ ჰკითხავ ბრძანებით python manage.py check --deploy.

შემდეგში თითოეული მათგანი თანმიმდევრობითაა განხილული, პლუს ის, რასაც ჩეკლისტი არ ფარავს: რამდენი worker ეტევა იმ მეხსიერებაში, რომელიც იყიდე, რა უნდა გაეშვას ყოველ restart-ზე და რა - მხოლოდ ერთხელ, როგორ იქცევა მონაცემთა ბაზა, როცა ოთხი worker პროცესი თითოეული საკუთარ კავშირებს ხსნის, და ის ხუთი შეცდომა, რომელიც Django-ს თითქმის ყველა წარუმატებელ გაშვებას ხსნის.

ჯერ ჰკითხე Django-ს, რა არის არასწორი#

ყველაფრის წინ გაუშვი deployment შემოწმება შენს production settings-ზე. ის კითხულობს შენს კონფიგურაციას და ბეჭდავს ყველა პარამეტრს, რომელიც არაუსაფრთხოა ან აკლია:

bash
$ DJANGO_SETTINGS_MODULE=myproject.settings.production \    python manage.py check --deploy --fail-level WARNING

ის დაიჩივლებს DEBUG-ზე, HSTS-ის არარსებულ პარამეტრებზე, cookie-ებზე, რომლებიც secure-ად არ არის მონიშნული, და SECRET_KEY-ზე, რომელიც startproject-ის გენერირებულს ჰგავს. ყველა გაფრთხილება რეალური პრობლემაა დოკუმენტირებული გამოსწორებით, ხოლო --fail-level WARNING მას არანულოვანი კოდით ამთავრებინებს, რაც ნიშნავს, რომ deploy სკრიპტში ჩაგიდვია და ის შენ შეგაჩერებს.

ის ყველაფერს ვერ იჭერს. მან არაფერი იცის იმაზე, რომ შენი static ფაილები მიუწვდომელია, ბაზის კავშირების რაოდენობაზე, ან იმაზე, ადგენს თუ არა შენს წინ მდგომი proxy იმ ჰედერებს, რასაც შენი settings ელოდება. ეს ქვემოთ მოცემული სექციებია.

Settings: DEBUG, ALLOWED_HOSTS და secret key#

DEBUG = False ყველაზე მნიშვნელოვანი ხაზია. როცა ჩართულია, exception აჩვენებს გვერდს, რომელიც შეიცავს შენს settings-ს, შენს გარემოს და stack trace-ს ლოკალური ცვლადებით, მას, ვინც ის გამოიწვია. ის ასევე აიძულებს Django-ს, პროცესის სიცოცხლის განმავლობაში მეხსიერებაში შეინახოს ყველა SQL query, რაც ზუსტად მეხსიერების გაჟონვას ჰგავს.

მისი გამორთვა კიდევ ორ ქცევას ცვლის, რაც ხალხს უკვირს. Django static ფაილებს საერთოდ აღარ ემსახურება და იწყებს ALLOWED_HOSTS-ის აღსრულებას. მოთხოვნა, რომლის Host ჰედერი ამ სიაში არ არის, უბრალო 400-ს იღებს და ლოგში DisallowedHost ჩანაწერს.

settings.py
import osDEBUG = os.environ.get("DJANGO_DEBUG", "false").lower() == "true"SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]ALLOWED_HOSTS = ["app.example.com", "www.example.com"]CSRF_TRUSTED_ORIGINS = ["https://app.example.com", "https://www.example.com"]

secret key-ს .get(...)-ის ნაცვლად os.environ[...]-ით კითხვა განზრახაა: ნაკლული გასაღები პროცესს import-ისას გასაგები შეცდომით აჩერებს და არ უშვებს None-ით, რაც ყველა სესიას ჩუმად ბათილს გახდიდა. CSRF_TRUSTED_ORIGINS-ს Django 4.0-დან სქემა სჭირდება და სწორედ ის არის მიზეზი იმ „CSRF verification failed - Origin checking failed“ შეტყობინებებისა, რომლებიც იმ დღეს ჩნდება, როცა საიტი HTTPS-ის უკან გადადის.

production settings შეინახე ცალკე მოდულში და არა ერთ ფაილში გარემოს ცვლადით განშტოებით. myproject/settings/base.py, საიდანაც development.py და production.py import-ს აკეთებენ, გავრცელებული სტრუქტურაა და ის კითხვას „რა არის რეალურად დაყენებული production-ში“ ერთი მოკლე ფაილის წაკითხვით პასუხგასაცემს ხდის. თავად მნიშვნელობები გარემოდან მოდის - გარემოს ცვლადები და საიდუმლოები აღწერს, სად ჩაწერო ისინი და რა გააკეთო, როცა ერთ-ერთი გაჟონავს.

გაშვება: gunicorn, worker-ები და მეხსიერება#

Django WSGI-ს ლაპარაკობს, ამიტომ gunicorn ნაგულისხმევი პასუხია, ხოლო myproject/wsgi.py შენს პროექტში უკვე არის:

bash
$ gunicorn myproject.wsgi:application \    --bind 0.0.0.0:${SERVER_PORT:-8000} \    --workers 3 --timeout 30 --access-logfile -

0.0.0.0-ზე bind-ი 127.0.0.1-ის ნაცვლად არის ის, რაც აპლიკაციას კონტეინერს გარედან ხელმისაწვდომს ხდის; ეს ყველაზე გავრცელებული მიზეზია „მუშაობს, მაგრამ არაფერი უკავშირდება“ სიტუაციისა. პორტის გარემოდან აღება მნიშვნელოვანია, რადგან პანელი ან პლატფორმა მას შენთვის გამოყოფს - სახელი Startup ჩანართზეა.

თითოეული worker ცალკე პროცესია, რომელიც Django-ს, შენს მოდელებს, შაბლონებს და ყველა დაყენებულ მესამე მხარის აპს საკუთარ ასლად ინახავს. მოკრძალებული პროექტი worker-ზე 100-200 MB-ს იკავებს; Django REST Framework-ით, PDF ბიბლიოთეკითა და სურათების დამმუშავებლით - უფრო მძიმეა. გაზომე ps -o rss= -p PID-ით და არა გამოცნობით.

გეგმის მეხსიერებაCPU წილიWorker-ებიშენიშვნები
1 GB0.5 ბირთვი1მეორე worker-ის ნაცვლად დაამატე --threads 4
2 GB1 ბირთვი2კომფორტულია პატარა საიტისთვის
4 GB1.5 ბირთვი3ჩვეულებრივი სამუშაო ზომა
6-8 GB2-3 ბირთვი4-6ამის შემდეგ ზღვარი ბაზაა და არა Django

ორი პარამეტრი იმსახურებს ადგილს. --threads 4 --worker-class gthread-თან ერთად ერთ worker-ს საშუალებას აძლევს, ოთხი მოთხოვნა ემსახუროს, რომლებიც ბაზას ელოდებიან, ოთხი პროცესის მეხსიერებაზე გაცილებით ნაკლებით. --max-requests 1000 --max-requests-jitter 100 worker-ებს პერიოდულად ანახლებს, რაც ნელ გაჟონვას ფარავს, სანამ მას იპოვი.

თუ Channels-ს, websocket-ებს ან async view-ებს სერიოზულად იყენებ, გაუშვი myproject.asgi:application uvicorn-ის ქვეშ. ამ პოსტში დანარჩენი ყველაფერი ძალაში რჩება; იცვლება მხოლოდ სერვერი. ორ მოდელს შორის შედარება არის FastAPI-ს თუ Flask-ის გაშვება.

Static ფაილები: collectstatic, WhiteNoise და media#

დეველოპმენტში Django static ფაილებს იქ პოულობს, სადაც არიან. production-ში ის მათ საერთოდ არ ეძებს. collectstatic ყველა დაყენებული აპის ყველა static ფაილს ერთ დირექტორიაში აკოპირებს, ხოლო სხვა რამ ემსახურება ამ დირექტორიას.

settings.py
STATIC_URL = "/static/"STATIC_ROOT = BASE_DIR / "staticfiles"STATICFILES_DIRS = [BASE_DIR / "assets"]MEDIA_URL = "/media/"MEDIA_ROOT = BASE_DIR / "media"
bash
$ python manage.py collectstatic --noinput

შედეგის მომსახურების ყველაზე მარტივი გზა ერთ სერვერზე არის WhiteNoise, რომელიც static ფაილებს თავად Django პროცესიდან აწვდის სწორი cache ჰედერებით. მას ერთი dependency სჭირდება, ერთი middleware ხაზი პირდაპირ SecurityMiddleware-ის შემდეგ და ერთი storage პარამეტრი:

settings.py
MIDDLEWARE = [    "django.middleware.security.SecurityMiddleware",    "whitenoise.middleware.WhiteNoiseMiddleware",    "django.contrib.sessions.middleware.SessionMiddleware",]STORAGES = {    "default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},    "staticfiles": {        "BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",    },}

STORAGES ლექსიკონი Django 4.2-ისა და უფრო ახალი ვერსიების ფორმაა; ძველი პროექტები მის ნაცვლად STATICFILES_STORAGE-ს იყენებენ, რომელიც Django 5.1-ში ამოიღეს. compressed manifest backend ყველა ფაილის სახელს ჰეშავს და manifest-ს წერს, ამიტომ asset-ები სამუდამოდ შეიძლება იქნას ქეშირებული და deploy ქეშს სახელების შეცვლით ანადგურებს. ის ასევე აჩერებს build-ს, თუ CSS ფაილი სურათზე მიუთითებს, რომელიც არ არსებობს, რაც პირველად მტრულად გეჩვენება, მეორედ კი გიხსნის.

Media ფაილები სხვაა და WhiteNoise მათ არ მოემსახურება. მომხმარებლის ატვირთვები MEDIA_ROOT-ში მიდის მუდმივ დისკზე, ისინი შენი გეგმის დისკის ლიმიტში ითვლება და შენს რეპოზიტორიაში არ არის, ამიტომ სწორედ ისაა, რაზეც ხალხს backup ავიწყდება. თუ ატვირთვები მნიშვნელოვანია, ისინი backup განრიგში ბაზის გვერდით უნდა იყოს.

მონაცემთა ბაზა, მიგრაციები და კავშირები#

Django ყოველი მოთხოვნისთვის ახალ ბაზის კავშირს ხსნის, თუ სხვაგვარად არ უთხარი. სერვერზე, სადაც ბაზა სხვა ჰოსტზეა, ეს handshake ყოველი პასუხის გაზომვად ნაწილია:

settings.py
DATABASES = {    "default": {        "ENGINE": "django.db.backends.postgresql",        "NAME": os.environ["DB_NAME"],        "USER": os.environ["DB_USER"],        "PASSWORD": os.environ["DB_PASSWORD"],        "HOST": os.environ["DB_HOST"],        "PORT": os.environ.get("DB_PORT", "5432"),        "CONN_MAX_AGE": 600,        "CONN_HEALTH_CHECKS": True,    }}

CONN_MAX_AGE კავშირს ათი წუთით ხსნილს ინახავს ხელახლა გამოსაყენებლად. CONN_HEALTH_CHECKS, რომელიც Django 4.1-ში დაემატა, Django-ს აიძულებს, ხელახლა გამოყენებული კავშირი გამოსცადოს, სანამ მოთხოვნას გადასცემს, რაც აჩერებს „server closed the connection unexpectedly“ შეცდომებს, რომლებსაც მუდმივი კავშირები უმოქმედობის შემდეგ სხვაგვარად წარმოქმნიან.

არითმეტიკა, რომელსაც უნდა უყურო: მუდმივი კავშირები თითო worker პროცესზეა, ამიტომ სამი gunicorn worker სამ კავშირს ინახავს და ინახავს იმისგან დამოუკიდებლად, ტრაფიკი მოდის თუ არა. დაამატე დაგეგმილი სამუშაო და shell სესია და პატარა PostgreSQL ინსტანცია იმაზე ახლოსაა ლიმიტთან, ვიდრე ელოდები. კავშირების პულები და ლიმიტები გამოთვლებს შეიცავს; PostgreSQL გეგმა database hosting-ზე არის პასუხი, როცა პანელის ბაზის slot აღარ ჰყოფნის.

მიგრაციები ახალი კოდის ტრაფიკის მომსახურებამდე გაეშვება და არა მისი შიგნიდან:

bash
$ python manage.py migrate --noinput

ერთ სერვერზე ეს ერთი ხაზია start ბრძანებაში და gunicorn-ის bind-მდე სრულდება. საინტერესო ხდება, როცა მიგრაცია დატვირთულ ცხრილზე lock-ს იღებს - სვეტის დამატება default-ით, ან ინდექსი CONCURRENTLY-ის გარეშე - და ყველა მოთხოვნა მის უკან რიგში დგება. მიგრაციები downtime-ის გარეშე გრძელი ვერსიაა; მოკლე ვერსია ასეთია: ნებისმიერი მიგრაცია დიდ ცხრილზე გაშვებამდე ერთხელ უნდა წაიკითხო.

პირველი admin მომხმარებლის შექმნა ინტერაქტიული shell-ის გარეშე:

bash
$ DJANGO_SUPERUSER_USERNAME=admin \  DJANGO_SUPERUSER_EMAIL=admin@example.com \  DJANGO_SUPERUSER_PASSWORD=... \  python manage.py createsuperuser --noinput

შენი აპი თითქმის აუცილებლად უბრალო HTTP-ს იღებს proxy-სგან, რომელმაც TLS დაასრულა. Django-ს უნდა უთხრა, თორემ ის ყველა მოთხოვნას უსაფრთხოდ არ ჩათვლის, http:// URL-ებს ააგებს და proxy-სთან გადამისამართებებზე იჩხუბებს:

settings.py
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")USE_X_FORWARDED_HOST = TrueSESSION_COOKIE_SECURE = TrueCSRF_COOKIE_SECURE = TrueSECURE_SSL_REDIRECT = TrueSECURE_HSTS_SECONDS = 31536000SECURE_HSTS_INCLUDE_SUBDOMAINS = TrueSECURE_HSTS_PRELOAD = True

SECURE_PROXY_SSL_HEADER დააყენე მხოლოდ მაშინ, როცა proxy, რომელსაც აკონტროლებ, ამ ჰედერს ყოველ მოთხოვნაზე ადგენს. თუ აპი პირდაპირაც ხელმისაწვდომია, კლიენტს ჰედერის გაგზავნა თავადაც შეუძლია და Django დაიჯერებს. და SECURE_SSL_REDIRECT ჩართე მხოლოდ მას შემდეგ, რაც proxy ჰედერი მუშაობს, თორემ უსასრულო გადამისამართების ციკლს მიიღებ: Django HTTPS-ზე გადაამისამართებს, proxy იმავე უბრალო მოთხოვნას გადასცემს, Django ისევ გადაამისამართებს.

HSTS ერთ წუთს დაფიქრებას იმსახურებს და არა copy-paste-ს. წლის სიგრძის SECURE_HSTS_SECONDS ეუბნება ყველა ბრაუზერს, რომელიც შენთან იყო, წლის განმავლობაში უარი თქვას უბრალო HTTP-ზე, ქვედომენებზეც, თუ ჩართავ. ეს სწორი პარამეტრია საიტისთვის, რომელიც სამუდამოდ HTTPS-ზე რჩება, და მტკივნეული - თუ ჰოსტის სახელებს ჯერ კიდევ ცვლი. დაიწყე რამდენიმე საათით, დარწმუნდი, რომ არაფერი გაფუჭდა, შემდეგ გაზარდე.

Push GitHub-ზეmain branchპანელი იღებს repo-სხანმოკლე tokenpip installrequirements.txtmanage.py migrateბაზაcollectstaticSTATIC_ROOTgunicornwsgi:application
რა ხდება push-სა და გაშვებულ Django აპს შორის

RE:NODE-ზე აპის გეგმის proxy slot არის ის, რაც ამ სურათის თავშია: მიუთითე A ჩანაწერი ნაჩვენებ მისამართზე, სერთიფიკატი გაიცემა და ავტომატურად განახლდება 21-დღიან ფანჯარაში, ხოლო კლიენტის ნამდვილი მისამართი X-Forwarded-For-ში მოდის. Git deploy-ები GitHub-იდან GitHub App-ით ხანმოკლე token-ებით მოდის, ამიტომ კერძო რეპოზიტორიები მუშაობს იმის გარეშე, რომ მუდმივი token სადმე ჩააკოპირო.

Deploy: რა გაეშვება ყოველ start-ზე#

გადაწყვიტე, რა მიეკუთვნება start ბრძანებას და რა - ერთჯერად ამოცანას, რადგან start ბრძანება ყოველ ჯერზე გაეშვება, როცა პროცესი restart-დება - crash-ის შემდეგაც, ღამის სამ საათზე, როცა ბაზას ცუდი დრო აქვს.

bash
$ pip install -r requirements.txt --no-cache-dir \  && python manage.py migrate --noinput \  && python manage.py collectstatic --noinput \  && gunicorn myproject.wsgi:application --bind 0.0.0.0:${SERVER_PORT:-8000} \     --workers 3 --access-logfile -

უსაფრთხოა ყოველ start-ზე: დაპინული requirements-ის ინსტალაცია (pip გამოტოვებს უკვე დაკმაყოფილებულს), migrate (no-op, როცა გასატარებელი არაფერია) და collectstatic --noinput (რამდენიმე წამი, იდემპოტენტურია). უსაფრთხო არ არის ყოველ start-ზე: ყველაფერი, რაც fixture-ებს ტვირთავს, ყველაფერი, რაც ელფოსტას აგზავნის, და ყველა მონაცემთა გამოსწორების ბრძანება, რომელიც ვიღაცამ ერთხელ ინციდენტისთვის დაწერა.

პინინგი ამ ყველაფერს პატიოსანს ინახავს. თუ requirements.txt-ში ზუსტი ვერსიების ნაცვლად დიაპაზონებია, restart უიღბლო მომენტში რაღაცის სხვა ვერსიას დააყენებს, ვიდრე გამოსცადე - იხილე Python requirements და virtualenv-ები lock ფაილებისთვის, რომლებიც ნამდვილად აფიქსირებს. დაამატე გარემოში PYTHONUNBUFFERED=1-იც, თორემ კონსოლი არაფერს აჩვენებს, სანამ გამოტანის ბუფერი არ ივსება.

ლოგირება სტანდარტულ გამოტანაზე უნდა მიდიოდეს, რომ კონსოლმა ის მიიღოს. Django-ს ნაგულისხმევი კონფიგურაცია შეცდომებს მხოლოდ ADMINS-ს უგზავნის ელფოსტით:

settings.py
LOGGING = {    "version": 1,    "disable_existing_loggers": False,    "handlers": {"console": {"class": "logging.StreamHandler"}},    "root": {"handlers": ["console"], "level": "INFO"},}

ელფოსტა ცალკე გაფრთხილებას იმსახურებს: Django პაროლის აღდგენებსა და შეცდომების ანგარიშებს SMTP-ით აგზავნის, ჰოსტინგის გეგმა კი საფოსტო სერვერი არ არის. გამოიყენე გარე პროვაიდერი, დააყენე EMAIL_HOST და დანარჩენი გარემოდან და გამოსცადე პაროლის აღდგენა გაშვებამდე და არა პირველი დაბლოკილი მომხმარებლის შემდეგ.

ფონური სამუშაო: განრიგები, ბრძანებები და Celery#

Django-ს ჩაშენებული ამოცანების რიგი არ აქვს. ვარიანტები მექანიზმის ზრდის მიხედვით:

  • Management ბრძანება ტაიმერზე. python manage.py clearsessions ან შენი საკუთარი, გაშვებული cron-ით მანქანაზე, სადაც ის გაქვს, ან პატარა scheduler-ით web პროცესის გვერდით. ეს ფარავს ღამის გასუფთავებას, ანგარიშების გენერაციასა და digest ელფოსტებს და არანაირ დამატებით სერვისს არ საჭიროებს.
  • django-q2, huey ან მსგავსი მსუბუქი რიგი ბაზაზე დაფუძნებული broker-ით. ერთი დამატებითი პროცესი, დამატებითი სერვისის გარეშე.
  • Celery გამოყოფილი broker-ით. ძლიერია და მეორე სერვისია გასაშვებად და გადასახდელად. ღირს მაშინ, როცა ამოცანები ხშირია, retry სჭირდება და restart-ს უნდა გადაურჩეს.

გულწრფელად უპასუხე, რომელი გჭირდება აპს. პატარა Django საიტების უმეტესობა პირველ ვარიანტს ითხოვს, მესამეს ჰყიდიან და ბოლოს broker რჩება, რომელსაც არავინ აკვირდება. ფონური სამუშაოები პატარა სერვერზე და Redis, როცა გჭირდება ორივე იგივე არგუმენტს უფრო ვრცლად ავითარებს.

რასაც არ უნდა აირჩევ, worker პროცესი მეორე პროცესია, რომელიც gunicorn-თან იმავე CPU წილსა და მეხსიერებას ეჯიბრება. 1 GB გეგმაზე ერთი gunicorn worker პლუს ერთი job worker უკვე მთელი ბიუჯეტია.

რა ვერ გამოდის#

უბრალო 400 და ლოგში `DisallowedHost`. Host ჰედერი ALLOWED_HOSTS-ში არ არის. დაამატე ზუსტი hostname, რომელსაც ხალხი იყენებს, www-ს ჩათვლით, თუ DNS მასზე მიუთითებს.

საიტი მუშაობს, მაგრამ სტილი არ აქვს. collectstatic არ გაეშვა, STATIC_ROOT არასწორია, ან ამ დირექტორიას არაფერი ემსახურება. შეამოწმე, რომ ფაილი ფიზიკურად STATIC_ROOT-შია, შემდეგ - რომ WhiteNoise-ის middleware არის და სწორ პოზიციაზეა.

`collectstatic` ვარდება „could not be found“-ით. manifest storage წყვეტს მითითებას CSS ფაილის შიგნით, რომელიც არარსებულ asset-ზე მიუთითებს. გაასწორე მითითება; ალტერნატივა manifest-ის გამორთვა და cache busting-ის დაკარგვაა.

CSRF verification failed ფორმაზე, რომელიც გუშინ მუშაობდა. ჩვეულებრივ CSRF_TRUSTED_ORIGINS-ს სქემა აკლია, ან secure-ად მონიშნული cookie იგზავნება კავშირზე, რომელიც Django-ს უბრალო HTTP-ად მიაჩნია. ჯერ proxy ჰედერი შეამოწმე.

Too many redirects. SECURE_SSL_REDIRECT მომუშავე SECURE_PROXY_SSL_HEADER-ის გარეშე.

`OperationalError: too many connections`. worker-ების რაოდენობამ, გამრავლებულმა მუდმივ კავშირებზე, ბაზის ლიმიტი გადააჭარბა. შეამცირე CONN_MAX_AGE, შეამცირე worker-ები, ან გადადი უფრო მაღალი ლიმიტის გეგმაზე.

მეხსიერება სტაბილურად იზრდება, სანამ სერვერი არ გადაიტვირთება. შეამოწმე, რომ DEBUG მართლა False-ია იმ settings მოდულში, რომელიც რეალურად იტვირთება - query-ების ლოგირება ჩვეულებრივი დამნაშავეა. თუ დარწმუნებული არ ხარ, დაბეჭდე settings.DEBUG manage.py shell-იდან.

FAQ#

მჭირდება თუ არა nginx gunicorn-თან ერთად?

არა ერთ სერვერზე WhiteNoise-ით, თუ შენს წინ უკვე რაღაც ასრულებს TLS-ს. Gunicorn აპლიკაციას ემსახურება და WhiteNoise - static ფაილებს სწორი ქეშირებით. დაამატე საკუთარი proxy, როცა გჭირდება მოთხოვნის ზომის ლიმიტები, rate limiting ან ქეშირება, რასაც Django არ უნდა აკეთებდეს.

რამდენი RAM სჭირდება Django საიტს?

ერთი gunicorn worker ჩვეულებრივ 100-200 MB-ია, ამიტომ 1 GB პატარა საიტს ერთი worker-ით და მარაგით უძღვება, ხოლო 2-4 GB ნამდვილი საიტისთვის კომფორტული დიაპაზონია. რიცხვი შენი dependency-ებით იზრდება და არა ტრაფიკით, ამიტომ გაზომე საკუთარი პროექტი და ცხრილს ნუ ენდობი.

უნდა გაეშვას თუ არა მიგრაციები deploy-ზე ავტომატურად?

ერთ სერვერზე - დიახ, gunicorn-ის დაწყებამდე ნაბიჯად, რომ არცერთ მოთხოვნას არ ემსახუროს კოდი, რომლის სქემაც ჯერ არ მოსულა. რისკიანი ხდება მიგრაცია, რომელიც დიდ ცხრილს ბლოკავს - მისი გადახედვა და განზრახ გაშვება სჯობს იმ მომენტს, როცა restart შემთხვევით მოხდება.

სად მიდის მომხმარებლის ატვირთვები?

MEDIA_ROOT-ში სერვერის დისკზე, რომელიც static ფაილებისგან განცალკევებულია და WhiteNoise-ს არ ემსახურება. ისინი გეგმის დისკში ითვლება, რეპოზიტორიაში არ არის და backup განრიგში უნდა იყოს, თორემ backup არ აქვს.

შემიძლია Celery-ის გაშვება იმავე სერვერზე, სადაც web აპი?

შეგიძლია და ის gunicorn-თან გეგმის CPU-სა და მეხსიერებას გაინაწილებს. broker უფრო რთული საკითხია: Celery-ს ის სჭირდება და ეს კიდევ ერთი სერვისია. თუ შენი სამუშაოები პერიოდულია და არა მოვლენებზე დამოკიდებული, განრიგზე გაშვებული management ბრძანება იმავეს broker-ის გარეშე აკეთებს.


კომენტარები

სრულიად ანონიმურად: ანგარიშის, ელფოსტის და cookie-ის გარეშე. ინახება მხოლოდ სახელი, ტექსტი და დრო - სხვა არაფერი. ბმულების რაოდენობა ლიმიტირებულია.

0/2000