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