আমি জানি আপনি মাইক্রোসার্ভিসেস নিয়ে কাজ করছেন আর সেখানে একটা বড় চ্যালেঞ্জ হলো পরস্পরকে খুঁজে পাওয়া। মাইক্রোসার্ভিস আর্কিটেকচারে একাধিক সার্ভিস আলাদা আলাদা পোর্টে চলে, আর এদের ঠিকানা (IP ও পোর্ট) ডায়নামিকভাবে পরিবর্তন হতে পারে। এই সমস্যার সমাধান হলো Service Discovery, যা সার্ভিসগুলোকে নিজেদের মধ্যে স্বয়ংক্রিয়ভাবে যোগাযোগ করতে সাহায্য করে। এই টিউটোরিয়ালে আমরা Service Discovery-র মূল ধারণা, Spring Cloud Netflix Eureka ব্যবহার করে বাস্তবায়ন, এবং সাধারণ সমস্যাগুলো সমাধানের পদ্ধতি শিখব।

ভূমিকা (Background)

মাইক্রোসার্ভিস আর্কিটেকচারে প্রতিটি সার্ভিস সাধারণত আলাদা আলাদা সার্ভারে বা কন্টেইনারে চলে। যখন একটি সার্ভিস (যেমন order-service) অন্য সার্ভিসের (যেমন payment-service) সাথে কথা বলতে চায়, তখন তাকে সেই সার্ভিসের বর্তমান অবস্থান (IP ও পোর্ট) জানতে হবে। কিন্তু ক্লাউড বা কন্টেইনারাইজড পরিবেশে সার্ভিসগুলো ডায়নামিকভাবে স্কেল আপ/ডাউন হয়, ফলে তাদের ঠিকানা স্থির থাকে না।

এই সমস্যার সমাধান হিসেবে Service Discovery একটি কেন্দ্রীয় রেজিস্ট্রি (যেমন Eureka Server) ব্যবহার করে। প্রতিটি সার্ভিস যখন চালু হয়, তখন সে নিজেকে এই রেজিস্ট্রিতে নিবন্ধন করে। আর অন্য সার্ভিসগুলো যখন কোনো নির্দিষ্ট সার্ভিসের প্রয়োজন হয়, তখন তারা রেজিস্ট্রি থেকে সেই সার্ভিসের বর্তমান ঠিকানা জিজ্ঞাসা করে নেয়। এই পদ্ধতিতে সার্ভিসগুলোর মধ্যে লুজ কাপলিং (loose coupling) বজায় থাকে এবং ম্যানুয়াল কনফিগারেশনের ঝামেলা দূর হয়।

পূর্বশর্ত (Prerequisites)

এই টিউটোরিয়াল অনুসরণ করতে আপনার নিচের বিষয়গুলো জানা বা সেটআপ করা থাকা উচিত:

  • জাভা ডেভেলপমেন্ট এনভায়রনমেন্ট: JDK 11 বা তার উপরে ইনস্টল করা থাকতে হবে।
  • স্প্রিং বুট বেসিক: @SpringBootApplication, application.yml ফাইল এবং REST API তৈরি সম্পর্কে ধারণা।
  • মাইক্রোসার্ভিস বেসিক: দুটি আলাদা সার্ভিস (যেমন order-servicepayment-service) কীভাবে কাজ করে, তা বুঝতে হবে।
  • ম্যাভেন বা গ্রেডল: প্রজেক্ট বিল্ড করার জন্য যেকোনো একটি বিল্ড টুল ব্যবহার করতে হবে।

যদি স্প্রিং ক্লাউডের সাথে পরিচিত না হন, তাহলে চিন্তা নেই — আমরা ধাপে ধাপে সবকিছু ব্যাখ্যা করব। প্রথমে Eureka Server তৈরি করব, তারপর দুটি ক্লায়েন্ট সার্ভিস।

ধাপে ধাপে বাস্তবায়ন (Step-by-step Implementation)

ধাপ ১: Eureka Server (Service Registry) তৈরি করা

প্রথমে একটি নতুন স্প্রিং বুট প্রজেক্ট তৈরি করুন। এটিকে আমরা eureka-server নাম দেব। এই সার্ভিসটি সার্ভিস ডিসকভারির রেজিস্ট্রি হিসেবে কাজ করবে। pom.xml ফাইলে নিচের ডিপেন্ডেন্সিগুলো যোগ করুন:

<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-web</artifactId>
</dependency>

এখন application.yml ফাইলে Eureka Server কনফিগার করুন:

server:
  port: 8761

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
  instance:
    hostname: localhost

register-with-eureka: false এবং fetch-registry: false দেওয়ার কারণ হলো — এই সার্ভিসটি নিজে অন্য কোনো রেজিস্ট্রিতে নিবন্ধন করবে না, এটি শুধু রেজিস্ট্রি হিসেবে কাজ করবে। এখন মূল ক্লাসে @EnableEurekaServer অ্যানোটেশন যোগ করুন:

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);
    }
}

এই ক্লাসটি চালু করলে http://localhost:8761 এ একটি ড্যাশবোর্ড পাবেন, যেখানে নিবন্ধিত সার্ভিসগুলোর তালিকা দেখা যাবে।

ধাপ ২: প্রথম ক্লায়েন্ট সার্ভিস (order-service) তৈরি করা

এখন একটি নতুন স্প্রিং বুট প্রজেক্ট তৈরি করুন, নাম দিন order-servicepom.xml-এ নিচের ডিপেন্ডেন্সি যোগ করুন:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

application.yml ফাইলে কনফিগারেশন দিন:

server:
  port: 8081

spring:
  application:
    name: order-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

এখন একটি REST কন্ট্রোলার তৈরি করুন যা অন্য সার্ভিসের সাথে যোগাযোগ করবে:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class OrderController {

    @GetMapping("/order")
    public String getOrder() {
        // এখানে আমরা payment-service-কে কল করব
        String paymentServiceUrl = "http://PAYMENT-SERVICE/payment";
        RestTemplate restTemplate = new RestTemplate();
        String response = restTemplate.getForObject(paymentServiceUrl, String.class);
        return "Order placed, payment: " + response;
    }
}

উপরের কোডে আমরা PAYMENT-SERVICE নাম ব্যবহার করেছি। এটি সার্ভিসের নাম (যা application.name-এ দেওয়া আছে), এবং Eureka স্বয়ংক্রিয়ভাবে এই নামকে বর্তমান IP ও পোর্টে রূপান্তর করে। এখানে RestTemplate ব্যবহার করা হয়েছে যা সার্ভিস ডিসকভারির মাধ্যমে ঠিকানা খুঁজে পায়।

ধাপ ৩: দ্বিতীয় ক্লায়েন্ট সার্ভিস (payment-service) তৈরি করা

একইভাবে payment-service প্রজেক্ট তৈরি করুন, পোর্ট 8082 ব্যবহার করুন:

server:
  port: 8082

spring:
  application:
    name: payment-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

এখন একটি কন্ট্রোলার তৈরি করুন:

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

@RestController
public class PaymentController {

    @GetMapping("/payment")
    public String getPayment() {
        return "Payment successful!";
    }
}

সম্পূর্ণ উদাহরণ (Complete Example)

নিচে একটি সম্পূর্ণ স্প্রিং বুট অ্যাপ্লিকেশন দেওয়া হল যা আপনি কপি করে চালাতে পারেন। প্রথমে Eureka Server চালু করুন, তারপর order-servicepayment-service চালু করুন।

Eureka Server (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);
    }
}

order-service (সার্ভিস ডিসকভারি ক্লায়েন্ট)

package com.example.orderservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
public class OrderServiceApplication {

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

@RestController
class OrderController {
    @GetMapping("/order")
    public String getOrder() {
        String paymentServiceUrl = "http://PAYMENT-SERVICE/payment";
        RestTemplate restTemplate = new RestTemplate();
        String response = restTemplate.getForObject(paymentServiceUrl, String.class);
        return "Order placed, payment: " + response;
    }
}

payment-service

package com.example.paymentservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@EnableDiscoveryClient
public class PaymentServiceApplication {

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

@RestController
class PaymentController {
    @GetMapping("/payment")
    public String getPayment() {
        return "Payment successful!";
    }
}

কিভাবে চালাবেন:

  1. প্রথমে eureka-server চালু করুন (পোর্ট 8761)।
  2. তারপর order-service (পোর্ট 8081) ও payment-service (পোর্ট 8082) চালু করুন।
  3. ব্রাউজারে http://localhost:8081/order হিট করুন। আপনি দেখবেন order-service স্বয়ংক্রিয়ভাবে payment-service-কে খুঁজে পেয়েছে এবং রেসপন্স দিচ্ছে।

সাধারণ সমস্যা ও সমাধান (Common Issues)

সমস্যা ১: সার্ভিস রেজিস্ট্রি না দেখানো

কারণ: application.yml-এ eureka.client.service-url.defaultZone ভুল দেওয়া।
সমাধান: নিশ্চিত করুন যে সব ক্লায়েন্ট একই Eureka সার্ভার URL ব্যবহার করছে (http://localhost:8761/eureka/).

সমস্যা ২: সার্ভিস নাম কেস-সেন্সিটিভ

কারণ: স্প্রিং ক্লাউডে সার্ভিসের নাম সাধারণত আপারকেস-এ রূপান্তরিত হয়।
সমাধান: payment-service এর নাম যখন ব্যবহার করবেন, তখন PAYMENT-SERVICE লিখুন (হাইফেন থাকলেও আপারকেস ব্যবহার করুন)।

সমস্যা ৩: লোড ব্যালেন্সিং না হওয়া

কারণ: ডিফল্ট RestTemplate লোড ব্যালেন্সিং সাপোর্ট করে না।
সমাধান: @LoadBalanced অ্যানোটেশন যুক্ত RestTemplate বিন তৈরি করুন:

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
    return new RestTemplate();
}

সারসংক্ষেপ (Summary)

এই টিউটোরিয়ালে আমরা শিখলাম Service Discovery কীভাবে মাইক্রোসার্ভিসের মধ্যে যোগাযোগ সহজ করে। আমরা Eureka Server ব্যবহার করে একটি কেন্দ্রীয় রেজিস্ট্রি তৈরি করলাম এবং দুটি ক্লায়েন্ট সার্ভিস (order-service ও payment-service) তাদের নিজেদের নাম ব্যবহার করে একে অপরকে খুঁজে পেল। এই পদ্ধতি ডায়নামিক স্কেলিং এবং ফল্ট টলারেন্স-এর জন্য অপরিহার্য।

আপনার প্রজেক্টে যদি মাইক্রোসার্ভিসের সংখ্যা বাড়ে, তাহলে Service Discovery ব্যবহার করে আপনি সহজেই নতুন সার্ভিস যোগ করতে পারবেন এবং পুরনো সার্ভিসের ঠিকানা পরিবর্তনের ঝামেলা থেকে মুক্ত থাকবেন।

Share