Spring Boot vs Quarkus Performance | Benchmarking Guide Sinhala

Spring Boot vs Quarkus Performance | Benchmarking Guide Sinhala

ආයුබෝවන් යාළුවනේ!

අද අපි කතා කරන්න යන්නේ software engineering field එකේ ගොඩක් වැදගත්, ඒ වගේම programmersලා හැමදාම හොයන මාතෘකාවක් ගැන – ඒ තමයි Performance Benchmarking. විශේෂයෙන්ම, අපි ගොඩක් දෙනෙක් දන්න, පාවිච්චි කරන Spring Boot වගේ application framework එකක් කොච්චර වේගවත්ද, ඒ වගේම අලුතින් ආපු, cloud-native ලෝකයටම හැදුණු Quarkus වගේ framework එකක් එක්ක compare කරන්නේ කොහොමද කියලා අපි බලමු.

ඇයි මේ Performance Benchmarking අපිට වැදගත් වෙන්නේ?

අපි හැමෝම කැමතියි fast-loading website එකකට, ඉක්මනට response දෙන API එකකට. Slow වෙන application එකක් කියන්නේ user experience එකටත්, business එකටත් ලොකු පාඩුවක්. අද කාලේ microservices, serverless වගේ technologies එක්ක application develop කරනකොට, resource efficiency, startup time, memory footprint වගේ දේවල් ගොඩක් වැදගත් වෙනවා. පොඩි milliseconds ගාණක වෙනසක් වුණත්, ලොකු scale එකකදී මිලියන ගණන් user requests handle කරනකොට ඒක ලොකු බලපෑමක් ඇති කරනවා.

ලංකාවේ programmersලා අතරත් Spring Boot ගොඩක් ජනප්‍රියයි. ඒත්, අලුත් framework එනකොට, "අපේ application එක මේ අලුත් එකට වඩා කොච්චර වේගවත්ද නැත්තම් slow ද?" කියලා ප්‍රශ්නයක් එනවා. මේ ප්‍රශ්නයට උත්තර හොයාගන්න තමයි benchmarking කියන එක අපිට උදව් කරන්නේ.

මේ tutorial එකෙන් අපි බලමු:

  • Performance කියන්නේ හරියටම මොකක්ද?
  • Benchmarking කරන්න පාවිච්චි කරන tools මොනවද? (විශේෂයෙන් JMH)
  • Spring Boot සහ Quarkus වලින් simple REST API දෙකක් හදලා, ඒවා performance wise compare කරන්නේ කොහොමද කියලා.

එහෙනම්, අපි පටන් ගමු නේද?

1. Performance කියන්නේ හරියටම මොකක්ද?

ගොඩක් වෙලාවට අපි හිතන්නේ "fast" කියන එක විතරයි, ඒත් ඒක මීට වඩා ගැඹුරුයි. Software application එකක performance මනින ප්‍රධාන metrics කිහිපයක් තියෙනවා:

Startup Time (ආරම්භක කාලය)

  • application එකක් start වෙන්න ගතවන කාලය.
  • microservices architectures, serverless functions වගේ තැන් වලදී මේක ගොඩක් වැදගත්. ඉක්මනට start වෙනවා කියන්නේ requests වලට ඉක්මනට respond කරන්න පුළුවන්.
  • Cloud environments වලදී, ඉක්මන් startup එකක් auto-scaling වලටත්, cost efficiency එකටත් direct බලපෑමක් කරනවා.

Memory Footprint (මතක පරිභෝජනය)

  • application එකක් run වෙනකොට කොච්චර RAM එකක් පාවිච්චි කරනවද කියන එක.
  • Cloud environments වලදී අඩු memory usage එකක් කියන්නේ අඩු වියදමක්.
  • සීමිත resources තියෙන embedded systems වලදීත් මේක ගොඩක් වැදගත්.

Throughput (ප්‍රතිදානය)

  • ඒකක කාලයක් (උදා: තත්පරයක්) ඇතුළත application එකකට handle කරන්න පුළුවන් requests ගණන.
  • මේක වැඩි වෙන්න වැඩි වෙන්න, application එකට වැඩි user load එකක් දරාගන්න පුළුවන් වෙනවා.
  • TPS (Transactions Per Second) කියලත් සමහර වෙලාවට කියනවා.

Latency (ප්‍රමාදය)

  • application එකට request එකක් යවලා, response එකක් ලැබෙන්න ගතවන කාලය.
  • අඩු latency එකක් කියන්නේ user experience එක ගොඩක් හොඳයි කියන එක.
  • API calls වලදී, database queries වලදී මේක ගොඩක් වැදගත්.

CPU Usage (CPU භාවිතය)

  • application එක run වෙන්න කොච්චර CPU resources පාවිච්චි කරනවද කියන එක.
  • අඩු CPU usage එකක් කියන්නේ resource efficient බව සහ වැඩි requests ප්‍රමාණයක් handle කරන්න පුළුවන් බව.

මේ metrics තේරුම් ගැනීම benchmarking වලට කලින් අත්‍යවශ්‍යයි. මොකද, අපිට benchmark කරන්න ඕන මොන metric එකද කියලා අපි හරියටම දැනගෙන ඉන්න ඕන.

2. Benchmarking Tools සහ Methodologies

නිවැරදිව benchmark කරන්න නම් හරියටම plan කරන්න ඕනේ. අහඹු විදිහට test කරලා ගන්න results විශ්වාස කරන්න බැහැ. අපි Systematic Methodology එකක් follow කරන්න ඕන.

Systematic Benchmarking කියන්නේ මොකක්ද?

  • Controlled Environment: Benchmarking කරනකොට, වෙනත් processes හෝ services මගින් test එකට බාධා නොවන පරිසරයක් පාවිච්චි කරන්න ඕනේ.
  • Reproducibility: ඕනෑම වෙලාවක නැවතත් එම test එකම කරලා, එකම results ලබාගන්න පුළුවන් වෙන්න ඕනේ.
  • Realistic Workload: අපි application එකට දෙන load එක, real-world scenario එකකදී application එකට එන load එකට සමාන වෙන්න ඕනේ.
  • Multiple Runs: එක test එකක් කරලා තීරණ ගන්න එපා. Test එක කිහිප වතාවක් run කරලා, average result එක ගන්න.

JVM Benchmarking Tools: JMH (Java Microbenchmark Harness)

Java application වල performance measure කරන්න තියෙන standard tool එක තමයි JMH (Java Microbenchmark Harness). මේක Oracle විසින්ම හදපු, open-source tool එකක්.

JMH එකක් මගින් අපිට application එකේ specific code blocks වල performance මනින්න පුළුවන්. warmup iterations, measurement iterations, forks වගේ advanced concepts හරහා JMH එක මගින් JVM එකේ optimisations (JIT compilation, garbage collection) වගේ දේවල් වල බලපෑම අවම කරලා, වඩාත් නිවැරදි results ලබා දෙනවා.

JMH වල ප්‍රධාන concepts කිහිපයක්:

  • Warmup Iterations: මේවා actual measurement වලට කලින් JMH විසින් code එක run කරනවා. මේකෙන් වෙන්නේ JVM එක JIT compilation කරලා, code එක optimize කරන්න අවස්ථාව දෙන එක. මේක නැතුව කෙලින්ම measure කරොත්, JIT compilation වලට ගතවන කාලයත් measure වෙලා result වැරදි වෙන්න පුළුවන්.
  • Measurement Iterations: මේවා තමයි actual performance data collect කරන runs.
  • Forks: JMH මගින් එක් test එකක් වෙන වෙනම JVM instances කිහිපයක run කරනවා. මේකෙන් JVM state එකේ බලපෑම අවම කරලා, වඩාත් stable results ලබාගන්න පුළුවන්.
  • Modes: JMH එකට විවිධ modes තියෙනවා:
    • Throughput: ඒකක කාලයකට operations කීයක්ද.
    • AverageTime: එක් operation එකකට ගතවන සාමාන්‍ය කාලය.
    • SampleTime: එක් operation එකකට ගතවන කාලය distribution එකක් විදිහට.
    • SingleShotTime: එක් operation එකකට ගතවන කාලය (සමහර වෙලාවට startup time වගේ දේවල් වලට).

වෙනත් Load Testing Tools:

JMH micro-benchmarking වලට හොඳ වුණාට, end-to-end application testing වලට, specialy HTTP endpoints test කරන්න වෙන tools තියෙනවා:

  • Apache JMeter: ගොඩක් ජනප්‍රිය, GUI එකක් තියෙන tool එකක්.
  • Gatling: Scala වලින් ලියලා තියෙන, code-driven load testing tool එකක්.
  • k6: JavaScript වලින් scripts ලියන්න පුළුවන්, developer-friendly tool එකක්.
  • Locust: Python වලින් scripts ලියන්න පුළුවන් tool එකක්.

අපේ මේ tutorial එකේදී, අපි JMH මූලිකවම භාවිතා කරමු, මොකද අපිට අවශ්‍යයි code level එකේ performance වෙනස්කම් තේරුම් ගන්න.

3. Practical Comparison: Spring Boot vs. Quarkus

මේක තමයි අපේ වැඩේට හදවත. අපි මේකෙන් තමයි ඇත්තටම බලන්නේ කවුද දක්ෂයා කියලා. අපි Spring Boot සහ Quarkus වලින් simple REST API දෙකක් හදලා, ඒවායේ performance compare කරමු.

3.1: Building a Simple REST API with Spring Boot

මුලින්ම, අපි simple Spring Boot project එකක් හදාගමු. අපිට අවශ්‍ය වන්නේ basic REST endpoint එකක් විතරයි.

Step 1: Create a Spring Boot Project

ඔබට Spring Initializr (start.spring.io) එකෙන් හෝ ඔබේ IDE එකෙන් (IntelliJ IDEA, VS Code) project එකක් හදාගන්න පුළුවන්. Dependencies විදිහට Spring Web එකතු කරන්න.

Step 2: Create a Simple Controller

HelloController.java නමින් class එකක් හදලා මේ code එක ඇතුළත් කරන්න:

package com.example.springbootbenchmark.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/spring")
public class HelloController {

    @GetMapping("/hello")
    public String sayHello() {
        return "Hello from Spring Boot!";
    }
}

මේක බොහොම සරල REST endpoint එකක්. /api/spring/hello කියන path එකට request එකක් ආවම "Hello from Spring Boot!" කියලා String එකක් return කරනවා.

Step 3: Run the Spring Boot Application

ඔබේ IDE එකෙන් හෝ Maven/Gradle command එකකින් application එක run කරන්න පුළුවන්:

mvn spring-boot:run

Application එක start වුණාම, console එකේදී ඔබට startup time එක බලාගන්න පුළුවන්. සාමාන්‍යයෙන් තත්පර කිහිපයක් ගතවෙනවා.

3.2: Building the Same API with Quarkus

දැන් අපි ඒ හා සමාන REST API එකක් Quarkus වලින් හදමු. Quarkus කියන්නේ cloud-native development වලට හදපු framework එකක්. මේක JIT compilation වලට අමතරව GraalVM Native Image එකත් support කරනවා, ඒකෙන් startup time සහ memory footprint ගොඩක් අඩු වෙනවා.

Step 1: Create a Quarkus Project

Quarkus project එකක් හදාගන්න ඔබට Quarkus CLI එක හෝ Maven/Gradle CLI එක පාවිච්චි කරන්න පුළුවන්:

mvn io.quarkus.platform:quarkus-maven-plugin:2.16.8.Final:create \
    -DprojectGroupId=com.example.quarkusbenchmark \
    -DprojectArtifactId=quarkus-benchmark-app \
    -DclassName="com.example.quarkusbenchmark.HelloResource" \
    -Dpath="/api/quarkus/hello"

මේකෙන් basic Quarkus project එකක් හදනවා, ඒ වගේම quarkus-resteasy-reactive extension එකත් add කරනවා.

Step 2: Create a Simple Resource

HelloResource.java file එකේ මේ code එක ඇතුළත් කරන්න (සාමාන්‍යයෙන් create command එකෙන් මේක generate වෙනවා):

package com.example.quarkusbenchmark;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/api/quarkus")
public class HelloResource {

    @GET
    @Path("/hello")
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "Hello from Quarkus!";
    }
}

මේක Spring Boot එකේ වගේම සරල REST endpoint එකක්. /api/quarkus/hello කියන path එකට request එකක් ආවම "Hello from Quarkus!" කියලා String එකක් return කරනවා.

Step 3: Run the Quarkus Application

Quarkus application එක run කරන්න ක්‍රම දෙකක් තියෙනවා:

Native Image Mode (Production):

mvn package -Pnative
./target/quarkus-benchmark-app-runner

මේකෙන් GraalVM භාවිතයෙන් native executable එකක් generate කරනවා. මේක build වෙන්න ටිකක් වෙලා යනවා, ඒත් build වුණාට පස්සේ startup time එක milliseconds ගාණකට අඩු වෙනවා, memory footprint එකත් ගොඩක් අඩුයි. මේක තමයි cloud-native deployments වලදී Quarkus වල ප්‍රධාන වාසිය.

JVM Mode (Development/Hot Reload):

mvn quarkus:dev

මේක development වලදී hot-reload support කරනවා. Startup time එක Spring Boot එකට වඩා වේගවත් වෙන්න පුළුවන්.

Quarkus native image එක run කරලා බලන්න. startup time එකේ සහ memory usage එකේ ලොකු වෙනසක් ඔබට පෙනෙයි.

3.3: Benchmarking Setup with JMH

දැන් අපි මේ application දෙකේ HTTP endpoints JMH වලින් benchmark කරන්නේ කොහොමද කියලා බලමු. මේ සඳහා අපිට වෙනම Maven project එකක් හදාගන්න පුළුවන්.

Step 1: Create a JMH Project

Maven archetype එකකින් JMH project එකක් හදාගන්න පුළුවන්:

mvn archetype:generate -DinteractiveMode=false \
    -DarchetypeGroupId=org.openjdk.jmh \
    -DarchetypeArtifactId=jmh-java-benchmark-archetype \
    -DgroupId=com.example.benchmark \
    -DartifactId=app-benchmarks \
    -Dversion=1.0-SNAPSHOT

මේකෙන් app-benchmarks නමින් project එකක් හදනවා.

Step 2: Add HTTP Client Dependency

අපිට HTTP requests යවන්න client එකක් අවශ්‍යයි. අපි OkHttp හෝ Apache HttpClient වගේ library එකක් පාවිච්චි කරමු. pom.xml එකට මේ dependency එක add කරන්න:

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.10.0</version> <!-- හෝ නවතම version එක -->
</dependency>

Step 3: Write the JMH Benchmark Class

MyBenchmark.java වගේ class එකක් src/main/java/com/example.benchmark folder එකේ හදලා මේ වගේ code එකක් ඇතුළත් කරන්න:

package com.example.benchmark;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

@State(Scope.Benchmark)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@BenchmarkMode(Mode.AverageTime)
@Fork(value = 1, warmups = 0)
@Warmup(iterations = 2, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
public class HttpEndpointBenchmark {

    private OkHttpClient client;

    // Before each benchmark run, initialize the HTTP client
    @Setup(Level.Trial)
    public void setup() {
        client = new OkHttpClient();
        // Ensure the applications are running before starting benchmarks
        // This part would typically be handled by an external script or separate setup
        System.out.println("Ensuring Spring Boot and Quarkus apps are running...");
        // You might add logic here to ping endpoints to ensure they are up
    }

    // After all benchmarks for this class are done, close resources
    @TearDown(Level.Trial)
    public void teardown() {
        client = null;
    }

    @Benchmark
    public void callSpringBootHello(Blackhole bh) throws IOException {
        Request request = new Request.Builder()
                .url("http://localhost:8080/api/spring/hello") // Spring Boot app runs on 8080
                .build();
        try (Response response = client.newCall(request).execute()) {
            bh.consume(response.body().string());
        }
    }

    @Benchmark
    public void callQuarkusHello(Blackhole bh) throws IOException {
        Request request = new Request.Builder()
                .url("http://localhost:8080/api/quarkus/hello") // Quarkus app also runs on 8080 by default
                .build();
        try (Response response = client.newCall(request).execute()) {
            bh.consume(response.body().string());
        }
    }

    // It's crucial that one app runs on a different port if both are run simultaneously
    // For this benchmark to work correctly, run Spring Boot on 8080 and Quarkus on 8081
    // For Quarkus, you can change the port in application.properties: quarkus.http.port=8081
    // For Spring Boot, in application.properties: server.port=8080
}

වැදගත් සටහන: Spring Boot සහ Quarkus application දෙකම එකම 8080 port එකේ run වෙන්න හදනවා. Benchmarking කරනකොට, එක් application එකක් 8080 port එකෙත්, අනෙක් application එක 8081 වගේ වෙනත් port එකකත් run කරන්න ඕනේ. application.properties file එකේ server.port (Spring Boot) හෝ quarkus.http.port (Quarkus) change කරන්න.

Step 4: Run the JMH Benchmark

JMH benchmark එක run කරන්න, JMH project එකේ root folder එකේදී මේ command එක දෙන්න:

java -jar target/benchmarks.jar

මේකෙන් JMH benchmarks run වෙලා console එකේ results print කරනවා. ඔබට AverageTime, Score වගේ values බලාගන්න පුළුවන්. JMH report එකේ එක් operation එකකට ගතවන සාමාන්‍ය කාලය milliseconds වලින් පෙන්නනවා.

3.4: Analyzing Results

JMH results බැලුවාම ඔබට Score කියන column එකේදී Spring Boot සහ Quarkus API calls වලට ගතවන AverageTime එක බලාගන්න පුළුවන් වේවි. සාමාන්‍යයෙන්, Quarkus (විශේෂයෙන් native image mode එකෙන් run කරනකොට) startup time එක සහ memory footprint එක ගොඩක් අඩුයි. Throughput එකත් සමහර use cases වලදී Spring Boot එකට වඩා වැඩි වෙන්න පුළුවන්.

අපේක්ෂිත ප්‍රතිඵල (Expected Results):

  • Startup Time: Quarkus native image එකේ startup time එක milliseconds කිහිපයක් වෙන්න පුළුවන්, Spring Boot එකට තත්පර කිහිපයක් ගතවෙන්න පුළුවන්. JVM mode එකේ Quarkus ටිකක් වේගවත් වෙන්න පුළුවන්.
  • Memory Footprint: Quarkus native image එකේ memory usage එක ගොඩක් අඩුයි (megabytes කිහිපයක්). Spring Boot එකට ඊට වඩා වැඩි memory ප්‍රමාණයක් (ගොඩක් වෙලාවට 100MB+ ) අවශ්‍ය වෙනවා.
  • Throughput/Latency: Simple REST endpoints වලට JMH වලින් මනිනකොට, Quarkus native image එක තරමක් හොඳ throughput/latency values පෙන්නන්න පුළුවන්. JVM mode එකේදී, Spring Boot සහ Quarkus අතර ලොකු වෙනසක් නැති වෙන්නත් පුළුවන්, workload එක අනුව මේක වෙනස් වෙනවා.

මේකෙන් අපිට තේරෙනවා අපි මොන වගේ application එකක් හදනවද කියන එකට අනුව framework එක තෝරගන්න එක කොච්චර වැදගත්ද කියලා. Cloud-native microservices, serverless functions වගේ තැන් වලදී low startup time සහ low memory footprint ගොඩක් වැදගත්. ඒ වගේ තැන් වලට Quarkus වගේ framework එකක් ඉතාම සුදුසුයි. Developer productivity, large enterprise applications, existing Spring ecosystem integration වගේ දේවල් වලට Spring Boot තවමත් powerhouse එකක්.

අවසාන වචනය (Conclusion)

අද අපි Spring Boot සහ Quarkus වැනි Java frameworks වල performance benchmarking කරන්නේ කොහොමද කියන එක ගැන විස්තරාත්මකව ඉගෙන ගත්තා. Performance කියන්නේ මොකක්ද, ඒක මනින metrics මොනවද, JMH වගේ tools පාවිච්චි කරන්නේ කොහොමද වගේ දේවල් ගැන අපි කතා කළා.

අපි දැක්කා Spring Boot කියන්නේ විශාල community එකක් සහ feature-rich ecosystem එකක් තියෙන framework එකක් කියලා. ඒ වගේම Quarkus කියන්නේ cloud-native applications වලට, අඩු startup time සහ memory footprint එකක් අවශ්‍ය applications වලට විශිෂ්ට විසඳුමක් කියලා. අවසාන වශයෙන්, "හොඳම framework එක" කියලා එකක් නැහැ, තියෙන්නේ ඔබේ project එකේ අවශ්‍යතාවලට ගැලපෙනම framework එකයි.

අලුත් project එකක් පටන් ගන්නකොට හෝ existing project එකක performance වැඩි දියුණු කරන්න බලනකොට, මේ benchmarking concepts සහ tools මතක තියාගන්න. මේකෙන් ඔබට ඔබේ application එකට හොඳම තීරණය ගන්න පුළුවන් වේවි.

ඔයාලත් මේක කරලා බලලා ඔයාලගේ අත්දැකීම් comment section එකේ කියන්න! Quarkus native image එකේ performance දැක්කාම ඔයාලට පුදුම හිතෙයි! ඔබේ මිතුරන් සමඟත් මේ ලිපිය share කරන්න, ඔවුන්ටත් මේ වටිනා දැනුම ලබාගන්න පුළුවන්.

ඉදිරියේදී මේ වගේම තවත් වටිනා tutorials එකකින් හමුවෙමු! ස්තූතියි!