Spring Boot RabbitMQ: Sri Lankan Dev's Asynchronous Messaging Guide - Sinhala Tech

Spring Boot සමඟ RabbitMQ: ඔබේ පණිවිඩ හුවමාරුවට සුපිරි විසඳුමක්!
ඉතිං කොහොමද යාලුවනේ? අද අපි කතා කරන්න යන්නේ ඔයාලා හැමෝටම ගොඩක් වැදගත් වෙන, ඒ වගේම අපේ Microservices Architecture වලට නැතුවම බැරි අංගයක් ගැන – ඒ තමයි Spring Boot එක්ක RabbitMQ භාවිතය! කට්ටියම සෙට් වෙලා මේ බ්ලොග් පෝස්ට් එක කියවන්න පටන් ගමු නේද? මේකෙන් අපේ සිස්ටම් (System) අතර දත්ත හුවමාරුව (Data Exchange) කරන හැටි පහසුවෙන් ඉගෙන ගන්න පුළුවන්.
දැන් කාලේ හැටියට Software Development කියන්නේ එක App එකක් විතරක් හදන එක නෙවෙයි. Platform ගණනාවක්, Service ගණනාවක් එකට සම්බන්ධ කරලා තියෙන ලොකු Systems හදන එක. මේ Services අතර දත්ත හුවමාරු කරගන්නේ කොහොමද කියන එක ලොකු ගැටලුවක් වෙන්න පුළුවන්. විශේෂයෙන්ම Asynchronous විදියට වැඩ කරන්න ඕන කරන තැන්වලදී.
අන්න ඒ වගේ තැනකට තමයි Message Queue එකක් එහෙමත් නැත්නම් Message Broker කෙනෙක් අපිට උදව් වෙන්නේ. RabbitMQ කියන්නේ ඒ වගේ ජනප්රියම Message Broker කෙනෙක්. Spring Boot එක්ක RabbitMQ පාවිච්චි කරන එක ලේසියි වගේම ගොඩක් Effective. මේ ලිපියෙන් අපි ඒ ගැන සවිස්තරව බලමු.
RabbitMQ ඇයි අපිට ඕනෙ?
කට්ටියට හිතෙන්න පුළුවන්, ඇයි අපිට මේ වගේ අමුතු දෙයක් ඕනේ කියලා. නිකන්ම API Call එකක් ගහලා වැඩේ කරගන්න බැරිද කියලා. ඇත්තටම සමහර අවස්ථාවලදී ඒක ඇති. හැබැයි ලොකු Systems හදනකොට, විශේෂයෙන්ම Microservices Architecture එකක් පාවිච්චි කරනකොට, API Call වලට වඩා Message Queue එකක් පාවිච්චි කරන එක ගොඩක් වාසිදායකයි.
1. Decoupling (සම්බන්ධතා ලිහිල් කිරීම)
හිතන්නකෝ ඔයා ලොකු Application එකක් හදනවා කියලා. ඒකෙ කොටස් ගොඩක් එකිනෙකට සම්බන්ධ වෙලා තියෙනවා (Highly Coupled). එක කොටසක් අවුල් වුණොත්, අනිත් හැම කොටසම අවුල් වෙන්න පුළුවන්. ඒ වගේම එක කොටසක වෙනසක් කළොත්, අනිත් හැම කොටසකටම ඒක බලපාන්න පුළුවන්.
RabbitMQ වගේ Message Broker කෙනෙක් ඉන්නවා නම්, මේ කොටස් එකිනෙකට සම්බන්ධ වෙන්නේ නැතුව වැඩ කරන්න පුළුවන්. ඒ කියන්නේ, "Producer" කෙනෙක් Message එකක් Queue එකට දානවා. "Consumer" කෙනෙක් Queue එකෙන් Message එක ගන්නවා. මේ දෙන්නා එකිනෙකා ගැන දන්නේ නෑ. Message Broker දන්නවා.
උදාහරණය: Order එකක් Process කරන System එකක්. Order එකක් දාපු ගමන් Inventory එක Update කරන්න ඕනේ, Email එකක් යවන්න ඕනේ, Shipping Process එක පටන් ගන්න ඕනේ. මේ හැම දේම එකම Service එකක් ඇතුළේ Sync විදියට කළොත්, එකක් Slow වුණොත් මුළු System එකම Slow වෙනවා. RabbitMQ පාවිච්චි කළොත්, Order Service එකෙන් Message එකක් Queue එකට දාලා තමන්ගේ වැඩේ ඉවර කරගන්නවා. අනිත් Service ටික ඒ Message එක අරන් තමන්ගේ වැඩ ටික Asynchronously කරගන්නවා. මේක "Asynchronous Communication" කියලා කියනවා.
2. Scalability (ප්රමාණයෙන් විශාල කිරීමට හැකිවීම)
සමහර වෙලාවට ඔයාගේ System එකට එක පාරට ලොකු Request ප්රමාණයක් එන්න පුළුවන්. ඒ හැම එකටම එක පාරට Response කරන්න බැරි වෙන්න පුළුවන්. ඒ වගේ වෙලාවට System එක Crash වෙන්න පුළුවන්. එහෙමත් නැත්නම් Performance අඩු වෙන්න පුළුවන්.
එතකොට RabbitMQ එකට මේ Request ටික දාලා, ඕන කරන වෙලාවට, ඕන කරන විදියට, ටික ටික Process කරන්න පුළුවන්. අවශ්ය නම්, Consumers ගණන වැඩි කරලා එක පාරට Process කරන්න පුළුවන් Message ගණන වැඩි කරන්න පුළුවන්. මේකෙන් System එකේ Scalability එක වැඩි වෙනවා.
3. Reliability (විශ්වාසනීයත්වය)
Message එකක් Process වෙන වෙලාවේ මොනවා හරි අවුලක් වුණොත් (Error එකක් ආවොත්, Server එක Crash වුණොත්), Message එක නැති වෙන්නේ නැතුව ආපහු Queue එකට දාන්න පුළුවන්. එතකොට ආපහු Process කරන්න පුළුවන්. RabbitMQ "Message Persistence" (Message එක Save කරලා තියාගැනීම) සහ "Acknowledgement" (Message එකක් ලැබුණු පසු තහවුරු කිරීම) වැනි විශේෂාංග ලබා දෙනවා. මේකෙන් System එකේ Reliability එක වැඩි වෙනවා.
4. Rate Limiting / Load Leveling (බර සමතුලිත කිරීම)
සමහර Service වලට එක පාරට යවන්න පුළුවන් Request ගණන සීමා වෙලා තියෙන්න පුළුවන්. එහෙමත් නැත්නම් Backend System එකක Process කරන්න පුළුවන් ප්රමාණයට වඩා වැඩි Requests ප්රමාණයක් එන්න පුළුවන්. Message Queue එකක් මේ Request ටික Buffer කරලා, Backend System එකට Process කරන්න පුළුවන් වේගයෙන් විතරක් Request යවනවා. මේකෙන් Backend System එක Overload වීම වළක්වනවා.
Spring Bootයි RabbitMQයි එකට
දැන් අපි බලමු කොහොමද මේ RabbitMQ, අපේ Spring Boot Project එකකට එකතු කරගෙන, අපේ වැඩේ පහසු කරගන්නේ කියලා. Spring Boot කියන්නේ Java Application හදන එක ලේසි කරන Framework එකක්. එයාලා "Spring AMQP" කියන Module එක හරහා RabbitMQ එක්ක වැඩ කරන එකට හොඳ Support එකක් දෙනවා. ඒ කියන්නේ අපිට Complex Configurations ලියන්නේ නැතුව, ඉක්මනට RabbitMQ එක්ක වැඩ කරන්න පුළුවන්.
Spring Boot මගින් Auto-Configuration, Declarative Listener Support (@RabbitListener
Annotation එක වගේ) වගේ දේවල් ලබා දෙනවා. ඒකෙන් අපේ Development Process එක ගොඩක් වේගවත් වෙනවා.
Project එක පටන් ගමු!
හරි, දැන් අපි කතාව පැත්තකින් තියලා, වැඩේට බහිමු. අපි පොඩි Spring Boot Project එකක් හදලා, ඒකෙන් RabbitMQ හරහා Message එකක් යවලා, ඒක ආපහු ගන්න හැටි බලමු.
පළමු පියවර: Project එක හදාගමු
අපි මුලින්ම Project එක හදාගමු. මේකට Spring Initializr (start.spring.io
) පාවිච්චි කරමු. පහත Dependencies ටික Add කරගන්න:
- Spring Web: REST Endpoints හදන්න ඕන නිසා.
- Spring for RabbitMQ: RabbitMQ Integration එකට.
Project එක Generate කරලා, ඔයාගේ IDE එකට (IntelliJ IDEA, VS Code වගේ) Open කරගන්න.
දෙවන පියවර: RabbitMQ Server එකක් Run කරමු
ඔයාට Local RabbitMQ Server එකක් Install කරන්න පුළුවන්. ඒත් මම Recommend කරන්නේ Docker පාවිච්චි කරන එක. මේක ගොඩක් ලේසියි.
docker run -d --hostname my-rabbit --name some-rabbit -p 5672:5672 -p 15672:15672 rabbitmq:3-management
මේ Command එකෙන් RabbitMQ Server එකක් Docker Container එකක් විදියට Run වෙනවා. 5672
Port එක Message Communication වලටත්, 15672
Port එක RabbitMQ Management UI එකටත් පාවිච්චි වෙනවා. ඔයාට Browser එකේ http://localhost:15672
ට ගිහින් guest/guest
Username/Password එකෙන් Login වෙලා RabbitMQ Management UI එක බලන්න පුළුවන්.
තුන්වන පියවර: application.properties සැකසීම
දැන් අපි අපේ Spring Boot Project එකේ src/main/resources/application.properties
File එකට RabbitMQ Connection Details ටික Add කරමු.
# RabbitMQ Configuration
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
ඔයා වෙනම RabbitMQ Server එකක් පාවිච්චි කරනවා නම්, ඒ Server එකේ Host, Port, Username, Password ටික මෙතනට දාන්න.
හතරවන පියවර: Queue, Exchange සහ Binding නිර්මාණය
RabbitMQ වලදී Messages යවන්නේ Queue වලට නෙවෙයි, Exchange එකකට. Exchange එකෙන් තමයි Rules අනුව Messages Queue වලට Distribution කරන්නේ. මේ Rules තමයි Binding කියන්නේ. අපි දැන් මේ ටික අපේ Spring Boot Project එකේදී Define කරමු.
com.example.rabbitmqexample.config
කියන Package එකක් හදලා ඒක ඇතුළේ RabbitMQConfig.java
කියලා Class එකක් හදන්න.
package com.example.rabbitmqexample.config;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMQConfig {
// Queue, Exchange, සහ Routing Key සඳහා නියත (Constants)
public static final String QUEUE_NAME = "my_queue";
public static final String EXCHANGE_NAME = "my_exchange";
public static final String ROUTING_KEY = "my_routing_key";
// 1. Queue එකක් නිර්මාණය කිරීම
@Bean
public Queue queue() {
// Queue එකේ නම my_queue. durable: false කියන්නේ RabbitMQ restart වුණාම Queue එක delete වෙනවා.
// Production වලදී durable: true දාන එක හොඳයි.
return new Queue(QUEUE_NAME, false);
}
// 2. Exchange එකක් නිර්මාණය කිරීම (DirectExchange - Routing Key එක හරියටම Match වෙන Queue එකට යවනවා)
@Bean
public DirectExchange exchange() {
return new DirectExchange(EXCHANGE_NAME);
}
// 3. Queue එකයි Exchange එකයි Binding කිරීම
@Bean
public Binding binding(Queue queue, DirectExchange exchange) {
// my_exchange එකට my_routing_key එකෙන් එන messages my_queue එකට යවන ලෙස නියම කරයි.
return BindingBuilder.bind(queue).to(exchange).with(ROUTING_KEY);
}
// Messages JSON format එකට Convert කරන්න Jackson2JsonMessageConverter එක භාවිතා කරයි.
@Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
// RabbitTemplate එක නිර්මාණය කිරීම. මේක තමයි Messages යවන්න පාවිච්චි කරන්නේ.
@Bean
public AmqpTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
// Message Converter එක Set කිරීම
rabbitTemplate.setMessageConverter(jsonMessageConverter());
return rabbitTemplate;
}
}
මේ RabbitMQConfig
Class එක මගින් අපි අවශ්ය Queue, Exchange සහ Binding ටික නිර්මාණය කරනවා. ඒ වගේම RabbitTemplate
එකත් Configure කරනවා. මේ RabbitTemplate
එක තමයි Messages යවන්න අපි පාවිච්චි කරන්නේ.
පස්වන පියවර: Message Producer (Sender) නිර්මාණය
දැන් අපි Message එකක් RabbitMQ Queue එකට යවන්න පුළුවන් Producer කෙනෙක් හදමු. මේකට අපි REST Controller එකක් පාවිච්චි කරමු.
com.example.rabbitmqexample.controller
කියන Package එකක් හදලා ඒක ඇතුළේ MessageProducerController.java
කියලා Class එකක් හදන්න.
package com.example.rabbitmqexample.controller;
import com.example.rabbitmqexample.config.RabbitMQConfig;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/message")
public class MessageProducerController {
@Autowired
private AmqpTemplate amqpTemplate; // RabbitTemplate එක Inject කරගැනීම
@PostMapping("/send")
public String sendMessage(@RequestBody String message) {
// EXCHANGE_NAME, ROUTING_KEY සහ message එක දාලා send කරනවා.
amqpTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME, RabbitMQConfig.ROUTING_KEY, message);
System.out.println("Message sent: " + message);
return "Message sent to RabbitMQ successfully!";
}
}
මේ Controller එකේ /api/message/send
කියන Endpoint එකට POST Request එකක් එවනකොට, ඒ Request Body එකේ තියෙන Message එක RabbitMQ එකට යවන්න අපි amqpTemplate.convertAndSend()
Method එක පාවිච්චි කරනවා.
හයවන පියවර: Message Consumer (Receiver) නිර්මාණය
අපි Message එකක් යැව්වා නම්, ඒක ගන්න කෙනෙක් ඉන්න ඕනේ නේද? අන්න ඒකට තමයි Consumer කෙනෙක් ඕනේ වෙන්නේ. මේ Consumer කෙනා Queue එකට එන Messages Listen කරනවා.
com.example.rabbitmqexample.consumer
කියන Package එකක් හදලා ඒක ඇතුළේ MessageConsumer.java
කියලා Class එකක් හදන්න.
package com.example.rabbitmqexample.consumer;
import com.example.rabbitmqexample.config.RabbitMQConfig;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class MessageConsumer {
// RabbitMQConfig එකේ Define කරපු QUEUE_NAME එක Listen කරනවා.
@RabbitListener(queues = RabbitMQConfig.QUEUE_NAME)
public void receiveMessage(String message) {
System.out.println("Message received: " + message);
// මෙතන තමයි ඔයාගේ message එක Process කරන Logic එක ලියන්නේ
// උදාහරණයක් ලෙස: database එකට save කරනවා, email එකක් යවනවා, වෙන Service එකකට යවනවා වගේ දේවල්.
// සැබෑ ලෝකයේදී මේක ටිකක් වෙලා යන වැඩක් වෙන්න පුළුවන්.
}
}
@RabbitListener(queues = RabbitMQConfig.QUEUE_NAME)
Annotation එකෙන් කියන්නේ මේ Method එක my_queue
එකට එන Messages Listen කරනවා කියලා. Message එකක් ආවම, receiveMessage
Method එක Call වෙනවා.
හත්වන පියවර: Project එක Run කරලා බලමු!
දැන් ඔක්කොම හරි. Project එක Run කරන්න. ඔයාගේ IDE එකෙන් Main Class එක Run කරන්න පුළුවන්, එහෙමත් නැත්නම් Command Line එකෙන්:
mvn spring-boot:run
Project එක සාර්ථකව Start වුණාම, Console එකේ RabbitMQ Connection Details පෙනෙයි.
දැන් අපි Message එකක් යවමු. Postman වගේ API Client එකක් පාවිච්චි කරලා, එහෙමත් නැත්නම් Curl Command එකකින් මේ විදියට Request එකක් යවන්න:
curl -X POST -H "Content-Type: text/plain" -d "Hello RabbitMQ from Sri Lanka!" http://localhost:8080/api/message/send
මේ Request එක යැව්වම, Producer Service එකේ Console එකේ "Message sent: Hello RabbitMQ from Sri Lanka!" කියලා පෙනෙයි. ඒ වගේම Consumer Service එකේ Console එකේ "Message received: Hello RabbitMQ from Sri Lanka!" කියලා පෙනෙයි. ඒ කියන්නේ ඔයාගේ Message එක සාර්ථකව RabbitMQ හරහා යවලා, ආපහු අරන් තියෙනවා!
ඔයාට පුළුවන් RabbitMQ Management UI (http://localhost:15672
) එකට ගිහින් Queues Tab එකට ගිහින් බලන්න, Message ගණන වැඩි වෙනවා අඩු වෙනවා, Queue එකේ තත්ත්වය වගේ දේවල්.
පොඩි ටිප්ස් ටිකක්
ඔයාලා RabbitMQ Production එකේදී පාවිච්චි කරනකොට මේ දේවල් ගැනත් සැලකිලිමත් වෙන්න.
1. Error Handling සහ Dead Letter Queues (DLQ)
Consumer කෙනෙක් Message එකක් Process කරනකොට මොනවා හරි අවුලක් වුණොත්, ඒක ආපහු Queue එකටම යැවීම වැරදියි. එතකොට ඒ Message එක ආපහු ආපහු Process වෙන්න බලනවා. මේක "Poison Message" එකක් වෙන්න පුළුවන්. ඒ වගේ වෙලාවට Dead Letter Queue (DLQ) එකක් පාවිච්චි කරන්න පුළුවන්. එතකොට Fail වෙන Messages ටික වෙනම Queue එකකට යනවා. පසුව අපිට ඒ Messages ටික අරන් Analysis කරලා, හදලා ආපහු Process කරන්න පුළුවන්. මේක Reliability එකට ගොඩක් වැදගත්.
2. Message Serialization/Deserialization
අපි මේ Example එකේදී String එකක් පාවිච්චි කළාට, Production Level වලදී Complex Data Structures යවන්න වෙන්න පුළුවන්. ඒ වගේ වෙලාවට JSON, Avro, Protobuf වගේ Format පාවිච්චි කරන එක හොඳයි. Spring AMQP එකේ Jackson2JsonMessageConverter එක වගේ Converters තියෙනවා. අපේ Example එකෙත් මම ඒක Add කළා.
3. Acknowledgements (සහතික කිරීම්)
Consumer කෙනෙක් Message එකක් ගත්තාම, ඒක Process කරලා ඉවරයි කියලා RabbitMQ එකට කියන්න ඕනේ. නැත්නම් ඒ Message එක Queue එකේම තියේවි. Spring Boot Default විදියට "Auto Acknowledgement" කරනවා. ඒ කියන්නේ Consumer එක සාර්ථකව Message එක Process කළාම, ඒක RabbitMQ එකෙන් Queue එකෙන් අයින් කරනවා. හැබැයි Manual Acknowledgement කරන්නත් පුළුවන්, සමහර වෙලාවට ඒක අවශ්ය වෙන්න පුළුවන් (උදා: Message එක Process කරලා Database එකට Save කරලා සාර්ථක නම් විතරක් Acknowledge කරනවා වගේ).
4. Concurrency සහ Threading
@RabbitListener
එකට Messages එක පාරට කීයක් Process කරන්න පුළුවන්ද කියලා Configure කරන්න පුළුවන්. concurrency
සහ prefetch
වගේ Properties පාවිච්චි කරලා. මේකෙන් Consumer එකේ Performance එක Boost කරගන්න පුළුවන්.
5. Durability (කල් පැවැත්ම)
අපි Queue එක හදනකොට durable: false
කියලා දැම්මා. ඒ කියන්නේ RabbitMQ Server එක Restart වුණොත් Queue එක නැති වෙනවා. Production Level වලදී Queue සහ Exchange දෙකම durable: true
විදියට හදන්න ඕනේ. එතකොට Server Restart වුණත් ඒ ටික නැති වෙන්නේ නෑ.
අවසන් වචන
ඉතිං යාලුවනේ, ඔන්න ඔයාලා අද Spring Boot එක්ක RabbitMQ කොහොමද පාවිච්චි කරන්නේ කියලා හොඳට ඉගෙන ගත්තා කියලා හිතනවා. මේක Microservices Architecture වලදී නැතුවම බැරි දෙයක්. විශේෂයෙන්ම System එකේ Scalability, Reliability, සහ Decoupling වැඩි කරගන්න නම් Message Queue එකක් අනිවාර්යයි.
ඔයාලත් මේක තනියම Try කරලා බලන්න. Project එක Clone කරලා, Docker එකෙන් RabbitMQ Server එක Run කරලා, Messages යවලා බලන්න. මොනවා හරි ගැටළුවක් ආවොත්, පහළින් Comments දාන්න. අපි ඒවට උත්තර දෙන්නම්. ඒ වගේම මේ Article එක ඔයාට වටිනවා නම්, යාළුවෝ එක්ක Share කරන්නත් අමතක කරන්න එපා. තවත් මේ වගේ Technical Blog Post එකකින් හමුවෙමු!
Happy Coding! 👋