როგორ მუშაობს backend: Nginx, Gunicorn და Django-ს არქიტექტურა
რა ხდება კულისებში, როცა საიტზე შედიხართ? მარტივად და დეტალურად ვხსნით ბექენდის მუშაობის პრინციპებს, Nginx-ის, Gunicorn-ისა და Django-ს მაგალითზე.
ამ ბლოგში ავხსნით, თუ როგორ მუშაობს ბექენდი. თუმცა ეს ტექსტი ოდნავ უფრო ტექნიკური იქნება, ვიდრე ჩვენი სხვა, დამწყებებისთვის უფრო მეგობრული შესავალი ბექენდში (back-end). შეგიძლიათ, ჯერ სწორედ ხსენებულ ბლოგს გაეცნოთ.
კარგი. მოდით, მარტივი მეტაფორებით დავიწყოთ თითოეული იმ ცნების გაგება, რომლებზეც ამ ბლოგში ვრცლად ვისაუბრებთ: Nginx, Gunicorn, Django, middleware, ORM და სხვა.
წარმოიდგინეთ, რომ ვებსაიტი არის ერთი უზარმაზარი, მუდმივად გადაჭედილი და პოპულარული რესტორანი. მაშინ, შენი ყოველი "კლიკი" არის შეკვეთა, რომელსაც ამ რესტორანში აკეთებ.
აი, როგორ მუშაობს ეს მექანიზმი:
Nginx (ვებ-სერვერი) არის რესტორნის სუპერ-სწრაფი მიმღები მენეჯერი. როცა რესტორანში შედიხარ, ის გხვდება კარში. თუ შენ უბრალოდ მენიუ, ხელსახოცი ან ჭიქა წყალი გჭირდება (ესენია ჩვენი სტატიკური სურათები და დიზაინის ფაილები), ის იქვე მაგიდიდან იღებს და წამში გაწვდის, რომ მზარეულები ტყუილად არ შეაწუხოს. თუ რთული კერძი გინდა, ის შენს შეკვეთას უკან, სამზარეულოსკენ აგზავნის.
Gunicorn / WSGI (აპლიკაციის სერვერი) არის თარჯიმანი მიმტანი. მიმღები მენეჯერი საუბრობს მხოლოდ მომხმარებლების ენაზე (HTTP), ხოლო სამზარეულოში მყოფ შეფებს ესმით მხოლოდ მზარეულების სპეციფიკური ენა (Python). ჩვენი მიმტანი იღებს შენს შეკვეთას, თარგმნის მას სამზარეულოსთვის გასაგებ ენაზე, აბარებს შეფს, და მერე გამზადებულ კერძს ისევ შენს ენაზე ნათარგმნს გიბრუნებს.
Django (ვებ-ფრეიმვორკი) არის თავად მთავარი სამზარეულო. სწორედ აქ ხდება ნამდვილი კულინარიული ჯადოქრობა. ის იღებს ნათარგმნ შეკვეთებს, აგროვებს ინგრედიენტებს, ხარშავს, წვავს და საბოლოოდ აწყობს იმ გემრიელ კერძს (მონაცემებს ან HTML გვერდს), რომელიც შენ მოითხოვე.
Middleware (შუალედური ფენა) არის დაცვის თანამშრომელი და სანიტარი სამზარეულოს კარებთან. სანამ შენი შეკვეთა მზარეულამდე მივა, ის ამოწმებს: "აქვს ამ ადამიანს აქ შემოსვლის უფლება?" (ავტორიზაცია) ან "ხომ არ არის ეს შეკვეთა მოწამლული?" (უსაფრთხოება). თუ რამე არ მოეწონა, შეკვეთას ეგრევე სანაგვეში აგდებს.
URL Routing (მარშრუტიზაცია) არის შეფის დამხმარე, რომელიც დავალებებს ანაწილებს. ის დახედავს შეკვეთის ბილეთს და ამბობს: "აჰა, ბურგერი უნდათ — ეს გაუშვით გრილის სექციაში! ეს სალათია — გადაეცით ცივი კერძების განყოფილებას!" ანუ მან ზუსტად იცის, რომელმა კონკრეტულმა მზარეულმა უნდა მოამზადოს შენი კონკრეტული მოთხოვნა.
ORM (მონაცემთა ბაზასთან კომუნიკაცია) არის საწყობის ჭკვიანი რობოტი. მზარეულს არ სჭირდება სარდაფში, გიგანტურ საწყობში ჩასვლა და ბნელ ლაბირინთებში (SQL ენაზე) პროდუქტის ძებნა. შეფი უბრალოდ ეუბნება რობოტს თავის ენაზე: "მომიტანე 5 პომიდორი" და რობოტმა ზუსტად იცის, საწყობის რომელ თაროზე მოძებნოს და ამოიტანოს ისინი წამებში.
ამ მეტაფორების შემდეგ, მოდით, ცოტა უფრო სიღრმისეულად და ტექნიკურად შევხედოთ მთელ სურათს.
თანამედროვე ვებ-არქიტექტურის მთავარი ხიბლი კომპონენტების მკაცრი გამიჯვნაა (Decoupling). ერთი მონოლითური პროგრამა, რომელიც მოთხოვნასაც მიიღებს, ქსელის უსაფრთხოებაზეც იზრუნებს და ბაზიდანაც წამოიღებს მონაცემებს, ძალიან ნელი და მოუქნელი იქნებოდა.
ამიტომ, სისტემა დაყოფილია სპეციალიზებულ ფენებად. მოდი, მივყვეთ HTTP მოთხოვნის მოგზაურობას ბრაუზერიდან მონაცემთა ბაზამდე და უკან.
1. Nginx: ქსელის დირიჟორი და კარიბჭის მცველი
როდესაც მომხმარებელი შენს საიტზე შემოდის, პირველი, რასაც მისი HTTP მოთხოვნა ეჯახება, არის Nginx (ვებ-სერვერი). Nginx არ არის უბრალოდ "გადამგზავნი" — ის არის უმძლავრესი ფილტრი და ოპტიმიზატორი.
რატომ ვიყენებთ Nginx-ს და არა პირდაპირ Django-ს?
- მოვლენებზე დაფუძნებული არქიტექტურა (Event-Driven): ტრადიციული სერვერები პრობლემური იყო. ისინი ყოველ შემოსულ მომხმარებელზე ახალ "ნაკადს" (thread) ქმნიდნენ, რაც მეხსიერებას მომენტალურად ავსებდა. Nginx იყენებს ასინქრონულ, Event Loop არქიტექტურას. მას შეუძლია ერთი პროცესით ათიათასობით მომხმარებელს ერთდროულად მოემსახუროს ისე, რომ ოპერატიული მეხსიერება არ გადატვირთოს.
- სტატიკური ფაილების მართვა ოპერაციული სისტემის დონეზე: წარმოიდგინე, პითონს რომ მოუწიოს 5-მეგაბაიტიანი სურათის წაკითხვა დისკიდან და მომხმარებლისთვის გაგზავნა. ამ დროს ის იბლოკება და სხვა, უფრო მნიშვნელოვან ლოგიკურ მოთხოვნებს ვეღარ ამუშავებს. Nginx იყენებს სისტემურ ბრძანებებს (მაგალითად,
sendfileLinux-ზე), რითაც ფაილებს პირდაპირ დისკიდან ქსელის ბარათზე აგზავნის, პითონის შეწუხების გარეშე. - უსაფრთხოება და Load Balancing: Nginx იცავს ბექენდს პირდაპირი შეტევებისგან. გარდა ამისა, თუ შენი საიტი გაიზარდა და ერთი Django სერვერი ვეღარ ყოფნის, Nginx-ს შეუძლია შემოსული ტრაფიკი თანაბრად გადაანაწილოს 2, 3 ან 10 სხვადასხვა სერვერზე.
ახლა გვაქვს სიტუაცია: Nginx-მა მიიღო მოთხოვნა, მიხვდა, რომ ეს სურათი არ არის და დინამიკური პასუხი სჭირდება. მოთხოვნა უნდა გაიგზავნოს ბექენდში, მაგრამ Nginx-ს მხოლოდ HTTP ტექსტი ესმის, Django კი პითონზე მუშაობს.
2. Gunicorn და WSGI: თარჯიმანი და მუშების მენეჯერი
აქ იწყება ყველაზე საინტერესო ტრანსფორმაცია. სანამ Gunicorn-ზე გადავალთ, უნდა გავიგოთ, რა პრობლემა იდგა წარსულში.
CGI-ის კრახი და WSGI-ის დაბადება
ძველად (CGI ეპოქაში), როცა სერვერს დინამიკური გვერდის გენერირება სჭირდებოდა, ის აკეთებდა უსაშველოდ ძვირადღირებულ ოპერაციას: თითოეულ მოთხოვნაზე უშვებდა პითონის სრულიად ახალ პროცესს. წარმოიდგინე პითონის ინტერპრეტატორის ჩართვა, მეხსიერების გამოყოფა, ბიბლიოთეკების ჩატვირთვა, კოდის გაშვება და შემდეგ ამ პროცესის მოკვლა — და ეს ყველაფერი წამში 100-ჯერ! სერვერები ამას უბრალოდ ვერ უძლებდნენ.
სწორედ ამიტომ შეიქმნა WSGI (Web Server Gateway Interface): ერთიანი, გენიალურად მარტივი სტანდარტი.
როგორ მუშაობს Gunicorn რეალურად?
Gunicorn არის WSGI სერვერი, რომელიც ორ მთავარ ფუნქციას ასრულებს:
- Master-Worker არქიტექტურა: Gunicorn-ს არ შემოაქვს პითონის კოდი ყოველ მოთხოვნაზე თავიდან. გაშვებისას იქმნება ერთი მთავარი (Master) პროცესი, რომელიც თავის მხრივ ქმნის რამდენიმე მუშას (Worker). ეს მუშები არიან პითონის პროცესები, რომლებსაც უკვე ჩატვირთული აქვთ მეხსიერებაში მთელი შენი Django პროექტი. ისინი უბრალოდ სხედან და ელოდებიან მოთხოვნებს. თუ რომელიმე მუშა გაიჭედება ან "მოკვდება", Master პროცესი წამიერად ქმნის ახალს.
- HTTP-ის პითონად თარგმნა: როცა Nginx აგზავნის დაუმუშავებელ HTTP მოთხოვნას, Gunicorn იღებს ამ ტექსტს (ჰედერებს, მეთოდებს) და ალაგებს მას პითონის სტანდარტულ ლექსიკონში (Dictionary), რომელსაც
environჰქვია. ახლა უკვე მოთხოვნა მონაცემთა სტრუქტურად იქცა, რომელზე მანიპულირებაც პითონს თავისუფლად შეუძლია.
3. Django: ბიზნეს ლოგიკის ცენტრი
Gunicorn-მა environ ლექსიკონი გადასცა Django-ს. ახლა იწყება მთავარი "ჯადოქრობა" ფრეიმვორკის შიგნით. მოთხოვნამ უნდა გაიაროს მკაცრად განსაზღვრული გზა (Pipeline):
ეტაპი 1: Middlewares (შუალედური ფენები)
სანამ მოთხოვნა რეალურ კოდამდე მივა, ის გადის ფილტრების კასკადს. თითოეულ Middleware-ს თავისი საქმე აქვს:
- SessionMiddleware — ამოწმებს, აქვს თუ არა მომხმარებელს აქტიური სესია.
- AuthenticationMiddleware — სესიის საფუძველზე მოთხოვნას აბამს კონკრეტულ User ობიექტს (ასე ხვდები შენს კოდში
request.userვინ არის). - CsrfViewMiddleware — ამოწმებს უსაფრთხოების ტოკენს, რათა თავიდან აირიდოს ჰაკერული შეტევები.
თუ რომელიმე Middleware-მა აღმოაჩინა პრობლემა (მაგალითად, მომხმარებელი არ არის ავტორიზებული), ის მოთხოვნას იქვე ბლოკავს და View-მდე საერთოდ აღარ უშვებს.
ეტაპი 2: URL მარშრუტიზაცია (URL Dispatcher)
თუ ფილტრები წარმატებით გაიარა, Django იღებს მოთხოვნის მისამართს (მაგ. /articles/2026/) და იწყებს მის ძებნას urls.py ფაილში. ის იყენებს რეგულარულ გამოსახულებებს (Regex) ან Path კონვერტორებს, რათა იპოვოს ზუსტად ის პითონის ფუნქცია ან კლასი (View), რომელიც ამ კონკრეტულ მისამართზეა მიბმული.
ეტაპი 3: Views და ORM
ეს არის შენი დაწერილი კოდის ეპიცენტრი. View არის ფუნქცია, რომელიც იღებს ინფორმაციას და წყვეტს, რა უნდა გააკეთოს:
- ის უკავშირდება ORM (Object-Relational Mapping) სისტემას.
- შენ წერ პითონის კოდს:
Article.objects.get(id=1). - ORM ამ პითონის კოდს ავტომატურად თარგმნის რთულ, ოპტიმიზებულ SQL მოთხოვნად.
- აგზავნის SQL-ს მონაცემთა ბაზაში (მაგ. PostgreSQL).
- ბაზიდან დაბრუნებულ ნედლ მონაცემებს ORM ისევ პითონის ობიექტებად გარდაქმნის და აწვდის View-ს.
ეტაპი 4: Response-ის ფორმირება
View იღებს ამ მონაცემებს და რთავს მათ HTML თემფლეითში (ან თუ API-ს წერ, აფორმატებს JSON-ად). ბოლოს, Django ამ ყველაფერს ფუთავს სპეციალურ HttpResponse ობიექტში, რომელშიც განთავსებულია სტატუსის კოდი (მაგ. 200 OK), შესაბამისი ჰედერები და თავად კონტენტი.
4. უკან დაბრუნების გზა
ახლა სისტემა იწყებს საპირისპირო მიმართულებით მოძრაობას, ოღონდ ბევრად სწრაფად:
- Django თავის
HttpResponseობიექტს უბრუნებს Gunicorn-ს. - Gunicorn ამ პითონის ობიექტს შლის და სტანდარტულ HTTP ტექსტად (მანქანურ ენად) თარგმნის.
- გადასცემს Nginx-ს.
- Nginx ამზადებს პაკეტებს და უსწრაფესად აგზავნის მომხმარებლის ბრაუზერში.
ბრაუზერი კითხულობს მიღებულ HTML-ს, ხედავს, რომ სჭირდება CSS და სურათები, და ხელახლა აგზავნის მოთხოვნებს ამ ფაილებზე. ამჯერად, Nginx უკვე პირდაპირ დისკიდან აწვდის მათ, Django-ს გაღვიძების გარეშე.
ეს კომპლექსური, მრავალშრიანი ჯაჭვი არის ზუსტად ის, რაც საშუალებას გვაძლევს ავაშენოთ საიტები, რომლებიც ერთდროულად მასშტაბურიცაა, უსაფრთხოც და მაქსიმალურად სწრაფიც.
P.S. ამ სტატიაში განვიხილეთ მაღალი დონის არქიტექტურა და ის, თუ რა ხდება კულისებში. თუმცა, როგორც ნებისმიერ ტექნოლოგიაში, ნამდვილი სწავლა პრაქტიკიდან იწყება. თუ გაინტერესებს, ტექნიკურად როგორ უნდა გამართო და დააკავშირო Nginx, Gunicorn, Django და PostgreSQL, ინტერნეტში ერთ-ერთი საუკეთესო რესურსი DigitalOcean-ის ეს სტატიაა. ეს არის იდეალური საწყისი წერტილი შენი აპლიკაციის რეალურ სამყაროში გასაშვებად.
ავტორის შესახებ
გიგი ჩაკაბერია
backend დეველოპერი და მენტორი