Pengenalan Vert.x, framework Java tercepat saat ini

Jika Anda baru-baru ini mencari di Google "kerangka kerja terbaik", Anda mungkin telah menemukan tolok ukur Techempower di mana lebih dari tiga ratus kerangka kerja diberi peringkat. Di sana Anda mungkin telah memperhatikan bahwa Vert.x adalah salah satu peringkat teratas, jika bukan yang pertama menurut beberapa ukuran.

Jadi, mari kita bicarakan.

Vert.x adalah kerangka kerja web poliglot yang berbagi fungsionalitas umum di antara bahasa yang didukungnya Java, Kotlin, Scala, Ruby, dan Javascript. Terlepas dari bahasanya, Vert.x beroperasi pada Java Virtual Machine (JVM). Menjadi modular dan ringan, ini diarahkan untuk pengembangan layanan mikro.

Tolok ukur Techempower mengukur kinerja pembaruan, pengambilan, dan pengiriman data dari database. Semakin banyak permintaan yang disajikan per detik, semakin baik. Dalam skenario IO di mana sedikit komputasi yang terlibat, kerangka kerja non-pemblokiran apa pun akan memiliki keunggulan. Dalam beberapa tahun terakhir, paradigma seperti itu hampir tidak dapat dipisahkan dari Node.js yang mempopulerkannya dengan loop peristiwa single-threaded-nya.

Vert.x, seperti Node, mengoperasikan satu putaran peristiwa. Tetapi Vert.x juga memanfaatkan JVM. Jika Node berjalan pada satu inti, Vert.x memelihara kumpulan utas dengan ukuran yang dapat menyesuaikan dengan jumlah inti yang tersedia. Dengan dukungan konkurensi yang lebih besar, Vert.x cocok tidak hanya untuk IO tetapi juga untuk proses yang berat dengan CPU yang memerlukan komputasi paralel.

Loop acara, bagaimanapun, adalah setengah dari cerita. Setengah lainnya tidak ada hubungannya dengan Vert.x.

Untuk menyambungkan ke database, klien memerlukan driver konektor. Di ranah Java, driver paling umum untuk Sql adalah JDBC. Masalahnya, driver ini sedang memblokir. Dan itu memblokir di level soket. Sebuah utas akan selalu macet di sana sampai ia kembali dengan respons.

Tak perlu dikatakan lagi, pengemudi telah menjadi hambatan dalam mewujudkan aplikasi yang sepenuhnya tidak memblokir. Untungnya telah ada kemajuan (meskipun tidak resmi) pada driver asinkron dengan beberapa garpu aktif, di antaranya:

  • //github.com/jasync-sql/jasync-sql (untuk Postgres dan MySql)
  • //github.com/reactiverse/reactive-pg-client (Postgres)

Aturan emas

Vert.x cukup mudah digunakan, dan server http dapat dijalankan dengan beberapa baris kode.

Metode requestHandler adalah tempat loop peristiwa mengirimkan peristiwa permintaan. Karena Vert.x tidak beropini, penanganannya adalah gaya bebas. Namun perlu diingat satu aturan penting dari utas non-pemblokiran: jangan memblokirnya.

Saat bekerja dengan konkurensi, kita dapat memanfaatkan begitu banyak opsi yang tersedia saat ini seperti Promise, Future, Rx, serta cara idiomatik Vert.x sendiri. Namun seiring dengan pertumbuhan kompleksitas aplikasi, memiliki fungsionalitas asinkron saja tidak cukup. Kami juga membutuhkan kemudahan mengoordinasikan dan merangkai panggilan sambil menghindari neraka panggilan balik, serta melewati kesalahan apa pun dengan anggun.

Scala Future memenuhi semua kondisi di atas dengan keuntungan tambahan yang didasarkan pada prinsip-prinsip pemrograman fungsional. Meskipun artikel ini tidak membahas Scala Future secara mendalam, kami dapat mencobanya dengan aplikasi sederhana. Katakanlah aplikasi tersebut adalah layanan API untuk menemukan pengguna yang diberi id mereka:

Ada tiga operasi yang terlibat: memeriksa parameter permintaan, memeriksa apakah id valid, dan mengambil data. Kami akan membungkus setiap operasi ini di Masa Depan dan mengoordinasikan eksekusi dalam struktur "untuk pemahaman".

  • Langkah pertama adalah mencocokkan permintaan dengan layanan. Scala memiliki fitur pencocokan pola yang kuat yang dapat kita gunakan untuk tujuan ini. Di sini kami mencegat penyebutan "/ pengguna" dan meneruskannya ke layanan kami.
  • Berikutnya adalah inti dari layanan ini di mana masa depan kita diatur dalam urutan pemahaman. Pemeriksaan parameter f1 wraps masa depan yang pertama . Kami secara khusus ingin mengambil id dari permintaan get dan memasukkannya ke int. (Scala tidak memerlukan pengembalian eksplisit jika nilai yang dikembalikan adalah baris terakhir dalam metode.) Seperti yang Anda lihat, operasi ini berpotensi memunculkan pengecualian karena id mungkin bukan int atau bahkan tidak tersedia, tetapi tidak apa-apa untuk saat ini .
  • F2 masa depan kedua memeriksa validitas id. Kami memblokir id apa pun yang lebih rendah dari 100 dengan secara eksplisit memanggil Future.failed dengan CustomException kami sendiri. Jika tidak, kita melewatkan Future kosong dalam bentuk Future.unit sebagai validasi yang berhasil.
  • F3 masa depan terakhir mengambil pengguna dengan id yang disediakan oleh f1. Karena ini hanya contoh, kami tidak benar-benar terhubung ke database. Kami baru saja mengembalikan beberapa string tiruan.
  • map menjalankan pengaturan yang menghasilkan data pengguna dari f3 lalu mencetaknya ke respons.
  • Sekarang jika di bagian manapun dari urutan terjadi kesalahan, Throwable dilewatkan untuk memulihkan . Di sini kita dapat mencocokkan tipenya dengan strategi pemulihan yang sesuai. Melihat kembali kode kami, kami telah mengantisipasi beberapa potensi kegagalan seperti id hilang, atau id yang tidak int atau tidak valid yang akan menimbulkan pengecualian tertentu. Kami menangani masing-masing di handleException dengan meneruskan pesan kesalahan ke klien.

Pengaturan ini tidak hanya menyediakan aliran asinkron dari awal hingga akhir, tetapi juga pendekatan yang bersih untuk menangani kesalahan. Dan karena disederhanakan di seluruh penangan, kami dapat fokus pada hal-hal yang penting, seperti kueri database.

Verticles, Event Bus, dan gotcha lainnya

Vert.x juga menawarkan model konkurensi yang disebut verticle yang menyerupai sistem Aktor. (Jika Anda ingin mempelajari lebih lanjut, buka panduan Akka Actor saya.) Verticle mengisolasi status dan perilakunya untuk menyediakan lingkungan yang aman untuk thread. Satu-satunya cara untuk berkomunikasi dengannya adalah melalui bus acara.

Namun, bus peristiwa Vert.x memerlukan pesannya berupa String atau JSON. Hal ini membuat sulit untuk meneruskan objek non-POJO arbitrer. Dan dalam sistem kinerja tinggi, menangani konversi JSON tidak diinginkan karena membebankan sejumlah biaya komputasi. Jika Anda mengembangkan aplikasi IO, Anda mungkin lebih baik tidak menggunakan verticle atau event bus, karena aplikasi semacam itu tidak terlalu membutuhkan status lokal.

Bekerja dengan beberapa komponen Vert.x juga bisa sangat menantang. Anda mungkin menemukan kurangnya dokumentasi, perilaku tidak terduga, dan bahkan kegagalan berfungsi. Vert.x mungkin mengalami ambisinya sendiri, karena mengembangkan komponen baru akan membutuhkan porting dalam banyak bahasa. Ini adalah pekerjaan yang sulit. Oleh karena itu, berpegang teguh pada inti adalah yang terbaik.

Jika Anda mengembangkan API publik, maka vertx-core sudah cukup. Jika ini adalah aplikasi web, Anda dapat menambahkan vertx-web yang menyediakan penanganan parameter http dan otentikasi JWT / Sesi. Keduanya adalah yang mendominasi tolok ukur. Ada beberapa penurunan kinerja dalam beberapa pengujian untuk menggunakan vertx-web, tetapi karena tampaknya berasal dari pengoptimalan, ini mungkin disetrika dalam rilis berikutnya.