JavaRush /Java Blog /Random-ID /Panduan untuk Layanan Mikro Java. Bagian 1: Dasar-dasar d...

Panduan untuk Layanan Mikro Java. Bagian 1: Dasar-dasar dan Arsitektur Layanan Mikro

Dipublikasikan di grup Random-ID
Dalam panduan ini, Anda akan mempelajari apa itu layanan mikro Java, cara merancang dan membuatnya. Ini juga mencakup pertanyaan tentang perpustakaan layanan mikro Java dan kelayakan penggunaan layanan mikro. Terjemahan dan adaptasi Java Microservices: Panduan Praktis .

Layanan Mikro Java: Dasar-dasar

Untuk memahami layanan mikro, Anda harus terlebih dahulu mendefinisikan apa yang bukan layanan mikro. Bukankah ini sebuah “monolit” - monolit Java: apa itu dan apa kelebihan atau kekurangannya? Panduan untuk Layanan Mikro Java.  Bagian 1: Dasar-dasar dan Arsitektur Layanan Mikro - 1

Apa itu monolit Java?

Bayangkan Anda bekerja di bank atau startup fintech. Anda memberi pengguna aplikasi seluler yang dapat mereka gunakan untuk membuka rekening bank baru. Dalam kode Java hal ini akan menghasilkan kehadiran kelas pengontrol. Secara sederhana, tampilannya seperti ini:
@Controller
class BankController {

    @PostMapping("/users/register")
    public void register(RegistrationForm form) {
        validate(form);
        riskCheck(form);
        openBankAccount(form);
        // etc..
    }
}
Anda memerlukan pengontrol untuk:
  1. Mengonfirmasi formulir pendaftaran.
  2. Memeriksa risiko alamat pengguna untuk memutuskan apakah akan memberinya rekening bank.
  3. Membuka rekening bank.
Kelas tersebut BankControllerakan dikemas bersama dengan sumber Anda yang lain ke dalam file bank.jar atau bank.war untuk diterapkan - ini adalah monolit lama yang bagus yang berisi semua kode yang diperlukan untuk menjalankan bank Anda. Sebagai perkiraan kasar, ukuran awal file .jar (atau .war) akan berkisar antara 1 hingga 100 MB. Sekarang Anda cukup menjalankan file .jar di server Anda... dan hanya itu yang perlu Anda lakukan untuk menerapkan aplikasi Java Anda. Panduan untuk Layanan Mikro Java.  Bagian 1: Dasar-dasar dan Arsitektur Layanan Mikro - 2Gambar, persegi panjang kiri atas: penerapan bank mono(litik) java -jar bank.jar (cp .war/.ear ke dalam server aplikasi). Persegi panjang kanan: buka browser.

Apa masalah dengan monolit Java?

Tidak ada yang salah dengan monolit Java. Namun, pengalaman menunjukkan bahwa jika dalam proyek Anda:
  • Ada banyak programmer/tim/konsultan yang bekerja...
  • ...atas monolit yang sama di bawah tekanan dari pelanggan dengan persyaratan yang sangat tidak jelas...
  • dalam beberapa tahun...
... maka dalam hal ini file bank.jar kecil Anda berubah menjadi gigabyte kode yang sangat besar saja, yang bahkan menakutkan untuk didekati, apalagi disebarkan.

Bagaimana cara mengurangi ukuran monolit Java?

Sebuah pertanyaan wajar muncul: bagaimana cara membuat monolit lebih kecil? Saat ini bank.jar Anda berjalan di satu JVM, satu proses di satu server. Tidak lebih, tidak kurang. Dan saat ini sebuah pemikiran logis mungkin muncul di benak saya: “Tetapi layanan verifikasi risiko dapat digunakan oleh departemen lain di perusahaan saya! Ini tidak terkait langsung dengan aplikasi perbankan monolitik saya! Mungkin itu harus dipotong dari monolit dan digunakan sebagai produk terpisah? Artinya, secara teknis, menjalankannya sebagai proses Java yang terpisah.”

Apa itu layanan mikro Java?

Dalam praktiknya, frasa ini berarti bahwa sekarang pemanggilan metode riskCheck()tidak akan dilakukan dari BankController: metode atau komponen kacang ini dengan semua kelas tambahannya akan dipindahkan ke proyek Maven atau Gradle miliknya sendiri. Ini juga akan diterapkan dan ditempatkan di bawah kendali versi secara independen dari monolit perbankan. Namun, seluruh proses ekstraksi ini tidak mengubah modul RiskCheck baru Anda menjadi layanan mikro, karena definisi layanan mikro terbuka untuk interpretasi. Hal ini menyebabkan seringnya diskusi dalam tim dan perusahaan.
  • Apakah 5-7 kelas dalam proyek mikro atau apa?
  • 100 atau 1000 kelas...masih mikro?
  • Apakah microservice secara umum berhubungan dengan jumlah kelas atau tidak?
Mari kita tinggalkan penalaran teoretis, dan tetap berpegang pada pertimbangan pragmatis dan lakukan ini:
  1. Mari kita sebut semua layanan mikro yang diterapkan secara terpisah, terlepas dari ukuran atau batasan domainnya.
  2. Mari kita pikirkan bagaimana mengatur komunikasi antar layanan. Layanan mikro kami memerlukan cara untuk berkomunikasi satu sama lain.
Jadi, untuk meringkas: sebelumnya Anda memiliki satu proses JVM, sebuah monolit yang solid untuk menjalankan bank. Sekarang Anda memiliki proses JVM monolit perbankan dan layanan mikro RiskCheck terpisah yang berjalan dalam proses JVM-nya sendiri. Dan sekarang, untuk memeriksa risiko, monolit Anda harus menghubungi layanan mikro ini. Bagaimana cara melakukannya?

Bagaimana cara menjalin komunikasi antar layanan mikro Java?

Secara umum dan umum, ada dua opsi - komunikasi sinkron dan asinkron.

Komunikasi sinkron: (HTTP)/REST

Biasanya, komunikasi tersinkronisasi antar layanan mikro terjadi melalui HTTP dan layanan mirip REST yang mengembalikan XML atau JSON. Tentu saja, mungkin ada opsi lain - setidaknya ambil Google Protocol Buffer . Jika Anda memerlukan respons segera, lebih baik menggunakan komunikasi REST. Dalam contoh kita, inilah yang perlu dilakukan, karena verifikasi risiko diperlukan sebelum membuka akun. Jika tidak ada pemeriksaan risiko, tidak ada akun. Kami akan membahas alat di bawah ini, di bagian “ Pustaka mana yang terbaik untuk panggilan Java REST yang disinkronkan ”.

Perpesanan - Komunikasi Asinkron

Komunikasi layanan mikro asinkron biasanya dilakukan dengan bertukar pesan dengan implementasi JMS dan/atau menggunakan protokol seperti AMQP . Kami menulis “biasanya” di sini karena suatu alasan: katakanlah jumlah integrasi email/SMTP tidak dapat dianggap remeh. Gunakan saat Anda tidak membutuhkan respons segera. Misalnya, pengguna mengklik tombol “beli sekarang”, dan Anda, selanjutnya, ingin membuat faktur. Proses ini tentu saja tidak boleh terjadi dalam siklus respons permintaan pembelian pengguna. Di bawah ini kami akan menjelaskan alat mana yang terbaik untuk perpesanan Java asinkron .

Contoh: Panggilan REST API di Java

Anggaplah kita memilih komunikasi layanan mikro yang sinkron. Dalam hal ini, kode Java kita (yang kami sajikan di atas) pada tingkat rendah akan terlihat seperti ini. (yang kami maksud dengan tingkat rendah di sini adalah fakta bahwa untuk komunikasi layanan mikro, pustaka klien biasanya dibuat yang mengabstraksi Anda dari panggilan HTTP yang sebenarnya).
@Controller
class BankController {

    @Autowired
    private HttpClient httpClient;

    @PostMapping("/users/register")
    public void register(RegistrationForm form) {
        validate(form);
        httpClient.send(riskRequest, responseHandler());
        setupAccount(form);
        // etc..
    }
}
Berdasarkan kode tersebut, menjadi jelas bahwa kita sekarang perlu menerapkan dua layanan Java (mikro), Bank dan RiskCheck. Hasilnya, kita akan menjalankan dua proses JVM. Panduan untuk Layanan Mikro Java.  Bagian 1: Dasar-dasar dan Arsitektur Layanan Mikro - 3Itu saja yang Anda perlukan untuk mengembangkan proyek layanan mikro Java: cukup buat dan terapkan potongan yang lebih kecil (file .jar atau .war) alih-alih satu potongan monolitik. Jawaban atas pertanyaan ini masih belum jelas: bagaimana kita seharusnya mengubah monolit menjadi layanan mikro? Seberapa kecil potongan-potongan ini, bagaimana cara menentukan ukuran yang benar? Mari kita periksa.

Arsitektur Layanan Mikro Java

Dalam praktiknya, perusahaan mengembangkan proyek layanan mikro dengan berbagai cara. Pendekatannya bergantung pada apakah Anda mencoba mengubah monolit yang ada menjadi proyek layanan mikro atau memulai proyek dari awal.

Dari monolit hingga layanan mikro

Salah satu ide paling logis adalah mengekstrak layanan mikro dari monolit yang sudah ada. Perhatikan bahwa awalan "mikro" di sini tidak berarti bahwa layanan yang diekstraksi akan benar-benar kecil; hal ini belum tentu demikian. Mari kita lihat latar belakang teorinya.

Ide: pecahkan monolit menjadi layanan mikro

Pendekatan layanan mikro dapat diterapkan pada proyek lama. Dan itulah kenapa:
  1. Seringkali, proyek seperti itu sulit untuk dipertahankan/diubah/diperluas.
  2. Semua orang, mulai dari pengembang hingga manajemen, menginginkan penyederhanaan.
  3. Anda memiliki (relatif) batasan domain yang jelas, artinya Anda tahu persis apa yang harus dilakukan perangkat lunak Anda.
Kembali ke contoh kami, ini berarti Anda dapat melihat monolit perbankan Java Anda dan mencoba mengelompokkannya melintasi batas domain.
  • Jadi, masuk akal untuk memisahkan pemrosesan data pengguna (seperti nama, alamat, nomor telepon) ke dalam layanan mikro “Manajemen Akun” yang terpisah.
  • Atau "Modul Pemeriksa Risiko" yang disebutkan di atas yang memeriksa tingkat risiko pengguna dan dapat digunakan oleh banyak proyek atau bahkan departemen lain di perusahaan.
  • Atau modul faktur yang mengirimkan faktur dalam format PDF atau melalui surat.

Implementasi sebuah ide: biarkan orang lain yang melakukannya

Pendekatan yang dijelaskan di atas tampak bagus di atas kertas dan diagram mirip UML. Namun, semuanya tidak sesederhana itu. Implementasi praktisnya memerlukan persiapan teknis yang serius: kesenjangan antara pemahaman kita tentang apa yang baik untuk diekstraksi dari monolit dan proses ekstraksi itu sendiri sangat besar. Sebagian besar proyek perusahaan mencapai tahap di mana pengembang takut untuk, misalnya, mengupgrade versi Hibernate yang berusia 7 tahun ke versi yang lebih baru. Perpustakaan akan diperbarui bersamaan dengan itu, tetapi ada bahaya nyata merusak sesuatu. Jadi para pengembang yang sama sekarang harus menggali kode lama dengan batasan transaksi database yang tidak jelas dan mengekstrak layanan mikro yang terdefinisi dengan baik? Seringkali, masalah ini sangat kompleks dan tidak dapat “diselesaikan” di papan tulis atau rapat arsitektur. Panduan untuk Layanan Mikro Java.  Bagian 1: Dasar-dasar dan Arsitektur Layanan Mikro - 4Mengutip pengembang Twitter @simonbrown: Saya akan mengatakan ini berulang kali... jika orang tidak dapat membangun monolit dengan benar, layanan mikro tidak akan membantu. Simon Brown

Proyek dari awal berdasarkan arsitektur layanan mikro

Dalam kasus proyek Java baru, tiga poin bernomor dari bagian sebelumnya terlihat sedikit berbeda:
  1. Anda memulai dengan awal yang bersih, jadi tidak ada “bagasi” yang harus dipelihara.
  2. Pengembang ingin menjaga semuanya tetap sederhana di masa depan.
  3. Masalah: Anda memiliki gambaran yang lebih kabur tentang batasan domain: Anda tidak tahu apa yang seharusnya dilakukan oleh perangkat lunak Anda (petunjuk: agile ;))
Hal ini menyebabkan perusahaan mencoba proyek baru dengan layanan mikro Java.

Arsitektur layanan mikro teknis

Poin pertama sepertinya yang paling jelas bagi para pengembang, namun ada juga yang sangat tidak menyarankannya. Hadi Hariri merekomendasikan refactoring "Extract Microservice" di IntelliJ. Dan meskipun contoh berikut ini sangat disederhanakan, sayangnya implementasi yang diamati dalam proyek nyata tidak jauh dari itu. Sebelum layanan mikro
@Service
class UserService {

    public void register(User user) {
        String email = user.getEmail();
        String username =  email.substring(0, email.indexOf("@"));
        // ...
    }
}
Dengan layanan mikro Java substring
@Service
class UserService {

    @Autowired
    private HttpClient client;

    public void register(User user) {
        String email = user.getEmail();
        //теперь вызываем substring microservice via http
        String username =  httpClient.send(substringRequest(email), responseHandler());
        // ...
    }
}
Jadi pada dasarnya Anda menggabungkan pemanggilan metode Java dalam panggilan HTTP, tanpa alasan yang jelas untuk melakukannya. Namun, salah satu alasannya adalah: kurangnya pengalaman dan upaya memaksakan pendekatan layanan mikro Java. Rekomendasi: Jangan lakukan ini.

Arsitektur layanan mikro berorientasi alur kerja

Pendekatan umum berikutnya adalah membagi layanan mikro Java ke dalam modul berbasis alur kerja. Contoh kehidupan nyata: Di Jerman, ketika Anda pergi ke dokter (umum), dia harus mencatat kunjungan Anda di sistem CRM medisnya. Untuk mendapatkan pembayaran dari asuransi, ia akan mengirimkan data tentang pengobatan Anda (dan pengobatan pasien lain) kepada perantara melalui XML. Broker akan melihat file XML ini dan (disederhanakan):
  1. Akan memeriksa apakah file XML yang benar telah diterima.
  2. Ini akan memeriksa masuk akalnya prosedur tersebut: katakanlah, seorang anak berusia satu tahun yang menerima tiga prosedur pembersihan gigi dalam satu hari dari dokter kandungan terlihat agak mencurigakan.
  3. Akan menggabungkan XML dengan beberapa data birokrasi lainnya.
  4. Akan meneruskan file XML ke perusahaan asuransi untuk memulai pembayaran.
  5. Dan hasilnya akan dikirimkan ke dokter, memberinya pesan “berhasil” atau “tolong kirim ulang rekaman ini segera setelah masuk akal.”
Catatan. Dalam contoh ini, komunikasi antar layanan mikro tidak berperan, namun dapat dilakukan secara asinkron oleh perantara pesan (misalnya RabbitMQ), karena dokter tidak menerima umpan balik langsung. Panduan untuk Layanan Mikro Java.  Bagian 1: Dasar-dasar dan Arsitektur Layanan Mikro - 5Sekali lagi, ini tampak bagus di atas kertas, tetapi pertanyaan wajar muncul:
  • Apakah perlu menerapkan enam aplikasi untuk memproses satu file XML?
  • Apakah layanan-layanan mikro ini benar-benar independen satu sama lain? Bisakah mereka dikerahkan secara independen satu sama lain? Dengan versi dan skema API yang berbeda?
  • Apa yang dilakukan layanan mikro yang masuk akal informasi jika layanan mikro verifikasi tidak berfungsi? Apakah sistemnya masih berfungsi?
  • Apakah layanan-layanan mikro ini berbagi basis data yang sama (mereka tentu memerlukan beberapa data umum dalam tabel DB), atau masing-masing memiliki basis datanya sendiri?
  • … dan banyak lagi.
Menariknya, diagram di atas terlihat lebih sederhana karena setiap layanan kini memiliki tujuan yang jelas dan jelas. Dulunya terlihat seperti monolit yang menakutkan ini: Panduan untuk Layanan Mikro Java.  Bagian 1: Dasar-dasar dan Arsitektur Layanan Mikro - 6Meskipun Anda dapat berdebat tentang kesederhanaan diagram ini, kini Anda harus menyelesaikan tantangan operasional tambahan ini.
  • Anda tidak hanya perlu menerapkan satu aplikasi, tetapi setidaknya enam aplikasi.
  • Anda bahkan mungkin perlu menerapkan beberapa database, bergantung pada seberapa jauh Anda ingin mendalami arsitektur layanan mikro.
  • Anda perlu memastikan bahwa setiap sistem online dan berfungsi dengan baik.
  • Anda perlu memastikan bahwa panggilan antar layanan mikro benar-benar tangguh (lihat Bagaimana cara membuat layanan mikro Java tangguh?).
  • Dan semua hal lain yang tersirat dalam pengaturan ini - mulai dari pengaturan pengembangan lokal hingga pengujian integrasi.
Jadi rekomendasinya adalah:
  • Jika Anda bukan Netflix (kemungkinan besar, Anda bukan Netflix)...
  • Kecuali Anda memiliki keterampilan kerja super kuat di mana Anda membuka lingkungan pengembangan dan itu menyebabkan kekacauan monyet yang membuang database produksi Anda yang mudah dipulihkan dalam 5 detik.
  • atau Anda merasa seperti @monzo dan ingin mencoba 1500 layanan mikro hanya karena Anda bisa.
→ Jangan lakukan ini. Dan sekarang tidak terlalu hiperbolis. Mencoba memodelkan layanan mikro melintasi batas domain tampaknya cukup masuk akal. Namun ini tidak berarti Anda perlu mengambil satu alur kerja dan membaginya menjadi beberapa bagian kecil (menerima XML, memvalidasi XML, meneruskan XML). Oleh karena itu, setiap kali Anda memulai proyek baru dengan layanan mikro Java dan batasan domain masih sangat kabur, cobalah untuk menjaga ukuran layanan mikro Anda pada tingkat yang rendah. Anda selalu dapat menambahkan lebih banyak modul nanti. Dan pastikan Anda memiliki DevOps tingkat lanjut di tim/perusahaan/divisi untuk mendukung infrastruktur baru Anda.

Arsitektur layanan mikro poliglot atau berorientasi tim

Ada pendekatan ketiga, yang hampir bersifat libertarian, dalam mengembangkan layanan mikro: memungkinkan tim atau bahkan individu untuk mengimplementasikan cerita pengguna menggunakan sejumlah bahasa atau layanan mikro (pemasar menyebut pendekatan ini sebagai “pemrograman poliglot”). Dengan demikian, layanan validasi XML yang dijelaskan di atas dapat ditulis dalam Java, sedangkan layanan mikro validasi pada saat yang sama dapat ditulis dalam Haskell (agar masuk akal secara matematis). Untuk microservice penerusan asuransi bisa menggunakan Erlang (karena memang perlu skala ;)). Apa yang tampak menyenangkan dari sudut pandang pengembang (mengembangkan sistem yang sempurna dengan bahasa sempurna Anda di lingkungan yang terisolasi), pada kenyataannya, tidak pernah diinginkan oleh organisasi: homogenisasi dan standardisasi. Ini berarti seperangkat bahasa, perpustakaan, dan alat yang relatif terstandarisasi sehingga pengembang lain dapat terus mendukung layanan mikro Haskell Anda di masa depan ketika Anda beralih ke lingkungan yang lebih ramah lingkungan. Panduan untuk Layanan Mikro Java.  Bagian 1: Dasar-dasar dan Arsitektur Layanan Mikro - 8Sejarah menunjukkan bahwa standardisasi biasanya sudah terlalu mendarah daging. Misalnya, pengembang di perusahaan besar Fortune 500 terkadang bahkan tidak diizinkan menggunakan Spring karena "bukan bagian dari peta jalan teknologi perusahaan". Namun, transisi menyeluruh ke pendekatan poliglot hampir sama, sisi lain dari mata uang yang sama. Rekomendasi: Jika Anda akan menggunakan pemrograman poliglot, cobalah mengurangi variasi dalam ekosistem bahasa pemrograman yang sama. Jadi, lebih baik menggunakan Kotlin dan Java secara bersamaan (kedua bahasa tersebut didasarkan pada JVM dan 100% kompatibel satu sama lain), daripada Java dan, katakanlah, Haskell. Di bagian selanjutnya, Anda akan mempelajari tentang penerapan dan pengujian layanan mikro Java.
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION