Μια εισαγωγή στο Vert.x, το γρηγορότερο πλαίσιο Java σήμερα

Αν έχετε πρόσφατα κάνει χρήση του «καλύτερου πλαισίου ιστού», ίσως έχετε σκοντάψει τα σημεία αναφοράς Techempower όπου κατατάσσονται περισσότερα από τριακόσια πλαίσια. Εκεί ίσως έχετε παρατηρήσει ότι το Vert.x είναι ένα από τα κορυφαία, αν όχι το πρώτο από κάποια μέτρα.

Ας μιλήσουμε λοιπόν για αυτό.

Το Vert.x είναι ένα πλαίσιο ιστού polyglot που μοιράζεται κοινές λειτουργίες μεταξύ των υποστηριζόμενων γλωσσών Java, Kotlin, Scala, Ruby και Javascript. Ανεξάρτητα από τη γλώσσα, το Vert.x λειτουργεί στην Java Virtual Machine (JVM). Όντας αρθρωτό και ελαφρύ, προσανατολίζεται προς την ανάπτυξη μικρο-υπηρεσιών.

Τα σημεία αναφοράς Techempower μετρούν την απόδοση της ενημέρωσης, της ανάκτησης και της παράδοσης δεδομένων από μια βάση δεδομένων. Όσο περισσότερα αιτήματα προβάλλονται ανά δευτερόλεπτο, τόσο το καλύτερο. Σε ένα τέτοιο σενάριο IO όπου εμπλέκεται λίγος υπολογισμός, οποιοδήποτε πλαίσιο μη αποκλεισμού θα έχει πλεονέκτημα. Τα τελευταία χρόνια, ένα τέτοιο παράδειγμα είναι σχεδόν αδιαχώριστο από το Node.js το οποίο το διαδόθηκε με τον βρόχο γεγονότος με ένα νήμα.

Το Vert.x, όπως το Node, λειτουργεί έναν βρόχο συμβάντος. Αλλά το Vert.x εκμεταλλεύεται επίσης το JVM. Ενώ ο κόμβος λειτουργεί σε έναν μόνο πυρήνα, το Vert.x διατηρεί μια ομάδα νήματος με μέγεθος που μπορεί να ταιριάζει με τον αριθμό των διαθέσιμων πυρήνων. Με μεγαλύτερη υποστήριξη ταυτόχρονης ταυτότητας, το Vert.x είναι κατάλληλο για όχι μόνο IO, αλλά και για διεργασίες βαριάς CPU που απαιτούν παράλληλο υπολογισμό.

Οι βρόχοι γεγονότων, ωστόσο, είναι το μισό της ιστορίας. Το άλλο μισό δεν έχει καμία σχέση με το Vert.x.

Για να συνδεθείτε σε μια βάση δεδομένων, ένας πελάτης απαιτεί πρόγραμμα οδήγησης σύνδεσης. Στον τομέα Java, το πιο κοινό πρόγραμμα οδήγησης για Sql είναι το JDBC. Το πρόβλημα είναι ότι αυτό το πρόγραμμα οδήγησης αποκλείει. Και μπλοκάρει στο επίπεδο της πρίζας. Ένα νήμα θα κολλήσει πάντα εκεί μέχρι να επιστρέψει με μια απάντηση.

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

  • //github.com/jasync-sql/jasync-sql (για Postgres και MySql)
  • //github.com/reactiverse/reactive-pg-client (Postgres)

Ο χρυσός κανόνας

Το Vert.x είναι πολύ απλό στη χρήση και ένας διακομιστής http μπορεί να εμφανιστεί με μερικές γραμμές κώδικα.

Η μέθοδος requestHandler είναι όπου ο βρόχος συμβάντος παραδίδει το συμβάν αιτήματος. Καθώς το Vert.x δεν είναι γνωστό, ο χειρισμός του είναι δωρεάν στυλ. Αλλά λάβετε υπόψη τον μοναδικό βασικό κανόνα του μη αποκλεισμού νήματος: μην το αποκλείσετε.

Όταν δουλεύουμε με ταυτόχρονη πρόσβαση μπορούμε να αντλήσουμε από τόσες πολλές διαθέσιμες επιλογές σήμερα, όπως Promise, Future, Rx, καθώς και τον ιδιότυπο τρόπο του Vert.x. Όμως καθώς αυξάνεται η πολυπλοκότητα μιας εφαρμογής, δεν αρκεί μόνο η λειτουργικότητα ασύγχρονου. Χρειαζόμαστε επίσης την ευκολία του συντονισμού και της δέσμευσης κλήσεων, αποφεύγοντας παράλληλα την επιστροφή κλήσης, καθώς και τη χαριτωμένη μεταβίβαση τυχόν σφαλμάτων.

Το Scala Future πληροί όλες τις παραπάνω προϋποθέσεις με το πρόσθετο πλεονέκτημα να βασίζεται σε αρχές λειτουργικού προγραμματισμού. Αν και αυτό το άρθρο δεν διερευνά το Scala Future σε βάθος, μπορούμε να το δοκιμάσουμε με μια απλή εφαρμογή. Ας υποθέσουμε ότι η εφαρμογή είναι μια υπηρεσία API για την εύρεση ενός χρήστη με δεδομένο το αναγνωριστικό του:

Υπάρχουν τρεις λειτουργίες: έλεγχος παραμέτρου αιτήματος, έλεγχος εάν το αναγνωριστικό είναι έγκυρο και ανάκτηση των δεδομένων. Θα ολοκληρώσουμε κάθε μία από αυτές τις λειτουργίες στο μέλλον και θα συντονίσουμε την εκτέλεση σε μια δομή «για κατανόηση».

  • Το πρώτο βήμα είναι να ταιριάξετε το αίτημα με μια υπηρεσία. Το Scala έχει μια ισχυρή δυνατότητα αντιστοίχισης μοτίβων που μπορούμε να χρησιμοποιήσουμε για το σκοπό αυτό. Εδώ παρεμποδίζουμε οποιαδήποτε αναφορά του "/ χρήστη" και την περνάμε στην υπηρεσία μας.
  • Στη συνέχεια είναι ο πυρήνας αυτής της υπηρεσίας όπου τα συμβόλαια μελλοντικής εκπλήρωσης είναι διαδοχικά για κατανόηση. Ο πρώτος μελλοντικός έλεγχος παραμέτρων f1 wraps. Θέλουμε συγκεκριμένα να ανακτήσουμε το αναγνωριστικό από το αίτημα λήψης και να το μεταφέρουμε στο int. (Το Scala δεν απαιτεί ρητή επιστροφή εάν η τιμή επιστροφής είναι η τελευταία γραμμή της μεθόδου.) Όπως βλέπετε, αυτή η λειτουργία θα μπορούσε ενδεχομένως να ρίξει μια εξαίρεση, καθώς το id ενδέχεται να μην είναι int ή ακόμη και διαθέσιμο, αλλά αυτό είναι εντάξει για τώρα .
  • Το δεύτερο μελλοντικό f2 ελέγχει την εγκυρότητα του id. Αποκλείουμε οποιοδήποτε αναγνωριστικό μικρότερο από 100 καλώντας ρητά το Future.failed με τη δική μας CustomException. Διαφορετικά, περνάμε ένα κενό Future με τη μορφή Future.unit ως επιτυχημένη επικύρωση.
  • Το τελευταίο μέλλον f3 ανακτά τον χρήστη με το αναγνωριστικό που παρέχεται από το f1. Καθώς αυτό είναι απλώς ένα δείγμα, δεν συνδέουμε πραγματικά με μια βάση δεδομένων. Επιστρέφουμε απλώς μια ψεύτικη χορδή.
  • Ο χάρτης εκτελεί τη διάταξη που αποδίδει τα δεδομένα χρήστη από το f3 και στη συνέχεια τα εκτυπώνει στην απόκριση.
  • Τώρα, εάν σε οποιοδήποτε μέρος της ακολουθίας παρουσιαστεί σφάλμα, ένα Throwable μεταβιβάζεται για ανάκτηση . Εδώ μπορούμε να αντιστοιχίσουμε τον τύπο του σε μια κατάλληλη στρατηγική ανάκτησης. Ανατρέχοντας στον κώδικά μας, έχουμε προβλέψει αρκετές πιθανές αστοχίες, όπως λείπει αναγνωριστικό ή αναγνωριστικό που δεν ήταν int ή μη έγκυρο, το οποίο θα επέφερε συγκεκριμένες εξαιρέσεις. Αντιμετωπίζουμε κάθε ένα από αυτά στο handleException, διαβιβάζοντας ένα μήνυμα σφάλματος στον πελάτη.

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

Verticles, Event Bus και άλλα gotchas

Το Vert.x προσφέρει επίσης ένα μοντέλο ταυτόχρονης ονομασίας verticle που μοιάζει με το σύστημα Actor. (Εάν θέλετε να μάθετε περισσότερα, μεταβείτε στον οδηγό του Akka Actor.) Το Verticle απομονώνει την κατάσταση και τη συμπεριφορά του για να παρέχει ένα ασφαλές περιβάλλον για νήματα. Ο μόνος τρόπος επικοινωνίας με αυτό είναι μέσω λεωφορείου εκδηλώσεων.

Ωστόσο, το λεωφορείο συμβάντων Vert.x απαιτεί τα μηνύματά του να είναι String ή JSON. Αυτό καθιστά δύσκολη τη διαβίβαση αυθαίρετων αντικειμένων εκτός POJO. Και σε ένα σύστημα υψηλής απόδοσης, η αντιμετώπιση της μετατροπής JSON είναι ανεπιθύμητη καθώς επιβάλλει κάποιο κόστος υπολογισμού. Εάν αναπτύσσετε εφαρμογές IO, μπορεί να προτιμάτε να μην χρησιμοποιείτε ούτε bus verticle ή event, καθώς τέτοιες εφαρμογές έχουν μικρή ανάγκη για τοπική πολιτεία.

Η εργασία με ορισμένα στοιχεία Vert.x μπορεί επίσης να είναι αρκετά δύσκολη. Μπορεί να βρείτε έλλειψη τεκμηρίωσης, απροσδόκητη συμπεριφορά, ακόμη και αποτυχία λειτουργίας. Το Vert.x μπορεί να υποφέρει από τη δική του φιλοδοξία, καθώς η ανάπτυξη νέων στοιχείων θα απαιτούσε μεταφορά σε πολλές γλώσσες. Αυτό είναι ένα δύσκολο εγχείρημα. Γι 'αυτό το λόγο η προσκόλληση στον πυρήνα θα ήταν η καλύτερη.

Εάν αναπτύσσετε ένα δημόσιο API, τότε ο πυρήνας vertx πρέπει να είναι αρκετός. Εάν είναι μια εφαρμογή ιστού, μπορείτε να προσθέσετε vertx-web που παρέχει χειρισμό παραμέτρων http και έλεγχο ταυτότητας JWT / Session. Αυτά τα δύο είναι αυτά που κυριάρχησαν ούτως ή άλλως. Υπάρχει κάποια μείωση της απόδοσης σε ορισμένες δοκιμές για τη χρήση του vertx-web, αλλά καθώς φαίνεται ότι προήλθε από τη βελτιστοποίηση, μπορεί να εξομαλυνθεί στις επόμενες κυκλοφορίες.