Membandingkan Kontainer Servlet Tertanam di Spring Boot

1. Perkenalan

Meningkatnya popularitas aplikasi cloud-native dan layanan mikro menghasilkan peningkatan permintaan untuk wadah servlet tertanam. Spring Boot memungkinkan pengembang untuk dengan mudah membangun aplikasi atau layanan menggunakan 3 kontainer paling matang yang tersedia: Tomcat, Undertow, dan Jetty.

Dalam tutorial ini, kami akan mendemonstrasikan cara untuk membandingkan implementasi container dengan cepat menggunakan metrik yang diperoleh saat memulai dan di bawah beberapa beban.

2. Dependensi

Penyiapan kami untuk setiap implementasi container yang tersedia akan selalu mengharuskan kami mendeklarasikan ketergantungan pada spring-boot-starter-web di pom.xml kami .

Secara umum, kami ingin menetapkan induk kami sebagai spring-boot-starter-parent , dan kemudian menyertakan starter yang kami inginkan:

 org.springframework.boot spring-boot-starter-parent 2.2.2.RELEASE     org.springframework.boot spring-boot-starter   org.springframework.boot spring-boot-starter-web   

2.1. Kucing jantan

Tidak ada ketergantungan lebih lanjut yang diperlukan saat menggunakan Tomcat karena sudah disertakan secara default saat menggunakan spring-boot-starter-web .

2.2. Dermaga

Untuk menggunakan Jetty, pertama-tama kita harus mengecualikan spring-boot-starter-tomcat dari spring-boot-starter-web .

Kemudian, kami cukup mendeklarasikan ketergantungan pada spring-boot-starter-jetty :

 org.springframework.boot spring-boot-starter-web   org.springframework.boot spring-boot-starter-tomcat     org.springframework.boot spring-boot-starter-jetty  

2.3. Arus bawah

Menyiapkan Undertow identik dengan Jetty, kecuali bahwa kita menggunakan spring-boot-starter-undertow sebagai ketergantungan kita:

 org.springframework.boot spring-boot-starter-web   org.springframework.boot spring-boot-starter-tomcat     org.springframework.boot spring-boot-starter-undertow 

2.4. Aktuator

Kami akan menggunakan Aktuator Spring Boot sebagai cara yang nyaman untuk menekankan sistem dan kueri metrik.

Lihat artikel ini untuk detail tentang Aktuator. Kami hanya menambahkan ketergantungan di pom kami untuk membuatnya tersedia:

 org.springframework.boot spring-boot-starter-actuator 

2.5. Apache Bench

Apache Bench adalah utilitas pengujian beban sumber terbuka yang dibundel dengan server web Apache.

Pengguna Windows dapat mengunduh Apache dari salah satu vendor pihak ketiga yang ditautkan di sini. Jika Apache sudah terinstal di mesin Windows Anda, Anda seharusnya dapat menemukan ab.exe di direktori apache / bin Anda .

Jika Anda menggunakan mesin Linux, ab dapat diinstal menggunakan apt-get dengan:

$ apt-get install apache2-utils

3. Metrik Startup

3.1. Koleksi

Untuk mengumpulkan metrik startup kami, kami akan mendaftarkan event handler untuk diaktifkan pada ApplicationReadyEvent Spring Boot .

Kami secara terprogram akan mengekstrak metrik yang kami minati dengan bekerja langsung dengan MeterRegistry yang digunakan oleh komponen Actuator:

@Component public class StartupEventHandler { // logger, constructor private String[] METRICS = { "jvm.memory.used", "jvm.classes.loaded", "jvm.threads.live"}; private String METRIC_MSG_FORMAT = "Startup Metric >> {}={}"; private MeterRegistry meterRegistry; @EventListener public void getAndLogStartupMetrics( ApplicationReadyEvent event) { Arrays.asList(METRICS) .forEach(this::getAndLogActuatorMetric); } private void processMetric(String metric) { Meter meter = meterRegistry.find(metric).meter(); Map stats = getSamples(meter); logger.info(METRIC_MSG_FORMAT, metric, stats.get(Statistic.VALUE).longValue()); } // other methods }

Kami menghindari kebutuhan untuk menanyakan titik akhir Aktuator REST secara manual atau untuk menjalankan konsol JMX mandiri dengan mencatat metrik yang menarik saat memulai dalam penangan kejadian kami.

3.2. Pilihan

Ada banyak metrik yang disediakan Aktuator di luar kotak. Kami memilih 3 metrik yang membantu mendapatkan ikhtisar tingkat tinggi tentang karakteristik runtime utama setelah server aktif:

  • jvm.memory.used - total memori yang digunakan oleh JVM sejak startup
  • jvm.classes.loaded - jumlah total kelas yang dimuat
  • jvm.threads.live - jumlah total utas aktif. Dalam pengujian kami, nilai ini dapat dilihat sebagai jumlah utas "diam"

4. Metrik Waktu Proses

4.1. Koleksi

Selain menyediakan metrik permulaan, kami akan menggunakan titik akhir / metrik yang diekspos oleh Aktuator sebagai URL target saat kami menjalankan Apache Bench untuk membuat aplikasi sedang dimuat.

Untuk menguji aplikasi nyata yang sedang dimuat, kita mungkin menggunakan titik akhir yang disediakan oleh aplikasi kita.

Setelah server dimulai, kita akan mendapatkan prompt perintah dan menjalankan ab :

ab -n 10000 -c 10 //localhost:8080/actuator/metrics

Pada perintah di atas, kami telah menentukan total 10.000 permintaan menggunakan 10 utas bersamaan.

4.2. Pilihan

Apache Bench is able to very quickly give us some useful information including connection times and the percentage of requests that are served within a certain time.

For our purposes, we focused on requests-per-second and time-per-request (mean).

5. Results

On startup, we found that the memory footprint of Tomcat, Jetty, and Undertow was comparable with Undertow requiring slightly more memory than the other two and Jetty requiring the smallest amount.

For our benchmark, we found that the performance of Tomcat, Jetty, and Undertow was comparable but that Undertow was clearly the fastest and Jetty only slightly less fast.

Metric Tomcat Jetty Undertow
jvm.memory.used (MB) 168 155 164
jvm.classes.loaded 9869 9784 9787
jvm.threads.live 25 17 19
Requests per second 1542 1627 1650
Average time per request (ms) 6.483 6.148 6.059

Note that the metrics are, naturally, representative of the bare-bones project; the metrics of your own application will most certainly be different.

6. Benchmark Discussion

Developing appropriate benchmark tests to perform thorough comparisons of server implementations can get complicated. In order to extract the most relevant information, it's critical to have a clear understanding of what's important for the use case in question.

It's important to note that the benchmark measurements collected in this example were taken using a very specific workload consisting of HTTP GET requests to an Actuator endpoint.

It's expected that different workloads would likely result in different relative measurements across container implementations. If more robust or precise measurements were required, it would be a very good idea to set up a test plan that more closely matched the production use case.

In addition, a more sophisticated benchmarking solution such as JMeter or Gatling would likely yield more valuable insights.

7. Choosing a Container

Selecting the right container implementation should likely be based on many factors that can't be neatly summarized with a handful of metrics alone. Comfort level, features, available configuration options, and policy are often equally important, if not more so.

8. Conclusion

Pada artikel ini, kita melihat implementasi wadah servlet tertanam Tomcat, Jetty, dan Undertow. Kami memeriksa karakteristik runtime setiap penampung saat memulai dengan konfigurasi default dengan melihat metrik yang diekspos oleh komponen Actuator.

Kami menjalankan beban kerja yang dibuat-buat pada sistem yang sedang berjalan dan kemudian mengukur kinerja menggunakan Apache Bench.

Terakhir, kami membahas manfaat dari strategi ini dan menyebutkan beberapa hal yang perlu diingat saat membandingkan tolok ukur implementasi. Seperti biasa, semua kode sumber dapat ditemukan di GitHub.