Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redis Pub/Sub with Spring Data Redis: Messages arrive in wrong order

I am attempting to implement a chat using Redis publish/subscribe with Spring Data Redis.

I use the RedisTemplate to publish messages, shown below:

public class RedisPublisher {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public void publish(ChannelTopic channelTopic, Object channelMessage) {
        redisTemplate.convertAndSend(channelTopic.getTopic(), channelMessage);
    }
}

And to receive messages I have a MessageListener as shown below:

public class RedisConsumer implements MessageListener {

MessageSerializer serializer = new MessageSerializer();
AtomicInteger atomicInteger = new AtomicInteger(0);

@Override
public void onMessage(Message message, byte[] pattern) {

    Object obj = serializer.deserialize(message.getBody());
    if(obj != null && obj instanceof RedisMessage) {
        System.err.println("Received message(" + atomicInteger.incrementAndGet() + ") " + obj.toString());
    }

}

Messages are published like so:

final ChannelTopic channelTopic=connectionManager.subscribe("topic");
    new Thread(new Runnable() {
        public void run() {                
            Thread.sleep(5000);                
            for (int i = 0; i < 10; i++) {
                redisPublisher.publish(channelTopic, new RedisMessage(i + 1));
            }
        }
    }).run();

However, the received messages appear to be delivered in wrong order:

Received message(1) message id: 3
Received message(2) message id: 2
Received message(3) message id: 1
Received message(4) message id: 4
Received message(5) message id: 5
Received message(6) message id: 6
Received message(7) message id: 7
Received message(8) message id: 8
Received message(9) message id: 9
Received message(10) message id: 10

Is it possible to send/receive messages synchronously using the RedisTemplate/MessageListener provided by Spring?

The current code-base is small and can be viewed at GitHub.

like image 694
aberg Avatar asked Aug 26 '15 16:08

aberg


1 Answers

Redis PubSub is known to deliver the messages in order (guaranteed at least if you use one connection and trigger PUBLISH. The PUBLISH command returns the number of clients that were notified). The cause for the out-of-order is the way how Spring Data Redis dispatches the messages by default. The notification is handled on different threads and that's the reason. Thanks for the code, it helped me to quickly reproduce the behavior.

I can think of two possible strategies to address this issue:

  1. You can however supply an executor that honors the order within RedisMessageListenerContainer. Right now, any form of synchronization I'm thinking of, would harm performance.

  2. Implement an own message listener on top of BinaryJedisPubSub. You're in control over the messages and you can omit the executor issue.

HTH, Mark

like image 69
mp911de Avatar answered Oct 17 '22 00:10

mp911de