Spring Boot Slow Startup Fixes | Performance Optimization Sinhala

Spring Boot Slow Startup Fixes | Performance Optimization Sinhala

ආයුබෝවන් යාළුවනේ! අද අපි කතා කරන්නේ Spring Boot developers ලා හැමෝටම වගේ මුහුණ දෙන්න සිද්ධ වෙන පොදු ප්‍රශ්නයක් ගැන – ඒ තමයි application එක slow startup වෙන එක. ඔයාටත් මේ ප්‍රශ්නේ තියෙනවා නම්, මේ guide එක ඔයාට ගොඩක් වැදගත් වෙයි. අපි බලමු ඇයි මෙහෙම වෙන්නේ කියලා, කොහොමද හොයාගන්නේ කියලා, සහ කොහොමද fix කරන්නේ කියලා.

නවීන software development වලදී, application එකක startup time එක කියන්නේ user experience එකට වගේම developer productivity එකටත් කෙලින්ම බලපාන දෙයක්. Spring Boot වගේ frameworks වේගවත් development වලට උදව් වුණත්, සමහර වෙලාවට වැරදි configuration හෝ design decisions නිසා startup එක slow වෙන්න පුළුවන්. ඒ නිසා, මේ ගැටලුව තේරුම් අරගෙන, ඒකට නිවැරදි විසඳුම් හොයාගැනීම අත්‍යවශ්‍යයි.

ඇයි අපේ Spring Boot App එක Slow වෙන්නේ? (Why is our Spring Boot App Slowing Down?)

හොඳයි, මේකට හේතු ගොඩක් තියෙන්න පුළුවන්. ප්‍රධාන හේතු කීපයක් මෙන්න:

  • අධික Component Scanning: Spring Boot application එකක් startup වෙනකොට, ඒක classpath එකේ තියෙන සියලුම Spring components (@Component, @Service, @Repository, @Controller වගේ annotations තියෙන classes) scan කරනවා. ඔයාගේ project එක ගොඩක් විශාල නම්, මේකට ගොඩක් වෙලා යන්න පුළුවන්. අනවශ්‍ය packages scan කිරීමෙන් startup time එක වැඩි වෙනවා.
  • Database Initialization: Application එක startup වෙනකොට database schemas (Flyway, Liquibase වගේ tools වලින්) initialize කරනවා නම්, හෝ ගොඩක් data load කරනවා නම්, මේක startup time එකට බලපානවා. විශේෂයෙන්ම large schemas හෝ seed data විශාල ප්‍රමාණයක් තිබේනම්.
  • බාහිර සේවාවන්ට කරන ඇමතුම් (External Service Calls): සමහර වෙලාවට application එක startup වෙනකොට external APIs වලට call කරනවා, හෝ external services (Kafka, RabbitMQ, Redis වගේ) වලට connect වෙන්න හදනවා. මේවා slow වුනොත්, startup එකත් slow වෙනවා. External service එකක් unavailable වුනොත් timeout වෙන්නත් පුළුවන්.
  • සංකීර්ණ Bean Definitions සහ Dependencies: ඔයාගේ beans වලට ගොඩක් dependencies තියෙනවා නම්, හෝ ඒවා initialize වෙන්න ගොඩක් process කරන්න ඕනේ නම්, ඒකත් වෙලාව ගන්න පුම්ළුවන්. Cyclic dependencies හෝ complex object graph එකක් මේකට හේතු වෙන්න පුළුවන්.
  • Classpath Issues: ඔයාගේ project එකේ unused libraries, හෝ එකම library එකේ versions ගොඩක් (dependency conflicts) තියෙනවා නම්, මේවා scan කරන්න වෙලා යන්න පුළුවන්. Classpath එකේ විශාලත්වයත් මෙයට බලපානවා.
  • Logging Level: Development වලදී DEBUG හෝ TRACE level එකේ logging දාගෙන ඉන්නකොට, startup එකේදී ගොඩක් logs generate වෙනවා. මේකත් සුළු වශයෙන් බලපානවා, විශේෂයෙන්ම disk I/O එක වැඩි කරනවා.

ගැටලුව හඳුනාගනිමු (Diagnosing the Problem)

හේතුව මොකක්ද කියලා දැනගත්තොත් විතරයි අපිට ඒක fix කරන්න පුළුවන්. මෙන්න ඔයාට පාවිච්චි කරන්න පුළුවන් ක්‍රම කීපයක්.

Spring Boot Actuator භාවිතයෙන් (Using Spring Boot Actuator)

Spring Boot Actuator කියන්නේ production-ready features ගොඩක් තියෙන powerful tool එකක්. Application startup එක analyze කරන්න /actuator/startup endpoint එක පාවිච්චි කරන්න පුළුවන්. මේක Spring Boot 2.3+ වලින් තමයි හඳුන්වා දුන්නේ.

මුලින්ම ඔයාගේ pom.xml එකට Actuator dependency එක add කරගන්න:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

ඊට පස්සේ, application.properties (හෝ .yml) එකට මේ settings ටික එකතු කරන්න, /startup endpoint එක enable කරන්න:

management.endpoints.web.exposure.include=health,info,startup
management.endpoint.startup.enabled=true

දැන් application එක run කරලා, http://localhost:8080/actuator/startup (ඔයාගේ port එක වෙනස් වෙන්න පුළුවන්) එකට ගියාම, ඔයාට startup process එකේ detailed breakdown එකක් බලාගන්න පුළුවන්. මේකෙන් මොන bean එක initialize වෙන්න කොච්චර වෙලා ගියාද කියලා හරියටම පේනවා. මේ JSON output එකේදී, startupSteps කියන array එක ඇතුළේ ඔයාට individual component initialization times බලාගන්න පුළුවන්.

Custom Logging සහ Timing (Custom Logging and Timing)

තව ක්‍රමයක් තමයි ඔයාගේ code එකේ key sections වලට timing logs add කරන එක. මේක සරලයි, ඒත් ගොඩක් effective. විශේෂයෙන්ම, @EventListener annotation එක ApplicationStartedEvent එකත් එක්ක පාවිච්චි කරලා, application context එක load වුණාට පස්සේ වෙලාව බලන්න පුළුවන්.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@SpringBootApplication
public class SlowStartupApplication {

    private static final Logger log = LoggerFactory.getLogger(SlowStartupApplication.class);
    private static long appStartMillis;

    public static void main(String[] args) {
        appStartMillis = System.currentTimeMillis();
        SpringApplication.run(SlowStartupApplication.class, args);
    }

    @EventListener
    public void handleApplicationStartedEvent(ApplicationStartedEvent event) {
        long end = System.currentTimeMillis();
        log.info("Application started in: {} ms", (end - appStartMillis));
    }

    // Example of timing a specific component initialization
    @Component
    public static class MySlowService {
        public MySlowService() throws InterruptedException {
            long serviceStart = System.currentTimeMillis();
            // Simulate a slow initialization process (e.g., loading large dataset, external call)
            Thread.sleep(2000); 
            log.info("MySlowService initialized in: {} ms", (System.currentTimeMillis() - serviceStart));
        }
    }
}

මේ code එකෙන් main method එකේ සම්පූර්ණ startup time එකයි (ApplicationStartedEvent එක හරහා), MySlowService එක initialize වෙන්න ගත්ත වෙලාවයි print කරනවා. මේ වගේ logs දාලා ඔයාට slow වෙන්නේ මොන parts ද කියලා අඳුරගන්න පුළුවන්. MySlowService එකේදී අපි Thread.sleep(2000) දාලා තියෙන්නේ slow initialization එකක් simulate කරන්නයි.

Startup වේගවත් කරමු (Optimizing Startup Time)

හොඳයි, දැන් අපි ගැටලුව හඳුනාගත්තා. දැන් බලමු ඒක fix කරන්නේ කොහොමද කියලා.

Component Scan එක අඩුකරමු (Reduce Component Scanning)

නිතරම මතක තියාගන්න, Spring Boot application එකේ base package එකට අමතරව වෙනත් package scan කරන්න අවශ්‍ය නම් විතරක් @ComponentScan annotation එකේ basePackages (හෝ basePackageClasses) attribute එක specify කරන්න. අනවශ්‍ය packages scan කිරීමෙන් වළකින්න. විශාල libraries හෝ third-party code scan නොකිරීමට වගබලා ගන්න.

තව දෙයක් තමයි, @Lazy annotation එක. යම්කිසි bean එකක් application startup එකේදී initialize නොවී, ඒක මුලින්ම request කරන වෙලාවේදී initialize වෙන්න සලස්වන්න මේක පාවිච්චි කරන්න පුළුවන්. හැබැයි මේක හැම bean එකකටම දාන්න එපා, අවශ්‍ය තැන් වලට විතරක් යොදවන්න. මොකද මේකෙන් startup time එක අඩු වුණාට, පළවෙනි request එක slow වෙන්න පුළුවන්. ඒ නිසා, මේක පාවිච්චි කරන්න ඕනේ startup එකේදී අනිවාර්යයෙන්ම අවශ්‍ය නැති, ඒ වගේම භාවිතය කලාතුරකින් සිදුවන beans සඳහායි.

import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

@Service
@Lazy // This bean will be initialized only when it's first used
public class ReportGeneratorService {
    public ReportGeneratorService() {
        System.out.println("ReportGeneratorService is being initialized (lazily).");
    }
    
    public String generateReport() {
        return "Report Generated!";
    }
}

Database Initialization Optimize කරමු (Optimize Database Initialization)

application.properties එකේ spring.sql.init.mode=never කියලා දාලා application startup එකේදී database scripts run වීම වළක්වන්න පුළුවන්. මේක හොඳයි production environment වලදී, අපි manual script deployments කරනවා නම්.

තවද, Spring Boot 2.5 සිට spring.datasource.initialization-mode වෙනුවට spring.sql.init.mode භාවිත වෙනවා. defer-datasource-initialization කියන property එක Spring Boot 2.5+ වල තියෙනවා, ඒකෙන් DataSource initialization එක application startup එකෙන් පස්සේ වෙන තෙක් කල් දාන්න පුළුවන්. මේක බොහෝ විට database connection pool එකක් init කිරීමට ගතවන කාලය startup time එකෙන් ඉවත් කිරීමට උපකාරී වෙනවා.

# Disable automatic SQL script execution on startup
spring.sql.init.mode=never

# For older Spring Boot versions (pre 2.5), use this:
# spring.datasource.initialization-mode=never 

# Defer DataSource initialization until after application startup (Spring Boot 2.5+)
spring.datasource.defer-datasource-initialization=true 

Flyway/Liquibase වගේ tools පාවිච්චි කරනවා නම්, ඒවායේ validation settings (flyway.validate-on-migrate=false, liquibase.validate-on-update=false) වගේ දේවල් production වලදී disable කරන්න පුළුවන්, මොකද ඒවාත් startup එකට වෙලා ගන්න පුළුවන්. හැබැයි මේවා off කරද්දි production වලදී schema drift වගේ issues එන්න පුළුවන් නිසා, ඒවා handle කරන විදිය ගැන හොඳ අවබෝධයක් තියෙන්න ඕනේ.

බාහිර සේවාවලට කරන ඇමතුම් කළමනාකරණය (Manage External Service Calls)

Startup එකේදී external services වලට call කරනවා නම්, ඒවා @Lazy load කරන්න පුළුවන්ද බලන්න, නැතිනම් @Async methods පාවිච්චි කරලා වෙන Thread එකකින් execute කරන්න. මේකෙන් startup thread එක block නොවී, application එක ඉක්මනින් up කරන්න පුළුවන්. @Async පාවිච්චි කරනවා නම්, @EnableAsync annotation එක configuration class එකකට දාන්න අමතක කරන්න එපා.

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
public class ExternalDataLoader {

    @Async
    public void loadDataAsync() {
        System.out.println("Loading external data in a separate thread...");
        try {
            Thread.sleep(5000); // Simulate slow external call
            System.out.println("External data loaded successfully!");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

මෙහිදී, ExternalDataLoader bean එක @Async හරහා වෙනම thread එකකින් run වෙන නිසා, main startup thread එක block වෙන්නේ නෑ.

Unused Dependencies අයින් කරමු (Remove Unused Dependencies)

ඔයාගේ pom.xml එක හෝ build.gradle එක review කරලා, project එකට අවශ්‍ය නැති dependencies ටික අයින් කරන්න. මේකෙන් classpath එකේ size එක අඩු වෙනවා වගේම, build time සහ startup time දෙකම අඩු වෙනවා. විශේෂයෙන්ම, spring-boot-starter dependencies වලට අමතරව තව starters එකතු කරලා තියෙනවා නම්, ඒවා ඇත්තටම අවශ්‍යද කියලා දෙවරක් හිතන්න.

Logging Level එක සකස් කරමු (Adjust Logging Level)

Production environment වලදී application.properties එකේ logging.level.root=WARN හෝ ERROR වගේ high level එකක් set කරන්න. මේකෙන් అనවශ්‍ය logs print වීම වළක්වනවා, ඒ වගේම startup එකේදී disk I/O එක අඩු කරනවා. Development වලදී DEBUG level එක අවශ්‍ය වුණත්, production වලදී මේකෙන් performance issue එන්න පුළුවන්.

# Set root logging level to WARN for production
logging.level.root=WARN

# Or for specific packages to control verbosity
logging.level.org.springframework=WARN
logging.level.com.yourcompany.yourapp=INFO # Keep your app's logs at INFO or DEBUG if needed

අවසන් වශයෙන් (Conclusion)

ඉතින් යාළුවනේ, Spring Boot application එකක slow startup එකක් කියන්නේ පොදු ප්‍රශ්නයක් වුණාට, ඒක diagnose කරලා fix කරන්න පුළුවන්. මේ guide එකේ තියෙන steps follow කරලා ඔයාලගේ applications වල startup time එක optimize කරන්න ඔයාලට පුළුවන් වෙයි. මතක තියාගන්න, හැම optimize කිරීමක්ම ඔයාගේ application එකේ context එක අනුව වෙනස් වෙනවා. හොඳම ප්‍රතිඵල ගන්න නම්, ක්‍රමානුකූලව explore කරලා, test කරලා බලන්න. /actuator/startup endpoint එක වගේ tools වලින් ලැබෙන information හොඳින් analyze කරලා, ඊට අදාලව නිවැරදි optimizations යොදවන්න.

ඔයාලටත් මේ වගේ ප්‍රශ්න ආවද? කොහොමද solve කරගත්තේ? ඔයාලගේ අත්දැකීම් අපිත් එක්ක share කරගන්න! පහළින් comment එකක් දාන්න! ඊළඟ project එකේදී මේ tips implement කරලා බලන්න. සුබ coding!