Βασικό configuration και βέλτιστες ρυθμίσεις του Nginx web server


Σε αυτό το άρθρο θα μιλήσουμε για βασικές ρυθμίσεις που πρέπει να κάνουμε στον Nginx. Οι ρυθμίσεις αυτές έχουν περισσότερο την έννοια του optimization, παρά του configuration, καθώς ο Nginx έρχεται pretty much configured, οπότε εδώ θα μιλήσουμε τις βέλτιστες ρυθμίσεις.

Φαντάζομαι ότι έχετε ήδη διαβάσει τους δύο προηγούμενους οδηγούς για το στήσιμο web server με Nginx:

Για να κάνω μία εισαγωγή, θα μιλήσουμε για πράγματα όπως: πόση μνήμη έχουμε διαθέσιμη, πόσους πυρήνες (cpu) θα διαθέσουμε, και πώς αυτά θα επιδράσουν στον συνολικό αριθμό των processes,threads, κ.α. πραγμάτων που σχετίζονται με τους πόρους και την λειτουργία του Nginx στο σύστημά μας. Τονίζω το «σύστημά μας» γιατί ο σκοπός μου δεν είναι να σας δώσω έτοιμο το /etc/nginx/nginx.conf αλλά να σας δείξω ποιες ρυθμίσεις είναι common use και ποιες χρειάζονται λίγο tweaking από την πλευρά σας.

Πάμε λοιπόν …

egkatastasi-nginx-linux

Αρχείο ρυθμίσεων 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 για τους οποίους θα μιλήσουμε:

  1. Client Buffer Body Size: Αυτό έχει να κάνει συνήθως με τις post actions. Όσοι γνωρίζετε HTML το μυαλό σας πολύ σωστά έχει πάει σε html forms ή buttons.
  2. Client Header Buffer Size: Ακριβώς το ίδιο, αλλά μόνο για τον header. Μία λογική τιμή που προτείνουν εδώ οι ειδικοί είναι 1024.
  3. Client Max Body Buffer: Είναι το μέγιστο επιτρεπόμενο μέγεθος για client request. Αν λοιπόν υπερβούμε αυτό το όριο, ο Nginx θα πετάξει ένα 413 Error – Request entity too larget.
  4. 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 μηχανή σένα αργό πεισματάρικο γαϊδουράκι. Εδώ έχουμε:

  1. Client Body Timeout
  2. Client Header Timeout
  3. Keepalive Timeout
  4. Send Timeout

και τα θέτω ως εξής:

    client_body_timeout 12;
    client_header_timeout 12;
    keepalive_timeout 15;
    send_timeout 10;

Επίλογος

Τα παραπάνω, αποτελούν ένα τυπικό configuration για τον Nginx με μέτριο προς υψηλό traffic. Σε κάθε περίπτωση καλό είναι να μην ξεχνάτε και το παρακάτω:

Τα πρώτα 10 λεπτά σε έναν νέο Server: Βασικές ρυθμίσεις ασφάλειας

Ελπίζω να σας κίνησα το ενδιαφέρον και να ασχοληθείτε περαιτέρω με τον Nginx. Για οτιδήποτε σας απασχολεί, μπορείτε να αφήσετε μήνυμα στα σχόλια.

Advertisements

One thought on “Βασικό configuration και βέλτιστες ρυθμίσεις του Nginx web server

Σου άρεσε το άρθρο; Πες την άποψή σου... έστω και Ανώνυμα:

Εισάγετε τα παρακάτω στοιχεία ή επιλέξτε ένα εικονίδιο για να συνδεθείτε:

Λογότυπο WordPress.com

Σχολιάζετε χρησιμοποιώντας τον λογαριασμό WordPress.com. Αποσύνδεση / Αλλαγή )

Φωτογραφία Twitter

Σχολιάζετε χρησιμοποιώντας τον λογαριασμό Twitter. Αποσύνδεση / Αλλαγή )

Φωτογραφία Facebook

Σχολιάζετε χρησιμοποιώντας τον λογαριασμό Facebook. Αποσύνδεση / Αλλαγή )

Φωτογραφία Google+

Σχολιάζετε χρησιμοποιώντας τον λογαριασμό Google+. Αποσύνδεση / Αλλαγή )

Σύνδεση με %s