Μετάβαση στο περιεχόμενο
EuroVPSEuroVPS
Περιοχή πελατών

Γιατί μια VM μεγαλύτερη από ένα CPU socket είναι συχνά πιο αργή

Πώς δουλεύει το NUMA σε host δύο sockets, γιατί μια VM που απλώνεται και στα δύο πληρώνει σε κάθε πρόσβαση μνήμης, και πώς διαστασιολογείτε σωστά.

Από EuroVPS Engineering

5 λεπτά ανάγνωσης
Why a VM bigger than one CPU socket is often slower

Όταν μια εικονική μηχανή είναι αργή, το αντανακλαστικό είναι να της δώσετε περισσότερους πυρήνες. Σε έναν σύγχρονο server δύο sockets υπάρχει ένα σημείο όπου αυτό το αντανακλαστικό στρέφεται εναντίον σας, και η μεγαλύτερη VM τρέχει πιο αργά από τη μικρότερη που αντικατέστησε. Το σημείο είναι το μέγεθος ενός CPU socket, και ο λόγος λέγεται NUMA.

Τι είναι το NUMA, σε μία παράγραφο

Ένας server με δύο επεξεργαστές είναι στην πραγματικότητα δύο υπολογιστές που μοιράζονται μια γέφυρα. Κάθε socket έχει τους δικούς του memory controllers και τη δική του συστοιχία μνήμης συνδεδεμένη απευθείας πάνω του. Ένας πυρήνας που διαβάζει μνήμη συνδεδεμένη στο δικό του socket την παίρνει με τοπική ταχύτητα. Ένας πυρήνας που διαβάζει μνήμη συνδεδεμένη στο άλλο socket πρέπει να διασχίσει το interconnect ανάμεσα στα sockets, και αυτή η πρόσβαση είναι πιο αργή. Αυτή η διάταξη είναι η μη ομοιόμορφη πρόσβαση μνήμης: κάθε πυρήνας φτάνει σε όλη τη μνήμη, αλλά όχι με το ίδιο κόστος. Κάθε socket με τη μνήμη του είναι ένας κόμβος NUMA.

Γιατί η διάσχιση του ορίου κοστίζει περισσότερο από όσο φαίνεται

Μια απομακρυσμένη πρόσβαση μνήμης παίρνει περίπου 1,7 φορές τον χρόνο μιας τοπικής. Αυτό από μόνο του είναι μεγάλη ποινή για οτιδήποτε αγγίζει τη μνήμη συχνά, δηλαδή σχεδόν τα πάντα. Και δεν είναι όλος ο λογαριασμός:

  • Συνοχή cache. Τα δύο sockets πρέπει να κρατούν τα caches τους συνεπή. Όταν threads και στις δύο πλευρές δουλεύουν στα ίδια δεδομένα, οι γραμμές cache αναπηδούν μέσα από το interconnect, και κάθε αναπήδηση είναι ένα stall.
  • Κορεσμός του interconnect. Ο σύνδεσμος ανάμεσα στα sockets έχει πεπερασμένο bandwidth. Μια απασχολημένη VM απλωμένη και στα δύο sockets ανταγωνίζεται για αυτόν με ό,τι άλλο τρέχει στον host.
  • Χρονοπρογραμματισμός. Μια VM της οποίας τα vCPU δεν μπορούν να τρέξουν όλα μαζί σε ένα socket περιμένει τον hypervisor να βρει χώρο και στα δύο, και τα threads της προσγειώνονται όπου υπάρχει χώρος, συχνά μακριά από τα δεδομένα τους.

Αυτές οι επιδράσεις πολλαπλασιάζονται αντί να προστίθενται. Ένας φόρτος εργασίας που θα κλιμακωνόταν ωραία μέσα σε ένα socket μπορεί να χάσει μεγάλο μέρος της απόδοσής του μόλις απλωθεί σε δύο, και οι επιπλέον πυρήνες που προσθέσατε πληρώνουν για το προνόμιο.

Διαβάστε την τοπολογία του host σας

Πριν διαστασιολογήσετε οτιδήποτε, δείτε τι έχει πραγματικά ο host:

lscpu | grep -E 'Socket|Core|Thread|NUMA'
numactl --hardware

Τυπική έξοδος σε host δύο sockets:

Thread(s) per core:  2
Core(s) per socket:  18
Socket(s):           2
NUMA node(s):        2
NUMA node0 CPU(s):   0-17,36-53
NUMA node1 CPU(s):   18-35,54-71

Οι αριθμοί που μετράνε είναι οι πυρήνες ανά socket και η μνήμη ανά κόμβο, που το numactl --hardware τυπώνει μαζί με έναν πίνακα αποστάσεων. Οι αποστάσεις δείχνουν πόσο περισσότερο κοστίζει μια απομακρυσμένη πρόσβαση από μια τοπική σε αυτό ακριβώς το μηχάνημα.

Διαστασιολογήστε με βάση τους φυσικούς πυρήνες, όχι τα hyper-threads.

Οι δύο κανόνες διαστασιολόγησης

Από την τοπολογία προκύπτουν δύο κανόνες που δηλώνονται εύκολα και αξίζει να μην παραβιάζονται ποτέ:

  1. Μια VM δεν παίρνει ποτέ περισσότερα vCPU από όσους φυσικούς πυρήνες έχει ένα socket. Αφήστε περιθώριο για τον ίδιο τον hypervisor, ώστε σε socket δεκαοκτώ πυρήνων ένα λογικό ταβάνι είναι δυο πυρήνες πιο κάτω.
  2. Μια VM δεν παίρνει ποτέ περισσότερη μνήμη από όση εξυπηρετεί ένας κόμβος NUMA. Αλλιώς μέρος της μνήμης της είναι απομακρυσμένο εκ κατασκευής, ό,τι κι αν κάνει ο scheduler.

Μια VM που χωράει και στους δύο κανόνες μπορεί να ζει ολόκληρη μέσα σε έναν κόμβο, και ένας καλός hypervisor θα την κρατήσει εκεί.

Ελέγξτε πού ζει πραγματικά μια VM που τρέχει

Σε host KVM μπορείτε να δείτε πώς είναι απλωμένη η μνήμη ενός guest στους κόμβους:

numastat -c qemu-kvm
virsh vcpuinfo <vm-name>
virsh numatune <vm-name>

Αν το numastat δείχνει μια μεγάλη VM με σημαντική μνήμη και στους δύο κόμβους, πληρώνει την ποινή απομακρυσμένης πρόσβασης σε μέρος της δουλειάς της. Μέσα σε guest Linux, τα lscpu και numactl --hardware δείχνουν την τοπολογία που της παρουσιάζει ο hypervisor.

Όταν ένα socket πραγματικά δεν αρκεί

Κάποιοι φόρτοι εργασίας χρειάζονται πράγματι περισσότερα από όσα δίνει ένα socket. Υπάρχουν καλύτερες απαντήσεις από μία γιγάντια VM:

  • Scale out. Δύο VM που χωρούν η καθεμία σε έναν κόμβο, πίσω από load balancer ή ως μέλη cluster, συνήθως νικούν μία VM απλωμένη και στα δύο.
  • Διορθώστε πρώτα το σημείο συμφόρησης. Μια VM που μοιάζει να χρειάζεται περισσότερους πυρήνες συχνά περιμένει storage, locks ή ένα μοναδικό απασχολημένο thread. Η προσθήκη πυρήνων σε φόρτο που δεν μπορεί να τους χρησιμοποιήσει δεν αλλάζει τίποτα εκτός από την ποινή NUMA.
  • Αν πρέπει να είναι μεγάλη, κάντε την NUMA-aware. Παρουσιάστε στον guest μια εικονική τοπολογία που καθρεφτίζει τον host, δύο εικονικούς κόμβους που αντιστοιχούν στους δύο φυσικούς, και καρφώστε κάθε εικονικό κόμβο στον φυσικό του. Ένα λειτουργικό σύστημα και μια εφαρμογή που γνωρίζουν το NUMA μπορούν τότε να κρατούν τα threads κοντά στα δεδομένα τους. Οι enterprise διαχειριστές KVM, το OLVM ανάμεσά τους, εκθέτουν NUMA pinning γι' αυτό.

Το μεγαλύτερο δεν είναι γραμμικά γρηγορότερο έτσι κι αλλιώς

Ακόμη και μέσα σε ένα socket, ο διπλασιασμός των vCPU σπάνια διπλασιάζει την απόδοση. Μέρη κάθε φόρτου είναι σειριακά, τα locks γίνονται πιο απασχολημένα καθώς τα threads πολλαπλασιάζονται, τα caches είναι κοινόχρηστα, και ο hypervisor χρειάζεται περισσότερη προσπάθεια για να χρονοπρογραμματίσει μια πλατιά VM. Ο διπλασιασμός συνήθως αξίζει ένα κλάσμα του διπλασιασμού, και πέρα από το όριο του socket μπορεί να γίνει αρνητικός. Ο ειλικρινής τρόπος διαστασιολόγησης είναι να τρέξετε τον πραγματικό φόρτο σε δύο μεγέθη και να μετρήσετε. Η μικρότερη VM κερδίζει πιο συχνά από όσο περιμένει ο κόσμος.

Πώς το κάνουμε εμείς

Στα private clouds μας με OLVM και σε κάθε άλλη πλατφόρμα που λειτουργούμε, και οι δύο κανόνες εφαρμόζονται σε κάθε VM: ποτέ περισσότερα vCPU από όσους πυρήνες έχει ένα φυσικό socket, ποτέ περισσότερη μνήμη από όση εξυπηρετεί ένας κόμβος NUMA, διαστασιολογημένα από την πραγματική τοπολογία του host. Διαστασιολογούμε ακριβώς σε ό,τι χρειάζεται ο φόρτος εργασίας αντί να στρογγυλοποιούμε προς τα πάνω.

Αν οι VM σας διαστασιολογήθηκαν με εικασίες, ή απλώς μεγάλωσαν ένα αίτημα τη φορά, ευχαρίστως να δούμε μαζί σας την τοπολογία και τους αριθμούς.

Μιλήστε με έναν μηχανικό

Related (rows[1])

Σχετικά: Private cloud σε KVM με OLVM · Μηχανική επιδόσεων και χωρητικότητας · Dedicated cloud σε Apache CloudStack, στις προδιαγραφές σας

Δημοσιεύθηκε 10 Σεπτεμβρίου 2026.

Όλες οι σημειώσεις