Επιτάχυνση υποδοχών PHP για Tarantool χρησιμοποιώντας Async, Swoole και Parallel

Επιτάχυνση υποδοχών PHP για Tarantool χρησιμοποιώντας Async, Swoole και Parallel

Στο οικοσύστημα PHP υπάρχουν αυτήν τη στιγμή δύο σύνδεσμοι για εργασία με τον διακομιστή Tarantool - αυτή είναι η επίσημη επέκταση PECL tarantool/tarantool-php, γραμμένο σε C, και tarantool-php/client, γραμμένο σε PHP. Είμαι ο συγγραφέας του τελευταίου.

Σε αυτό το άρθρο, θα ήθελα να μοιραστώ τα αποτελέσματα των δοκιμών απόδοσης και των δύο βιβλιοθηκών και να δείξω πώς, με ελάχιστες αλλαγές στον κώδικα, μπορείτε να επιτύχετε αύξηση απόδοσης 3-5 (σε συνθετικές δοκιμές!).

Τι θα δοκιμάσουμε;

Θα δοκιμάσουμε αυτά που αναφέρθηκαν παραπάνω σύγχρονος συνδέσεις που λειτουργούν ασύγχρονα, παράλληλα και ασύγχρονα-παράλληλα. 🙂 Επίσης, δεν θέλουμε να αγγίξουμε τον κωδικό των ίδιων των συνδέσμων. Αυτήν τη στιγμή υπάρχουν πολλές διαθέσιμες επεκτάσεις για να πετύχετε αυτό που θέλετε:

  • Swoole ― ένα ασύγχρονο πλαίσιο υψηλής απόδοσης για PHP. Χρησιμοποιείται από τέτοιους γίγαντες του Διαδικτύου όπως η Alibaba και η Baidu. Από την έκδοση 4.1.0 εμφανίστηκε μια μαγική μέθοδος SwooleRuntime::enableCoroutine(), το οποίο σας επιτρέπει να "μετατρέπετε τις σύγχρονες βιβλιοθήκες δικτύου PHP σε ασύγχρονες με μία γραμμή κώδικα."
  • Το Async ήταν μέχρι πρόσφατα μια πολλά υποσχόμενη επέκταση για ασύγχρονη εργασία στην PHP. Γιατί μέχρι πρόσφατα; Δυστυχώς, για άγνωστο σε μένα λόγο, ο συγγραφέας διέγραψε το αποθετήριο και η μελλοντική τύχη του έργου είναι ασαφής. Θα πρέπει να το χρησιμοποιήσω ένα από πιρούνια. Όπως και το Swoole, αυτή η επέκταση σάς επιτρέπει να ανοίγετε εύκολα το παντελόνι σας με μια κίνηση του καρπού για να ενεργοποιήσετε τον ασύγχρονο αντικαθιστώντας την τυπική υλοποίηση των ροών TCP και TLS με τις ασύγχρονες εκδόσεις τους. Αυτό γίνεται μέσω της επιλογής "async.tcp = 1".
  • Παράλληλο ― μια αρκετά νέα επέκταση από τον γνωστό Joe Watkins, συγγραφέα τέτοιων βιβλιοθηκών όπως phpdbg, apcu, pthreads, pcov, uopz. Η επέκταση παρέχει ένα API για multithreading στην PHP και τοποθετείται ως αντικατάσταση των pthreads. Ένας σημαντικός περιορισμός της βιβλιοθήκης είναι ότι λειτουργεί μόνο με την έκδοση ZTS (Zend Thread Safe) της PHP.

Πώς θα κάνουμε δοκιμή;

Ας ξεκινήσουμε μια παρουσία Tarantool με απενεργοποιημένη καταγραφή εγγραφής (wal_mode = κανένας) και αυξημένο buffer δικτύου (readahead = 1 * 1024 * 1024). Η πρώτη επιλογή θα εξαλείψει την εργασία με το δίσκο, η δεύτερη θα επιτρέψει την ανάγνωση περισσότερων αιτημάτων από την προσωρινή μνήμη του λειτουργικού συστήματος και έτσι θα ελαχιστοποιήσει τον αριθμό των κλήσεων συστήματος.

Για δείκτες αναφοράς που λειτουργούν με δεδομένα (εισαγωγή, διαγραφή, ανάγνωση, κ.λπ.), πριν από την έναρξη του σημείου αναφοράς, θα (επανα)δημιουργηθεί ένας χώρος memtx, στον οποίο οι κύριες τιμές ευρετηρίου δημιουργούνται από μια γεννήτρια διατεταγμένων ακεραίων τιμών ​(ακολουθία).
Το space DDL μοιάζει με αυτό:

space = box.schema.space.create(config.space_name, {id = config.space_id, temporary = true})
space:create_index('primary', {type = 'tree', parts = {1, 'unsigned'}, sequence = true})
space:format({{name = 'id', type = 'unsigned'}, {name = 'name', type = 'string', is_nullable = false}})

Εάν είναι απαραίτητο, πριν εκτελέσετε το σημείο αναφοράς, ο χώρος γεμίζει με 10,000 πλειάδες της φόρμας

{id, "tuplе_<id>"}

Η πρόσβαση στις πλειάδες γίνεται χρησιμοποιώντας μια τυχαία τιμή κλειδιού.

Το ίδιο το σημείο αναφοράς είναι ένα μόνο αίτημα προς τον διακομιστή, το οποίο εκτελείται 10,000 φορές (επαναστάσεις), οι οποίες, με τη σειρά τους, εκτελούνται σε επαναλήψεις. Οι επαναλήψεις επαναλαμβάνονται έως ότου όλες οι χρονικές αποκλίσεις μεταξύ 5 επαναλήψεων είναι εντός ενός αποδεκτού σφάλματος 3%*. Μετά από αυτό, λαμβάνεται το μέσο αποτέλεσμα. Υπάρχει μια παύση 1 δευτερολέπτου μεταξύ των επαναλήψεων για να αποτραπεί ο στραγγαλισμός του επεξεργαστή. Ο συλλέκτης σκουπιδιών του Lua απενεργοποιείται πριν από κάθε επανάληψη και αναγκάζεται να ξεκινήσει αφού ολοκληρωθεί. Η διαδικασία PHP εκκινείται μόνο με τις επεκτάσεις που είναι απαραίτητες για το σημείο αναφοράς, με ενεργοποιημένη την προσωρινή μνήμη εξόδου και απενεργοποιημένο τον συλλέκτη απορριμμάτων.

* Ο αριθμός των περιστροφών, των επαναλήψεων και το όριο σφάλματος μπορούν να αλλάξουν στις ρυθμίσεις συγκριτικής αξιολόγησης.

Περιβάλλον δοκιμής

Τα αποτελέσματα που δημοσιεύονται παρακάτω έγιναν σε MacBookPro (2015), λειτουργικό σύστημα - Fedora 30 (έκδοση πυρήνα 5.3.8-200.fc30.x86_64). Το Tarantool ξεκίνησε στο docker με την παράμετρο "--network host".

Εκδόσεις πακέτου:

Tarantool: 2.3.0-115-g5ba5ed37e
Docker: 19.03.3, build a872fc2f86
PHP: 7.3.11 (cli) (κατασκευή: 22 Οκτωβρίου 2019 08:11:04)
tarantool/πελάτης: 0.6.0
rybakit/msgpack: 0.6.1
ext-tarantool: 0.3.2 (+ patch για 7.3)*
ext-msgpack: 2.0.3
ext-async: 0.3.0-8c1da46
ακραίο: 4.4.12
εξωπαράλληλος: 1.1.3

* Δυστυχώς, η επίσημη σύνδεση δεν λειτουργεί με την έκδοση PHP > 7.2. Για να μεταγλωττίσω και να εκτελέσω την επέκταση σε PHP 7.3, έπρεπε να χρησιμοποιήσω κηλίδα.

Ευρήματα

Σύγχρονη λειτουργία

Το πρωτόκολλο Tarantool χρησιμοποιεί μια δυαδική μορφή Πακέτο μηνυμάτων για σειριοποίηση μηνυμάτων. Στην υποδοχή PECL, η σειριοποίηση είναι κρυμμένη βαθιά στα βάθη της βιβλιοθήκης και επηρεάζει τη διαδικασία κωδικοποίησης από τον κώδικα της χώρας χρήστη δεν φαίνεται δυνατό. Ένας καθαρός σύνδεσμος PHP, αντίθετα, παρέχει τη δυνατότητα προσαρμογής της διαδικασίας κωδικοποίησης επεκτείνοντας τον τυπικό κωδικοποιητή ή χρησιμοποιώντας τη δική σας υλοποίηση. Υπάρχουν δύο κωδικοποιητές διαθέσιμοι εκτός συσκευασίας, ο ένας βασίζεται σε msgpack/msgpack-php (επίσημη επέκταση MessagePack PECL), η άλλη είναι ενεργοποιημένη rybakit/msgpack (σε καθαρή PHP).

Πριν συγκρίνουμε τις συνδέσεις, θα μετρήσουμε την απόδοση των κωδικοποιητών MessagePack για την υποδοχή PHP και σε περαιτέρω δοκιμές θα χρησιμοποιήσουμε αυτήν που δείχνει το καλύτερο αποτέλεσμα:

Επιτάχυνση υποδοχών PHP για Tarantool χρησιμοποιώντας Async, Swoole και Parallel
Αν και η έκδοση PHP (Pure) είναι κατώτερη από την επέκταση PECL σε ταχύτητα, σε πραγματικά έργα θα συνιστούσα να τη χρησιμοποιήσετε rybakit/msgpack, επειδή στην επίσημη επέκταση MessagePack η προδιαγραφή μορφής εφαρμόζεται μόνο εν μέρει (για παράδειγμα, δεν υπάρχει υποστήριξη για προσαρμοσμένους τύπους δεδομένων, χωρίς τους οποίους δεν θα μπορείτε να χρησιμοποιήσετε το Decimal - έναν νέο τύπο δεδομένων που εισήχθη στο Tarantool 2.3) και έχει αριθμός άλλων πρόβλημα (συμπεριλαμβανομένων ζητημάτων συμβατότητας με την PHP 7.4). Λοιπόν, γενικά, το έργο φαίνεται εγκαταλελειμμένο.

Λοιπόν, ας μετρήσουμε την απόδοση των συνδέσμων σε σύγχρονη λειτουργία:

Επιτάχυνση υποδοχών PHP για Tarantool χρησιμοποιώντας Async, Swoole και Parallel
Όπως φαίνεται από το γράφημα, ο σύνδεσμος PECL (Tarantool) παρουσιάζει καλύτερη απόδοση σε σύγκριση με τον σύνδεσμο PHP (Πελάτης). Αλλά αυτό δεν προκαλεί έκπληξη, δεδομένου ότι η τελευταία, εκτός του ότι υλοποιείται σε πιο αργή γλώσσα, στην πραγματικότητα κάνει περισσότερη δουλειά: δημιουργείται ένα νέο αντικείμενο με κάθε κλήση Αίτημα и Απάντηση (στην περίπτωση του Select - επίσης Κριτήρια, και στην περίπτωση Ενημέρωση/Ενημέρωση ― λειτουργίες), ξεχωριστές οντότητες σύνδεση, Συσκευαστής и Handler προσθέτουν επίσης γενικά έξοδα. Προφανώς, η ευελιξία έχει ένα τίμημα. Ωστόσο, γενικά, ο διερμηνέας PHP δείχνει καλή απόδοση, αν και υπάρχει μια διαφορά, είναι ασήμαντη και, ίσως, θα είναι ακόμη μικρότερη κατά τη χρήση προφόρτωσης στην PHP 7.4, για να μην αναφέρουμε το JIT στην PHP 8.

Ας προχωρήσουμε. Το Tarantool 2.0 πρόσθεσε υποστήριξη για SQL. Ας προσπαθήσουμε να εκτελέσουμε τις λειτουργίες Select, Insert, Update και Delete χρησιμοποιώντας το πρωτόκολλο SQL και να συγκρίνουμε τα αποτελέσματα με τα noSQL (δυαδικά) ισοδύναμα:

Επιτάχυνση υποδοχών PHP για Tarantool χρησιμοποιώντας Async, Swoole και Parallel
Τα αποτελέσματα της SQL δεν είναι πολύ εντυπωσιακά (να σας υπενθυμίσω ότι ακόμα δοκιμάζουμε τη σύγχρονη λειτουργία). Ωστόσο, δεν θα εκνευριζόμουν για αυτό εκ των προτέρων· η υποστήριξη SQL εξακολουθεί να αναπτύσσεται ενεργά (σχετικά πρόσφατα, για παράδειγμα, προστέθηκε υποστήριξη έτοιμες δηλώσεις) και, αν κρίνουμε από τη λίστα θέματα, η μηχανή SQL θα υποβληθεί σε διάφορες βελτιστοποιήσεις στο μέλλον.

Ασύγ

Λοιπόν, τώρα ας δούμε πώς η επέκταση Async μπορεί να μας βοηθήσει να βελτιώσουμε τα παραπάνω αποτελέσματα. Για τη σύνταξη ασύγχρονων προγραμμάτων, η επέκταση παρέχει ένα API βασισμένο σε κορουτίνες, το οποίο θα χρησιμοποιήσουμε. Ανακαλύπτουμε εμπειρικά ότι ο βέλτιστος αριθμός κορουτινών για το περιβάλλον μας είναι 25:

Επιτάχυνση υποδοχών PHP για Tarantool χρησιμοποιώντας Async, Swoole και Parallel
Διαδώστε 10,000 λειτουργίες σε 25 κορουτίνες και δείτε τι συμβαίνει:

Επιτάχυνση υποδοχών PHP για Tarantool χρησιμοποιώντας Async, Swoole και Parallel
Ο αριθμός των λειτουργιών ανά δευτερόλεπτο αυξήθηκε κατά περισσότερο από 3 φορές για tarantool-php/client!

Δυστυχώς, η υποδοχή PECL δεν ξεκίνησε με ext-async.

Τι γίνεται με την SQL;

Επιτάχυνση υποδοχών PHP για Tarantool χρησιμοποιώντας Async, Swoole και Parallel
Όπως μπορείτε να δείτε, στην ασύγχρονη λειτουργία η διαφορά μεταξύ του δυαδικού πρωτοκόλλου και της SQL έγινε εντός του περιθωρίου σφάλματος.

Swoole

Και πάλι ανακαλύπτουμε τον βέλτιστο αριθμό κορουτινών, αυτή τη φορά για τον Swoole:
Επιτάχυνση υποδοχών PHP για Tarantool χρησιμοποιώντας Async, Swoole και Parallel
Ας σταματήσουμε στο 25. Ας επαναλάβουμε το ίδιο κόλπο με την επέκταση Async - κατανείμετε 10,000 πράξεις μεταξύ 25 κορουτίνες. Επιπλέον, θα προσθέσουμε ένα άλλο τεστ στο οποίο θα χωρίσουμε όλη την εργασία σε 2 δύο διεργασίες (δηλαδή κάθε διεργασία θα εκτελεί 5,000 πράξεις σε 25 κορουτίνες). Οι διαδικασίες θα δημιουργηθούν χρησιμοποιώντας SwooleProcess.

Αποτελέσματα:

Επιτάχυνση υποδοχών PHP για Tarantool χρησιμοποιώντας Async, Swoole και Parallel
Το Swole δείχνει ελαφρώς χαμηλότερο αποτέλεσμα σε σύγκριση με το Async όταν εκτελείται σε μία διαδικασία, αλλά με 2 διεργασίες η εικόνα αλλάζει δραματικά (ο αριθμός 2 δεν επιλέχθηκε τυχαία· στο μηχάνημά μου, ήταν 2 διεργασίες που έδειξαν το καλύτερο αποτέλεσμα).

Παρεμπιπτόντως, η επέκταση Async έχει επίσης ένα API για εργασία με διεργασίες, αλλά εκεί δεν παρατήρησα καμία διαφορά από την εκτέλεση σημείων αναφοράς σε μία ή περισσότερες διεργασίες (είναι πιθανό να μπέρδεψα κάπου).

SQL έναντι δυαδικού πρωτοκόλλου:

Επιτάχυνση υποδοχών PHP για Tarantool χρησιμοποιώντας Async, Swoole και Parallel
Όπως και με το Async, η διαφορά μεταξύ δυαδικών και λειτουργιών SQL εξαλείφεται στην ασύγχρονη λειτουργία.

Παράλληλο

Επειδή η επέκταση Parallel δεν αφορά κορουτίνες, αλλά για νήματα, ας μετρήσουμε τον βέλτιστο αριθμό παράλληλων νημάτων:

Επιτάχυνση υποδοχών PHP για Tarantool χρησιμοποιώντας Async, Swoole και Parallel
Είναι ίσο με 16 στο μηχάνημά μου. Ας εκτελέσουμε συγκριτικά κριτήρια σύνδεσης σε 16 παράλληλα νήματα:

Επιτάχυνση υποδοχών PHP για Tarantool χρησιμοποιώντας Async, Swoole και Parallel
Όπως μπορείτε να δείτε, το αποτέλεσμα είναι ακόμα καλύτερο από ό,τι με τις ασύγχρονες επεκτάσεις (χωρίς να υπολογίζουμε το Swoole που εκτελείται σε 2 διεργασίες). Σημειώστε ότι για την υποδοχή PECL, οι λειτουργίες Update και Upsert είναι κενές. Αυτό οφείλεται στο γεγονός ότι αυτές οι λειτουργίες απέτυχαν με ένα σφάλμα - δεν ξέρω αν έφταιγε το ext-parallel, το ext-tarantool ή και τα δύο.

Τώρα ας συγκρίνουμε την απόδοση της SQL:

Επιτάχυνση υποδοχών PHP για Tarantool χρησιμοποιώντας Async, Swoole και Parallel
Παρατηρήστε την ομοιότητα με το γράφημα για τις συνδέσεις που λειτουργούν συγχρονισμένα;

Μαζί

Και τέλος, ας συνοψίσουμε όλα τα αποτελέσματα σε ένα γράφημα για να δούμε τη συνολική εικόνα για τις δοκιμασμένες επεκτάσεις. Ας προσθέσουμε μόνο μια νέα δοκιμή στο γράφημα, την οποία δεν έχουμε κάνει ακόμα - ας εκτελέσουμε παράλληλα τις κορουτίνες Async χρησιμοποιώντας το Parallel*. Η ιδέα της ενσωμάτωσης των παραπάνω επεκτάσεων είναι ήδη συζητήθηκε συγγραφείς, αλλά δεν επιτεύχθηκε συναίνεση, θα πρέπει να το κάνετε μόνοι σας.

* Δεν ήταν δυνατή η εκκίνηση των κορουτινών Swoole με το Parallel· φαίνεται ότι αυτές οι επεκτάσεις δεν είναι συμβατές.

Λοιπόν, τα τελικά αποτελέσματα:

Επιτάχυνση υποδοχών PHP για Tarantool χρησιμοποιώντας Async, Swoole και Parallel

Αντί για ένα συμπέρασμα

Κατά τη γνώμη μου, τα αποτελέσματα αποδείχθηκαν αρκετά άξια και για κάποιο λόγο είμαι σίγουρος ότι αυτό δεν είναι το όριο! Είτε πρέπει να το αποφασίσετε σε ένα πραγματικό έργο αποκλειστικά για τον εαυτό σας, θα πω μόνο ότι για μένα ήταν ένα ενδιαφέρον πείραμα που σας επιτρέπει να αξιολογήσετε πόσα μπορείτε να «συμπιέσετε» από μια σύγχρονη σύνδεση TCP με ελάχιστη προσπάθεια. Εάν έχετε ιδέες για τη βελτίωση των σημείων αναφοράς, θα χαρώ να εξετάσω το αίτημά σας για έλξη. Όλος ο κώδικας με οδηγίες εκκίνησης και αποτελέσματα δημοσιεύεται σε ξεχωριστό αποθετήρια.

Πηγή: www.habr.com

Προσθέστε ένα σχόλιο