Java Developer | digipay
Spring Boot Redis Messaging

مدیریت صف با استفاده از Redis در Spring Boot
1- اول از همه بگیم کلا Message Broker چیه و چیکار میکنه برامون ؟
یک Message Broker یک نرم افزار است که برنامه ها و اپلیکیشن ها رو قادر میسازه که بتونن اطلاعات خودشون رو در قالب یک پروتکل استاندارد بین یکدیگر جابه جا کنند و مستقیما با یکدیگر صحبت کنند.حتی اگر هر سرویس یا اپلیکیشن به زبان متفاوتی نوشته شده باشه. (Java - .net - php - ...)
پیاده سازی ساختار مایکروسرویس بین برنامه نویس ها خیلی باب شده که یکی از جاهایی که میشه از Message Broker ها استفاده کرد بین مایکروسرویس هامون هست.
وقتی از Message Broker ها استفاده میکنیم درواقع داریم میزان قابل اعتماد بودن و پایداری رو تضین میکنیم و همچنین اینکه میتونیم پیام ها رو مدیریت و نظارت کنیم تا اطمینان حاصل بشه که پیام ها گم نمیشوند.
در حال حاضر Message Broker های زیادی وجود دارد که میتونیم از هرکدوم از اونها استفاده کنیم.
اما در اینجا بحث اصلی ما روی Redis یا Remote Dictionary Server که یک NoSQL بر مبنای کلید/دیتا میباشد. که به عنوان کش ، پایگاه داده و Message Broker استفاده میشود.
از صف Redis در برنامه های با مقیاس پذیری و کارایی بالا استفاده میشود.
ردیس قابلیت انتقال پیام به صورت Point To Point و همچنین publish/subscribe را دارد.
نحوه کارکرد MessageBroker :

تولید کننده (Producer): اپلیکیشن یا برنامه ای است که پیام را تولید کرده و در صف مربوطه قرار میدهد.
مصرف کننده (Consumer) : مقصد پیام است ، در واقع اپلیکیشن یا برنامه است که پیام های مربوط به خود یعنی پیام هایی با پترن خاص را از صف مربوط به خود دریافت میکند.
صف (Queue) : فایل سیستمی است که صف برای نگداری پیام ها از آن استفاده میکند.
نکته : در Redis نوع ارسال پیام بر اساس Topic میباشد.
حالا Topic چیه : (publish/subscribe )

این نوع از کانال ارتباطی برای پیاده سازی الگوهای publish/subscribe مناسب است.همچنین اینکه برای مسیریابی های multicast پیامها مناسب است. حالتی را تصور کنید که برای یک پیام چندین مصرف کننده وجود دارد که میتوان انتخاب کرد که پیام را به کدام داد، برای این کار از این الگو استفاده می شود.
همانطور که گفتیم مصرف کننده ها پیام هایی با پترن یا درواقع در اینجا Topic Name خاص خود را دریافت میکنند.
هر چند که میتونید از هر Message Broker که دوست دارید استفاده کنید (RabbitMQ , Apache Kafka , Apache ActiveMQ , RedisMQ ,... ) اما Redis هم جذابیت ها و استفاده های خودش رو داره مثلا من ازش توی پیاده سازی پنل اس ام اس استفاده کردم .
3- یه مثال بزنیم
خوب میخوایم یه پروژه نمونه بنویسیم که بتونید ازش توی کارتون استفاده کنید :

نیازمندی هامون :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>موارد لازم در application.propertis:
server.port=2222
spring.data.redis.host=localhost
spring.data.redis.port=6379بخش کانفیگ Redis :
اگر به این قسمت دقت کنید ما موقع ایجاد کردن یه Topic اومدیم یه UUID رندم ایجاد کردیم شما میتونید این کار رو نکنید و یه پترن خاص قرار بدید و بعد در بخش مصرف کننده اون پترن خاص رو مقایسه کنید و اگر با پترن مصرف کننده برابر بود اون پیام رو دریافت کنید.
@Configuration
public class RedisConfiguration {
@Bean
JedisConnectionFactory connectionFactory(){
JedisConnectionFactory factory = new JedisConnectionFactory();
return factory;
}
@Bean
public RedisTemplate<String, String> redisTemplate() {
RedisTemplate<String, String> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory());
template.setValueSerializer(new GenericToStringSerializer<String>(String.class));
return template;
}
@Bean
ChannelTopic topic() {
return new ChannelTopic(UUID.randomUUID().toString());
}
@Bean
RedisMessageListenerContainer redisContainer() {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory());
container.addMessageListener(new MessageListenerAdapter(new RedisReciever()), topic());
container.setTaskExecutor(Executors.newFixedThreadPool(4));
return container;
}
}بخش Producer :
@Service
public class RedisSender {
private static final Logger LOGGER = LoggerFactory.getLogger(RedisSender.class);
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private ChannelTopic topic;
public void sendDataToRedisQueue(String input) {
redisTemplate.convertAndSend(topic.getTopic(), input);
LOGGER.info("Data - " + input + " sent through Redis Topic - " + topic.getTopic());
}
}بخش Costumer :
@Service
public class RedisReciever implements MessageListener {
private static final Logger LOGGER = LoggerFactory.getLogger(RedisReciever.class);
@Override
public void (Message message, byte[] pattern) {
LOGGER.info("Received data - " + message.toString() + " from Topic - " + new String(pattern));
}
}حالا یه کنترولر مینویسیم که یه متن پیام رو برای Producer میفرسته و Producer اون رو میزاره توی صف تا مصرف کننده اون رو برداره :
@RestController
@RequestMapping("/redis")
public class RedisController {
@Autowired
private RedisSender sender;
@GetMapping
public String sendDataToRedisQueue(@RequestParam("redis") String input) {
sender.sendDataToRedisQueue(input);
return "successfully sent"
}
}اینم تستش و نتیجه به صورت لاگ در کنسول :
Data - HELLO WORLD sent through Redis Topic - df59e344-a70c-4e79-973f-8f6f2d109e84
Received data - HELLO WORLD from Topic - df59e344-a70c-4e79-973f-8f6f2d109e84
منتظر نگاه های زیباتون هستم .
موفق و پیروز باشید.
مطلبی دیگر از این انتشارات
Mutable VS Immutable in java
مطلبی دیگر از این انتشارات
Heap and Stack in Java
مطلبی دیگر از این انتشارات
Spring AOP ( Aspect Oriented Programming)