Redis in Microservices Architecture Example
This post features a comprehensive tutorial with code examples on Redis in Microservices Architecture.
1. Redis – A brief overview
Redis is an open source, in-memory data structure store, used as a database, cache and message broker.
![Redis in Microservices](https://examples.javacodegeeks.com/wp-content/uploads/2019/11/ResizeJcgRedis.jpg)
It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes with radius queries and streams.
2. Redis in Microservices Architecture
Redis can be leveraged as a database, cache, message broker in a microservices architecture depending on the requirement.
It supports built-in replication, Lua scripting, LRU(Least Recently Used) eviction, transactions and different levels of on-disk persistence, provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster.
The above mentioned architectural, design and performance aspects of redis make it ideal for various use cases in a scalable and robust microservices architecture. We will understand the various use cases of redis in microservices architecture in the sections below.
2.1 Redis as In-memory data store
We will understand how redis can be used as an in-memory data store in this section through a simple event store micro-service built using spring boot and maven.
We will be using spring data redis for the easy configuration and access from the spring applications and spring-boot-starter-data-redis is the dependency which needs to be added to the pom.xml
The entity of the application, the Event object, is defined like below.
Event
@Data @RedisHash("event") public class Event implements Serializable { private static final long serialVersionUID = 1L; @Id private Long id; private Date date; private EventStatus status; public enum EventStatus { NEW, IN_PROGRESS, DONE; } @Override public String toString() { return this.id + "::" + this.date + ":" + this.status; } }
It is important to note that it is annotated with RedisHash so as to be used with Event repository which is defined like below.
EventRepository
public interface EventRepository extends CrudRepository { }
The REST APIs corresponding to the manipulation of Event entity is defined as part of the EventController like below.
EventController
@RestController @RequestMapping("/events") public class EventController { @Autowired EventPublisher publisher; @Autowired EventRepository repository; @PostMapping public Event create(@RequestBody Event event) { event = repository.save(event); try { publisher.publish(event); } catch (JsonProcessingException e) { e.printStackTrace(); } return event; } @GetMapping("/{id}") public Event findById(@PathVariable("id") Long id) { Optional optEvent = repository.findById(id); if (optEvent.isPresent()) { return optEvent.get(); } else { return null; } } @GetMapping public List findAll() { return (List) repository.findAll(); } }
When an event is created using the POST API in the above controller, the event data gets stored as key value pairs in a redis hash like shown in the screenshot below
![Redis in Microservices - Redis as In memory store](https://examples.javacodegeeks.com/wp-content/uploads/2019/11/ResizeJcgInMemoryStore.jpg)
2.2 Redis as Message broker
In microservices architecture, Redis can as well be used as a message broker. According to its official documentation, publish/subscribe messaging paradigm is implemented by Subscribe, Unsubscribe and Publish commands. The published messages are characterized into channels and subscribers express interest in one or more channels to only receive those messages
In the below sections, we will understand how redis is used as a message broker in our event store application.
Below is the publisher code to publish an event to a channel.
EventPublisher
public class EventPublisher { private static final Logger LOGGER = LoggerFactory.getLogger(EventPublisher.class); RedisTemplate redisTemplate; ChannelTopic topic; @SuppressWarnings("unchecked") public EventPublisher(RedisTemplate redisTemplate, ChannelTopic topic) { this.redisTemplate = redisTemplate; this.redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Event.class)); this.topic = topic; } public void publish(Event trip) throws JsonProcessingException { LOGGER.info("Sending: {}", trip); redisTemplate.convertAndSend(topic.getTopic(), trip); } }
The publish method converts Event Object to json using Jackson2JsonRedisSerializer which is defined as part of RedisTemplate instantiation.
The event subscriber needs to implement the MessageListener interface overriding the onMessage method like shown in the code below
EventSubscriber
@Service public class EventSubscriber implements MessageListener { private final Logger LOGGER = LoggerFactory.getLogger(EventSubscriber.class); @Autowired EventRepository repository; ObjectMapper mapper = new ObjectMapper(); @Override public void onMessage(Message message, byte[] bytes) { try { Event event = mapper.readValue(message.getBody(), Event.class); LOGGER.info("Message received: {}", event.toString()); } catch (IOException e) { LOGGER.error("Error reading message", e); } } }
Both the publisher and subscriber configurations are defined as part of EventConfiguration like shown in the code below.
EventConfiguration
@Configuration @EnableRedisRepositories public class EventConfiguration { @Autowired RedisTemplate redisTemplate; @Bean EventPublisher redisPublisher() { return new EventPublisher(redisTemplate, topic()); } @Bean ChannelTopic topic() { return new ChannelTopic("events"); } @Autowired RedisConnectionFactory redisConnectionFactory; @Bean RedisMessageListenerContainer container() { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.addMessageListener(messageListener(), topic()); container.setConnectionFactory(redisConnectionFactory); return container; } @Bean MessageListenerAdapter messageListener() { return new MessageListenerAdapter(new EventSubscriber()); } }
In the above configuration, EventSubscriber is added as the message listener to the RedisMessageListenerContainer bean instance which is responsible for subscribing EventSubscriber to the created event channel
When the spring boot application is run and an event is created using the create REST API, we can note that the message is published and is being consumed by the EventSubscriber from the logs printed in the figure below
![Redis in Microservices - Redis as message broker](https://examples.javacodegeeks.com/wp-content/uploads/2019/11/ResizedJcgMsgBroker.jpg)
2.3 Redis as Caching layer
One of the most common use cases of Redis is the caching capability. LRU(Least Recently Used) eviction policy, performance, high availability and built in replication capabilities make Redis the go-to data store for caching use case in microservice architecture.
2.4 Redis as Database
Redis comes about as a robust solution for database in microservices given the numerous persistence options it supports along with its inherent architectural and design capabilities.
The various persistence mechanisms it supports are below
- RDB – snapshots your dataset at specified intervals
- AOF – persists log of every write operation received by the server
3. Conclusion
In this article, we have understood the various use cases of redis in microservices architecture. We have illustrated how redis can be used as in- memory datastore and message broker through an example microservice application. Towards the end of the article, we have also understood the other use case of how redis can be used as cache and as a persistent database. Thus, we can realise the power of redis from the variety of use cases it supports and how instrumental it is in the design of microservices architecture applications.
4. Download the Source Code
This source contains the example code snippets used in this article to illustrate use cases of Redis in Microservices Architecture.
You can download the full source code of this example here: Redis in Microservices Architecture Example