Rumah  >  Artikel  >  Java  >  Memodenkan Java Monolith untuk Prestasi Lebih Baik dengan Seni Bina Async dan Tanpa Sekat

Memodenkan Java Monolith untuk Prestasi Lebih Baik dengan Seni Bina Async dan Tanpa Sekat

Susan Sarandon
Susan Sarandonasal
2024-11-17 06:13:03464semak imbas

Modernizing Java Monoliths for Better Performance with Async and Non-Blocking Architectures

Dalam projek baru-baru ini, saya memodenkan perkhidmatan web Java monolitik lama yang ditulis dalam Dropwizard. Perkhidmatan ini mengendalikan beberapa kebergantungan pihak ketiga (3P) melalui fungsi AWS Lambda, tetapi prestasi ketinggalan disebabkan sifat seni bina yang menyekat segerak. Persediaan mempunyai kependaman P99 selama 20 saat, menyekat urutan permintaan sementara menunggu fungsi tanpa pelayan selesai. Penyekatan ini menyebabkan ketepuan kumpulan benang, yang membawa kepada kegagalan permintaan yang kerap semasa trafik puncak.

Mengenalpasti Bottleneck Prestasi

Inti isu ialah setiap permintaan kepada fungsi Lambda menduduki urutan permintaan dalam perkhidmatan Java. Memandangkan fungsi 3P ini sering mengambil masa yang agak lama untuk disiapkan, utas yang mengendalikannya akan kekal disekat, memakan sumber dan mengehadkan kebolehskalaan. Berikut ialah contoh kelakuan menyekat ini dalam kod:

// Blocking code example
public String callLambdaService(String payload) {
    String response = externalLambdaService.invoke(payload);
    return response;
}

Dalam contoh ini, kaedah callLambdaService menunggu sehingga externalLambdaService.invoke() mengembalikan respons. Sementara itu, tiada tugasan lain yang boleh menggunakan benang.

Penyelesaian: Berhijrah kepada Corak Tak Segerak, Tidak Menyekat

Untuk menangani kesesakan ini, saya mereka bentuk semula perkhidmatan menggunakan kaedah tak segerak dan tidak menyekat. Perubahan ini melibatkan penggunaan klien HTTP yang menggunakan fungsi Lambda untuk menggunakan AsyncHttpClient daripada perpustakaan org.asynchttpclient, yang secara dalaman menggunakan EventLoopGroup untuk mengendalikan permintaan secara tidak segerak.

Menggunakan AsyncHttpClient membantu memunggah operasi menyekat tanpa menggunakan benang daripada kumpulan. Berikut ialah contoh rupa panggilan tidak menyekat yang dikemas kini:

// Non-blocking code example
public CompletableFuture<String> callLambdaServiceAsync(String payload) {
    return CompletableFuture.supplyAsync(() -> {
        return asyncHttpClient.invoke(payload);
    });
}

Memanfaatkan CompletableFuture Java untuk Merangkai Panggilan Async

Selain membuat panggilan individu tanpa menyekat, saya merantai beberapa panggilan pergantungan menggunakan CompletableFuture. Dengan kaedah seperti thenCombine dan thenApply, saya boleh mengambil dan menggabungkan data secara tidak segerak daripada berbilang sumber, meningkatkan daya pemprosesan dengan ketara.

CompletableFuture<String> future1 = callLambdaServiceAsync(payload1);
CompletableFuture<String> future2 = callLambdaServiceAsync(payload2);

CompletableFuture<String> combinedResult = future1.thenCombine(future2, (result1, result2) -> {
    return processResults(result1, result2);
});

Memperkenalkan Jenis Keselamatan dengan Kelas SafeAsyncResponse Tersuai

Semasa pelaksanaan, saya memerhatikan bahawa objek AsyncResponse lalai Java tidak mempunyai keselamatan jenis, membenarkan objek Java sewenang-wenangnya dihantar. Untuk menangani perkara ini, saya mencipta kelas SafeAsyncResponse dengan generik, yang memastikan bahawa hanya jenis respons yang ditentukan boleh dikembalikan, menggalakkan kebolehselenggaraan dan mengurangkan risiko ralat masa jalan. Kelas ini juga mencatat ralat jika respons ditulis lebih daripada sekali.

// Blocking code example
public String callLambdaService(String payload) {
    String response = externalLambdaService.invoke(payload);
    return response;
}

Contoh Penggunaan SafeAsyncResponse

// Non-blocking code example
public CompletableFuture<String> callLambdaServiceAsync(String payload) {
    return CompletableFuture.supplyAsync(() -> {
        return asyncHttpClient.invoke(payload);
    });
}

Ujian dan Keuntungan Prestasi

Untuk mengesahkan keberkesanan perubahan ini, saya menulis ujian beban menggunakan benang maya untuk mensimulasikan pemprosesan maksimum pada satu mesin. Saya menjana tahap masa pelaksanaan fungsi tanpa pelayan yang berbeza (antara 1 hingga 20 saat) dan mendapati bahawa pelaksanaan tidak menyekat async baharu meningkatkan daya pemprosesan sebanyak 8x untuk masa pelaksanaan yang lebih rendah dan kira-kira 4x untuk masa pelaksanaan yang lebih tinggi.

Dalam menyediakan ujian beban ini, saya memastikan untuk melaraskan had sambungan peringkat pelanggan untuk memaksimumkan daya pemprosesan, yang penting untuk mengelakkan kesesakan dalam sistem tak segerak.

Menemui Pepijat Tersembunyi dalam Klien HTTP

Semasa menjalankan ujian tekanan ini, saya menemui pepijat tersembunyi dalam klien HTTP tersuai kami. Pelanggan menggunakan semaphore dengan tamat masa sambungan ditetapkan kepada Integer.MAX_VALUE, bermakna jika pelanggan kehabisan sambungan yang tersedia, ia akan menyekat utas selama-lamanya. Penyelesaian pepijat ini adalah penting untuk mengelakkan kemungkinan kebuntuan dalam senario beban tinggi.

Pilihan Antara Benang Maya dan Kod Async Tradisional

Mungkin ada yang tertanya-tanya mengapa kami tidak bertukar kepada utas maya sahaja, yang boleh mengurangkan keperluan untuk kod tak segerak dengan membenarkan utas disekat tanpa kos sumber yang ketara. Walau bagaimanapun, terdapat had semasa dengan benang maya: ia disematkan semasa operasi disegerakkan. Ini bermakna apabila benang maya memasuki blok yang disegerakkan, ia tidak boleh menyahlekap, berpotensi menyekat sumber OS sehingga operasi selesai.

Contohnya:

CompletableFuture<String> future1 = callLambdaServiceAsync(payload1);
CompletableFuture<String> future2 = callLambdaServiceAsync(payload2);

CompletableFuture<String> combinedResult = future1.thenCombine(future2, (result1, result2) -> {
    return processResults(result1, result2);
});

Dalam kod ini, jika baca disekat kerana tiada data tersedia, benang maya disematkan pada urutan OS, menghalangnya daripada menyahlekap dan menyekat urutan OS juga.

Nasib baik, dengan JEP 491 di ufuk, pembangun Java boleh menantikan tingkah laku yang dipertingkatkan untuk urutan maya, di mana operasi menyekat dalam kod disegerakkan boleh dikendalikan dengan lebih cekap tanpa meletihkan urutan platform.

Kesimpulan

Melalui pemfaktoran semula perkhidmatan kami kepada seni bina tidak menyekat async, kami mencapai peningkatan prestasi yang ketara. Dengan melaksanakan AsyncHttpClient, memperkenalkan SafeAsyncResponse untuk keselamatan jenis, dan menjalankan ujian beban, kami dapat mengoptimumkan perkhidmatan Java kami dan meningkatkan daya pemprosesan. Projek ini merupakan latihan yang berharga dalam memodenkan aplikasi monolitik dan mendedahkan kepentingan amalan async yang betul untuk skalabiliti.

Apabila Java berkembang, kami mungkin dapat memanfaatkan urutan maya dengan lebih berkesan pada masa hadapan, tetapi buat masa ini, seni bina async dan tidak menyekat kekal sebagai pendekatan penting untuk pengoptimuman prestasi dalam kependaman tinggi, perkhidmatan bergantung kepada pihak ketiga.

Atas ialah kandungan terperinci Memodenkan Java Monolith untuk Prestasi Lebih Baik dengan Seni Bina Async dan Tanpa Sekat. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn