Spring Cloud හැඳින්වීම: Distributed Systems වල බලය Lankan Style - SC Guide

Spring Cloud හැඳින්වීම: Distributed Systems වල බලය Lankan Style - SC Guide

ආයුබෝවන්, කොහොමද ඉතින් ඔයාලට? අද අපි කතා කරන්න යන්නේ මේ දවස්වල software development field එකේ හරිම වැදගත් මාතෘකාවක් ගැන – ඒ තමයි Spring Cloud.

දැන් Microservices architecture එක කියන්නේ කවුරුත් දන්න, ගොඩක් අය use කරන concept එකක්නේ. කලින් වගේ ලොකු, තනි Monolithic application හදනවා වෙනුවට, පොඩි පොඩි services ගොඩක් හදලා ඒවා එකට connect කරලා, ලොකු system එකක් build කරන එක තමයි Microservices වලින් කරන්නේ. මේකේ ලොකු වාසි ගොඩක් තියෙනවා – scalable කරන්න පුළුවන්, maintain කරන්න ලේසියි, fault isolation වගේ දේවල්.

හැබැයි, මේ පොඩි services ගොඩක් manage කරන එකත් ලේසි වැඩක් නෙවෙයි. Services එකිනෙකා හොයාගන්නේ කොහොමද? Configuration manage කරන්නේ කොහොමද? Requests බෙදලා දෙන්නේ කොහොමද? මේ වගේ ප්‍රශ්න ගොඩක් එනවා. මේ ප්‍රශ්න වලට උත්තර දෙන්න, distributed systems පහසුවෙන් හදන්න අපිට ලොකු උදව්වක් වෙනවා Spring Cloud.

ඉතින් අද මේ ලිපියෙන් අපි Spring Cloud කියන්නේ මොකක්ද, ඒකේ තියෙන ප්‍රධාන components මොනවද, සහ පුංචි project එකක් පටන් අරන් Spring Cloud වල බලය කොහොමද use කරන්නේ කියලා බලමු. ඔයා දැනටමත් Spring Boot එක්ක වැඩ කරන කෙනෙක් නම්, මේක ඔයාට ලොකු අමතර දැනුමක් වෙයි. එහෙනම් අපි පටන් ගමු!

Distributed Systems සහ Spring Cloud: මූලික අදහස

කලින් කිව්වා වගේ, සාම්ප්‍රදායික Monolithic application එකක හැමදේම තියෙන්නේ එකම code base එකක, එකම server එකක. ඒක develop කරන්න ලේසියි වගේ පෙනුනත්, application එක ලොකු වෙනකොට, users ලා වැඩි වෙනකොට, ඒක maintain කරන එක, scale කරන එක හරිම අමාරු වෙනවා. පොඩි change එකක් කරන්නත් whole application එක redeploy කරන්න වෙනවා, එක තැනක අවුලක් ගියොත් whole system එකම වැටෙන්න පුළුවන්.

Distributed system එකකදී අපි application එක පොඩි පොඩි, ස්වාධීන services වලට කඩනවා. මේ services එකිනෙකාත් එක්ක communicate කරන්නේ network calls (බොහෝ වෙලාවට REST APIs) හරහා. මේකෙන් ලැබෙන වාසි තමයි:

  • Scalability: වැඩිපුර load එකක් එන service එක විතරක් scale කරන්න පුළුවන්.
  • Resilience: එක service එකක් crash උනොත්, අනිත් services වැඩ කරනවා. සම්පූර්ණ system එකම වැටෙන්නේ නැහැ.
  • Flexibility: විවිධ services වලට විවිධ technologies use කරන්න පුළුවන්.
  • Independent Deployment: වෙනම deploy කරන්න පුළුවන් නිසා deployment process එක වේගවත් වෙනවා.

හැබැයි, මේ වාසිත් එක්කම අලුත් අභියෝග ගොඩකුත් එනවා. Services එකිනෙකා හොයාගන්නේ කොහොමද? (Service Discovery), services අතර communication එක ආරක්ෂිතව කරන්නේ කොහොමද? (Load Balancing), distributed system එකේ errors manage කරන්නේ කොහොමද? (Circuit Breaking), configurations manage කරන්නේ කොහොමද? (Distributed Configuration) මේ වගේ ප්‍රශ්න ගොඩක්. Spring Cloud කියන්නේ හරියට මේ අභියෝග වලටම පිළිතුරු දෙන, Spring Boot මත හැදිච්ච framework එකක්. ඒකෙන් distributed systems හදන එක හරිම පහසු කරනවා.

Spring Cloud වල ප්‍රධාන Components: ටිකක් විතර විස්තර

Spring Cloud කියන්නේ එක technology එකක් නෙවෙයි, ඒක components ගොඩක එකතුවක්. ඒ හැම component එකක්ම distributed systems වල තියෙන අභියෝගයකට විසඳුමක් දෙනවා. අපි ප්‍රධාන components ටිකක් ගැන බලමු.

1. Spring Cloud Netflix Eureka (Service Discovery)

නිකන් හිතන්නකෝ ඔයාට යාළුවෝ ගොඩක් ඉන්නවා කියලා. ඔයාට කෙනෙක් එක්ක කතා කරන්න ඕන නම්, ඔයා එයාගේ phone number එක හොයාගන්න ඕනේ නේද? Eureka Server එක කියන්නේ මේ phone book එක වගේ. Microservices deploy කරාම, ඒ හැම service එකක්ම Eureka Server එකට ගිහින් "මම මේ address එකෙන් ඉන්නවා, මේ තමයි මගේ නම" කියලා register වෙනවා. අනිත් services වලට, කා එක්ක හරි කතා කරන්න ඕන උනාම, ඒ අය Eureka Server එකෙන් අහනවා "අර service එක කොහෙද ඉන්නේ?" කියලා. මේකෙන් services වලට එකිනෙකා ගැන දැනගෙන communicate කරන්න පුළුවන් වෙනවා. මේක distributed systems වල අත්‍යවශ්‍යම අංගයක්.

2. Spring Cloud Config (Distributed Configuration)

Distributed system එකක services ගොඩක් තියෙන නිසා, ඒ හැම service එකටම තමන්ගේම configuration file එකක් තියෙනවා. මේවා වෙනස් කරන්න, manage කරන්න හරිම අමාරුයි. Spring Cloud Config Server එකෙන් කරන්නේ මේ හැම configuration file එකක්ම centrally manage කරන එක. ගොඩක් වෙලාවට මේවා Git repository එකක තියලා, Config Server එකෙන් ඒවට access දෙනවා. එතකොට services වලට අවශ්‍ය configurations Config Server එකෙන් අරගන්න පුළුවන්. ඒ වගේම, runtime එකේදී configurations වෙනස් කරන්නත් පුළුවන්.

3. Spring Cloud Gateway (API Gateway)

ඔයාගේ system එකට requests එනකොට, ඒ හැම request එකක්ම හැම service එකකටම යවනවාද? නැහැ. API Gateway එක කියන්නේ system එකට ඇතුල් වෙන Single Entry Point එක. Client එකක් requests කරන්නේ API Gateway එකට. Gateway එකෙන් ඒ requests අදාළ service එකට route කරනවා. මේකෙන් load balancing, security, monitoring, request filtering වගේ දේවල් කරන්නත් පුළුවන්. System එකේ internal structure එක client එකෙන් හංගලා තියන්නත් පුළුවන්.

4. Spring Cloud LoadBalancer (Client-side Load Balancing)

ඒකම service එකේ instances ගොඩක් තියෙනවා නම්, requests ඒ අතරේ බෙදලා දෙන්න ඕන. LoadBalancer එකෙන් කරන්නේ requests evenly distribute කරන එක. Spring Cloud Netflix Ribbon (දැන් maintenance mode එකේ) වගේ දේවල් තිබුණා, දැන් Spring Cloud LoadBalancer කියන module එකෙන් ඒක කරනවා. Client-side load balancing කියන්නේ, client එකම තමයි load balance කරන්නේ. එයා Eureka Server එකෙන් service instances ටික අරගෙන, ඒ අතරින් request යවන්න හොඳම instance එක තෝරගන්නවා.

5. Spring Cloud CircuitBreaker (Resilience)

Distributed system එකකදී, එක service එකක් down උනොත්, ඒකෙන් call වෙන අනිත් services වලටත් බලපාන්න පුළුවන්. මේක "Cascading Failure" එකක් විදිහට මුළු system එකටම පැතිරෙන්න පුළුවන්. CircuitBreaker එකක් කියන්නේ මේක වලක්වන mechanism එකක්. නිකන් විදුලි පරිපථයක circuit breaker එක වගේමයි. Service එකක් malfunction කරනවා කියලා හඳුනාගත්තාම, ඒකට යන calls ටික වෙලාවකට නවත්තනවා. ඒකෙන් එම service එකට restore වෙන්න කාලය ලැබෙනවා. Resilience4j කියන්නේ Spring Cloud CircuitBreaker implementation එකට භාවිතා කරන ජනප්‍රිය library එකක්.

6. Spring Cloud Sleuth & Zipkin (Distributed Tracing)

requests එකක් services ගොඩක් අතරින් ගමන් කරනකොට, ඒකේ flow එක තේරුම් ගන්න එක හරිම අමාරුයි. Sleuth එකෙන් කරන්නේ, හැම request එකකටම unique ID එකක් (trace ID) දෙන එක. මේ ID එක request එක යන හැම service එකක් හරහාම යනවා. Zipkin වගේ tool එකක් එක්ක use කරාම, මේ trace ID එක use කරලා request එකේ සම්පූර්ණ flow එක graphical විදිහට බලන්න පුළුවන්. මේක debugging වලට සහ monitoring වලට හරිම වැදගත්.

Project එකක් පටන් ගමු: Eureka Server එකක් සහ Clients

හරි, දැන් අපි theoretical පැත්තෙන් ටිකක් ඉගෙන ගත්තා. දැන් බලමු practical විදිහට මේවා කොහොමද use කරන්නේ කියලා. අපි සරල Spring Cloud Eureka Server එකක් සහ ඒකට register වෙන Eureka Clients දෙකක් හදමු.

Step 1: Maven Project එකක් හදාගමු

මුලින්ම, අපිට project තුනක් අවශ්‍ය වෙනවා: Eureka Server එකට එකක්, සහ Clients දෙකට තව දෙකක්. මේවා Spring Initializr (start.spring.io) හරහා පහසුවෙන් generate කරගන්න පුළුවන්.

පළමු Project එක: eureka-server

  • Project Type: Maven Project
  • Language: Java
  • Spring Boot Version: (ඔබ කැමති නවතම stable version එකක් තෝරන්න, උදා: 3.2.x)
  • Dependencies: Eureka Server

Generate කරාට පස්සේ, pom.xml එක මේ වගේ වෙන්න ඕනේ:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.5</version> <!-- Update to your chosen version -->
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>eureka-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>eureka-server</name>
    <description>Demo Eureka Server</description>
    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2023.0.1</spring-cloud.version> <!-- Match with Spring Boot 3.2.x -->
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

දෙවන සහ තුන්වන Project: service-client-1 සහ service-client-2

  • Project Type: Maven Project
  • Language: Java
  • Spring Boot Version: (ඔබ කැමති නවතම stable version එකක් තෝරන්න, උදා: 3.2.x)
  • Dependencies: Eureka Discovery Client, Spring Web

මේ clients දෙකටම එකම pom.xml එක සහ dependencies තියෙන්නේ. pom.xml එක මේ වගේ වෙන්න ඕනේ:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.5</version> <!-- Update to your chosen version -->
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>service-client-1</artifactId> <!-- හෝ service-client-2 -->
    <version>0.0.1-SNAPSHOT</version>
    <name>service-client-1</name>
    <description>Demo Spring Cloud Client</description>
    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2023.0.1</spring-cloud.version> <!-- Match with Spring Boot 3.2.x -->
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Step 2: Eureka Server Application එක

eureka-server project එකේ main application class එකට (උදා: EurekaServerApplication.java) @EnableEurekaServer annotation එක add කරන්න ඕනේ. මේකෙන් තමයි Spring Boot application එක Eureka Server එකක් විදිහට වැඩ කරන්න කියලා කියන්නේ.

package com.example.eurekaserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }

}

ඊළඟට, src/main/resources/application.yml (හෝ application.properties) file එකේ Eureka Server එකේ configurations දෙන්න ඕනේ. Eureka Server එක තමන්වම register කරගන්න ඕන නැති නිසා register-with-eureka සහ fetch-registry කියන properties දෙක false කරන්න. ඒ වගේම, server එක run වෙන්න ඕනේ port එකත් define කරන්න.

server:
  port: 8761 # Default Eureka server port

eureka:
  client:
    register-with-eureka: false # Eureka server doesn't need to register itself
    fetch-registry: false # Eureka server doesn't need to fetch registry from itself
  instance:
    hostname: localhost # Hostname for Eureka server

Step 3: Eureka Client Project දෙකක්

දැන් අපි client applications හදමු. service-client-1 සහ service-client-2 කියන projects දෙකේ main application class එකට @EnableDiscoveryClient annotation එක add කරන්න ඕනේ. මේකෙන් කියන්නේ මේ applications Eureka client ලා විදිහට register වෙන්න ඕනේ කියලා.

package com.example.serviceclient1; // or serviceclient2

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class ServiceClient1Application { // or ServiceClient2Application

    public static void main(String[] args) {
        SpringApplication.run(ServiceClient1Application.class, args);
    }

}

application.yml file එකේ මේ clients ලා register වෙන්න ඕනේ Eureka Server එකේ URL එක සහ application එකේ නම දෙන්න ඕනේ. ඒ වගේම, හැම client එකක්ම වෙන වෙනම ports වලින් run කරන්න ඕනේ.

service-client-1 සඳහා application.yml:

server:
  port: 8081 # Unique port for client 1

spring:
  application:
    name: MY-SERVICE # Application name to register with Eureka

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/ # Eureka server URL

service-client-2 සඳහා application.yml:

server:
  port: 8082 # Unique port for client 2

spring:
  application:
    name: MY-SERVICE # Same application name, but different instances

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/ # Eureka server URL

දැන් මේ clients දෙකටම අමතරව, අපි පුංචි REST endpoint එකක් හදමු, ඒකෙන් අපිට service එක වැඩ කරනවද කියලා බලන්න පුළුවන් වෙන්න.

package com.example.serviceclient1; // or serviceclient2

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/hello")
public class HelloController {

    @Value("${server.port}")
    private String port;

    @GetMapping
    public String hello() {
        return "Hello from MY-SERVICE running on port: " + port;
    }
}

මේ HelloController එක service-client-1 සහ service-client-2 කියන projects දෙකටම add කරන්න. මතක තියාගන්න, application name දෙකටම "MY-SERVICE" කියලා දුන්නේ, ඒක Eureka Server එකට register වෙන්නේ එකම service එකක් විදිහට, නමුත් instances දෙකක් විදිහට පෙන්නන්න. (එකම service එකේ different instances.)

Step 4: ටෙස්ට් කරමු!

දැන් අපේ projects ටික ready. මේ ටික මේ විදිහට run කරමු:

  1. මුලින්ම eureka-server project එක run කරන්න. සාමාන්‍යයෙන් Spring Boot application එකක් run කරනවා වගේමයි. (main method එක run කිරීම හෝ mvn spring-boot:run)
  2. Server එක start උනාට පස්සේ, ඔයාගේ web browser එකේ http://localhost:8761 කියන URL එකට යන්න. ඔයාට Eureka Dashboard එක පෙනෙයි. ඒකේ Services ලා තවම නැති බව පෙන්නයි.
  3. ඊළඟට, service-client-1 project එක run කරන්න.
  4. ඊට පස්සේ, service-client-2 project එක run කරන්න.
  5. දැන් ආයෙත් Eureka Dashboard (http://localhost:8761) එක refresh කරන්න. ඔයාට "MY-SERVICE" කියන service එකේ instances දෙකක්, Ports 8081 සහ 8082 එක්ක "UP" කියලා පෙන්නයි. ඒ කියන්නේ අපේ clients ලා සාර්ථකව Eureka Server එකට register වෙලා!
  6. Test කරන්න, browser එකේ http://localhost:8081/hello සහ http://localhost:8082/hello URL වලට ගිහින් බලන්න. "Hello from MY-SERVICE running on port: 8081" සහ "Hello from MY-SERVICE running on port: 8082" වගේ message එකක් එයි.

දැන් ඔයා සාර්ථකව Spring Cloud Eureka Server එකක් සහ Clients දෙකක් හදලා තියෙන්නේ! මේක Distributed Systems වල මූලිකම පියවරක්.

ඊළඟට මොනවද? Spring Cloud වල තවත් දේවල්

මේ අපි කතා කලේ Spring Cloud වල පොඩි කොටසක් විතරයි. ඔයාට පුළුවන් මේකෙන් එහාට ගිහින් තව components ගැන ඉගෙන ගන්න:

  • Spring Cloud Config Server: ඔයාගේ configurations centrally manage කරන්නේ කොහොමද කියලා.
  • Spring Cloud Gateway: requests route කරන විදිහ, filters add කරන විදිහ වගේ දේවල්.
  • Resilience4j සමග Circuit Breaking: services fail වෙනකොට ඒවා handle කරන්නේ කොහොමද කියලා.
  • Spring Cloud LoadBalancer: Eureka එක්ක වැඩ කරනකොට requests client side එකේදී load balance කරන්නේ කොහොමද කියලා.
  • Spring Cloud Sleuth & Zipkin: Distributed Tracing setup කරලා requests වල flow එක බලන විදිහ.

මේ හැම එකක්ම ඔයාගේ distributed applications හදනකොට ලොකු පහසුවක් සහ system එකේ reliability එක වැඩි කරනවා.

ඉතින් අද අපි Spring Cloud ගැන හොඳ අවබෝධයක් ලබාගත්තා කියලා හිතනවා. Distributed systems හදනකොට Spring Cloud කියන්නේ හරිම අත්‍යවශ්‍ය tool එකක්. ඒකෙන් Microservices වල තියෙන අභියෝග වලට පහසු විසඳුම් සපයනවා. මේක නොදැන හිටියා නම් අනිවාර්යයෙන්ම ඉගෙන ගන්න. ඔයාලගේ development journey එකට ලොකු අත්වැලක් වෙයි.

මේ ලිපිය ගැන ඔයාලගේ අදහස්, ප්‍රශ්න පහලින් comment කරන්න. ඔයාලගේ අත්දැකීම් share කරන්න. මේ වගේ තව දේවල් ගැන දැනගන්න අපිත් එක්ක එකතු වෙලා ඉන්න. එහෙනම් ආයෙත් දවසක හම්බවෙමු! සුභ දවසක්!