Σε αυτό το άρθρο θα μιλήσουμε για βασικές ρυθμίσεις που πρέπει να κάνουμε στον Nginx. Οι ρυθμίσεις αυτές έχουν περισσότερο την έννοια του optimization, παρά του configuration, καθώς ο Nginx έρχεται pretty much configured, οπότε εδώ θα μιλήσουμε τις βέλτιστες ρυθμίσεις.
Φαντάζομαι ότι έχετε ήδη διαβάσει τους δύο προηγούμενους οδηγούς για το στήσιμο web server με Nginx:
Για να κάνω μία εισαγωγή, θα μιλήσουμε για πράγματα όπως: πόση μνήμη έχουμε διαθέσιμη, πόσους πυρήνες (cpu) θα διαθέσουμε, και πώς αυτά θα επιδράσουν στον συνολικό αριθμό των processes,threads, κ.α. πραγμάτων που σχετίζονται με τους πόρους και την λειτουργία του Nginx στο σύστημά μας. Τονίζω το «σύστημά μας» γιατί ο σκοπός μου δεν είναι να σας δώσω έτοιμο το /etc/nginx/nginx.conf
αλλά να σας δείξω ποιες ρυθμίσεις είναι common use και ποιες χρειάζονται λίγο tweaking από την πλευρά σας.
Πάμε λοιπόν …
Αρχείο ρυθμίσεων Nginx
sudo vim /etc/nginx/nginx.conf
Το αρχείο με το οποίο θα ασχοληθούμε, είναι το /etc/nginx/nginx.conf
το οποίο αποτελεί το βασικό αρχείο ρυθμίσεων του Nginx. Είναι το Νο1 αρχείο στο οποίο κοιτάει ο Nginx να βρει πληροφορίες.
Μόλις το ανοίξετε, θα δείτε ένα χάος από επιλογές και μεταβλητές οι οποίες άλλες είναι ήδη defined κι άλλες είναι απλά μαρκαρισμένες ως #comment
. Μην σας πιάνει πανικός, πάμε να τις δούμε:
Worker Processes
Η μεταβλητή worker_processes
μαζί με την worker_connections
που θα δούμε στην συνέχεια, αποτελούν στην ουσία το backbone του Nginx.
Ξεκινώντας με την πρώτη, αυτό που κάνει είναι να λέει στον server (ή τον virtual server) πόσους workers να διαθέσει για ένα connection. Μόλις ολοκληρωθεί το πάρε-δώσε τον μηνυμάτων και οριστικοποιηθούν έννοιες όπως dest IP, source IP, TCP Port, UDP Port, τότε ο Nginx κάνει spawn μία στρατιά από workers οι οποίοι είναι υπεύθυνοι για κατάσταση του εκάστοτε connection.
παράδειγμα: Όταν συνδέεστε στο
localhost:80
, ο Nginx θα ψάξει να δει τι τιμή έχει η μεταβλητήworker_processes
και ανάλογα θα πράξει. Από default λοιπόν αυτή η λειτουργία αξιοποιείται στηνTCP 80
γιαhttp
protocol και στηνTCP 443
γιαssl
(μην μπερδεύεστε, τοhttps
εννοώ).
Για οποιοδήποτε άλλο socket
( Socket ονομάζουμε τον συνδυασμό IP
και port
. πχ 127.0.0.1:80
), θα πρέπει να το ρυθμίσουμε διαφορετικά ή να αγοράσουμε το εμπορικό μέρος του Nginx. Δεν είμαι όμως σίγουρος, οπότε λέω να μην σας μπλέξω με αυτό. Άλλωστε δεν νομίζω να το χρειάζεστε, εκτός κι αν έχετε κάποιο αρκετά σύνθετο configuration, όπως για παράδειγμα πολλά ethX
interfaces ή πολλά VMs σε bridge mode
.
H formula που χρησιμοποιείται ευρέως στο Internet λέει:
1 worker για κάθε core processor
Προφανώς αυτό δεν είναι πανάκεια, δηλαδή μπορεί κάποιος να πει:
«Και γιατί ρε φίλε να μην βάλω 2 workers για κάθε core; Θα πάθει κάτι; Θα χαλάσει;«.
Η απάντηση είναι, χμ, οκ δεν θα πάθει κάτι αλλά είναι bad practice, και ως side effect μπορεί να έχει κάποια connections να παραμένουν idle για αρκετό διάστημα, στα οποία όμως να σπαταλιούνται workers, άρα επεξεργαστική ισχύ. Κακή διαχείριση πόρων λοιπόν — είναι κάτι που θέλουμε να αποφύγουμε, ειδικά στην περίπτωση μου που έχω έναν μικρό Atom Processor.
Στην δική μου περίπτωση λοιπόν, στο PC που κάνω δοκιμές, γνωρίζω ότι έχω έναν Intel(R) Atom(TM) CPU N2800 @ 1.86GHz, o οποίος σύμφωνα με τα specs είναι dual core με hyper-threading. Αυτό σημαίνει ότι έχω 4 threads. Άρα, σύμφωνα με την παραπάνω formula, θα δώσω 1 worker για κάθε thread, συνεπώς:
worker_processes 4;
Στην δική σας περίπτωση, αν δεν γνωρίζετε τι επεξεργαστή τρέχετε στον server, ή το VPS, μπορείτε απλά να ρίξετε μια ματιά στο /proc/cpuinfo/
. Για κάποιον ηλίθιο λόγο, έχουν μπερδέψει την έννοια του processor
με του thread
, οπότε αρκεί να μετρήσετε πόσα instances του processor
σας εμφανίζει. Για να μάθετε να σκέφτεστε με εντολές bash, αυτό προϋποθέτει ένα cat
του αρχείου, στην συνέχεια ένα grep
του string processor
μέσω ενός |
, το οποίο στην περίπτωση μου, θα δώσε:
ns348481:~ # cat /proc/cpuinfo | grep "processor" processor : 0 processor : 1 processor : 2 processor : 3
Οπότε, είτε μετράω με το μάτι, και βλέπω 4 processors (n+1) γιατί ξεκινάει από τον «μηδέν», ή απλά ξανά κάνω pipe
και περνάω τα instances από έναν μετρητή ανά γραμμή, δηλαδή wc -l
, δηλαδή κάπως έτσι:
cat /proc/cpuinfo | grep "processor" | wc -l 4
Αν κάνω το λάθος, το παίξω άπλας, και δώσω μεγαλύτερο νούμερο, τότε για τον δικό μου server σημαίνει ότι δεσμεύω περισσότερους υπολογιστικούς πόρους από όσους πραγματικά έχω.
Τι θα γίνει λοιπόν στην περίπτωση όπου υπάρχει όντως μεγάλο load και θα χρειαστούν αυτοί οι παραπάνω πόροι (τους οποίους δήλωσα εσφαλμένα ότι έχω;) ; Πρόβλημα! Για αυτό λοιπόν, σαν καλός μηχανικός θα δώσω τον σωστό αριθμό, και θα αφήσω τα μεγάλα λόγια για τους πολιτικούς. Computers don’t lie.
Worker Connections
Η δεύτερη αλλά εξίσου σημαντική μεταβλητή, είναι η worker_connections
η οποία βρίσκεται μέσα στο events {}
structure. Το νούμερο που θα βάλουμε εδώ συμβολίζει το αριθμό των ταυτόχρονων connections.
Με άλλα λόγια, είναι το πόσοι users μπορούν να συνδεθούν ταυτόχρονα, στον server. Αν και αυτό δεν είναι απολύτως σωστό, καθώς αν και συνήθως στην θεωρία ο browser ανοίγει ένα connection, στην πράξη αυτό φαίνεται να είναι 3 ή τουλάχιστον παραπάνω από 1. By default, ο Nginx έχει ορίσει την τιμή στα 768
connections, αλλά εμείς θα θέσουμε την βέλτιστη τιμή για το σύστημά σας, την οποία θα μας δώσει η εντολή ulimit
.
Αρκετές φορές χρησιμοποιώ αυτή την εντολή, ειδικά όταν τρέχω κάποιον bug reproducer όπου γνωρίζω εκ των προτέρων ότι θα έρθω αντιμέτωπος με κάποιο segmentation fault
. Για να μπορέσω να κάνω debugging με το gdb
, θα πρέπει να ορίσω τον αριθμό τον maximum resources που μπορώ να δεσμεύσω στο σύστημα (και εδώ έρχεται η ulimit
). Σε διαφορετική, αν το σύστημα αρχίζει να τρέχει υπερβολικά πολλές processes ή να καταναλώνει υπερβολική μνήμη τότε είναι θέμα χρόνου μέχρι να γίνει το όλο πράγμα unresponsive.
Λέγοντας όλα αυτά, είναι εμφανές ότι ο Nginx θέλει να αποφύγει παρόμοια προβλήματα τα οποία θα οφείλονται σε μαζική κίνηση από έναν ή περισσότερους users. Βάζοντας μια μικρή τιμή, τότε περιορίζουμε την επισκεψημότητά μας, ενώ βάζοντας υψηλή τιμή υπερεκτιμάμε τις δυνατότητες του μηχανήματός μας. Η πιο σωστή επιλογή λοιπόν είναι να βάλουμε ακριβώς το sweet spot, το οποίο θα μας το δώσει η εκτέλεση της εντολής ulimit -n
. Στην δική μου περίπτωση, το output της εντολής είναι 1024
, οπότε πάνω στο /etc/nginx/nginx.conf
και την θέτω ως εξής:
events { worker_connections 1024; use epoll; }
Το epoll
σημαίνει efficient method for connection processing και είναι ενεργοποιημένο από default στις καινούριες Linux διανομές. Αν έχετε kernel παλιότερο από Linux 2.6+
τότε ίσως πρέπει να χρησιμοποιήσετε το απλό poll
ή τηνstandard
μέθοδο η οποία χρησιμοποιείτε σε περιπτώσει όπου υπάρχει αδυναμία χρήσης της efficient. Τώρα, αν έχετε FreeBSD, Solaris ή οτιδήποτε άλλο, περισσότερες πληροφορίες θα βρείτε εδώ.
Buffers
Αυτό που πρέπει να γνωρίζετε σχετικά με τους buffers, είναι πως αν τους θέσετε να έχουν πολύ μικρό μέγεθος, τότε ο Nginx θα αναγκαστεί να δημιουργεί τα δικά του προσωρινά αρχεία.
Αυτό σημαίνει ότι θα αρχίσει ένα «γράψε-διάβασε», το οποίο ανάλογα με τα connections, μπορεί να οδηγήσει σε ανεπιθύμητο load για το σύστημα. Όσο περισσότερο I/O κάνει ένα σύστημα, τόσο περισσότερο load προκαλεί, τόσο πιο πολύ καθυστερεί να απαντήσει σε requests
.
Υπάρχουν 4 buffers για τους οποίους θα μιλήσουμε:
- Client Buffer Body Size: Αυτό έχει να κάνει συνήθως με τις
post actions
. Όσοι γνωρίζετε HTML το μυαλό σας πολύ σωστά έχει πάει σεhtml forms
ήbuttons
. - Client Header Buffer Size: Ακριβώς το ίδιο, αλλά μόνο για τον header. Μία λογική τιμή που προτείνουν εδώ οι ειδικοί είναι 1024.
- Client Max Body Buffer: Είναι το μέγιστο επιτρεπόμενο μέγεθος για client request. Αν λοιπόν υπερβούμε αυτό το όριο, ο Nginx θα πετάξει ένα 413 Error – Request entity too larget.
- Large Client Header Buffer: Το οποίο είναι το ίδιο, αλλά για τον Header.
Πάμε λοιπόν στο http { }
section και εκεί θέτουμε:
http { ... ... client_body_buffer_size 10k; client_header_buffer_size 1k; client_max_body_size 8m; large_client_header_buffers 2 1k; ... ... }
Εδώ είναι ένα καλό σημείο να κάνουμε save και να τεστάρουμε αν το configuration έχει κάποιο λάθος (typo ή μη). Τρέχουμε λοιπόν την εντολή nginx -t
και περιμένουμε ένα output σας αυτό:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Timeouts
Τα Timeouts είναι ένα άλλο σημαντικό ζήτημα που αν δεν το λάβετε σοβαρά υπόψιν σας, μπορεί να στραγγίξει όλη την δύναμη του πανίσχυρου server σας και να τον μετατρέψει από μία High Performance μηχανή σένα αργό πεισματάρικο γαϊδουράκι. Εδώ έχουμε:
- Client Body Timeout
- Client Header Timeout
- Keepalive Timeout
- Send Timeout
και τα θέτω ως εξής:
client_body_timeout 12; client_header_timeout 12; keepalive_timeout 15; send_timeout 10;
Επίλογος
Τα παραπάνω, αποτελούν ένα τυπικό configuration για τον Nginx με μέτριο προς υψηλό traffic. Σε κάθε περίπτωση καλό είναι να μην ξεχνάτε και το παρακάτω:
Τα πρώτα 10 λεπτά σε έναν νέο Server: Βασικές ρυθμίσεις ασφάλειας
Ελπίζω να σας κίνησα το ενδιαφέρον και να ασχοληθείτε περαιτέρω με τον Nginx. Για οτιδήποτε σας απασχολεί, μπορείτε να αφήσετε μήνυμα στα σχόλια.
να προτιματε το sudoedit απο το sudo vim