https://making.pusher.com/redis-pubsub-under-the-hood/
To track subscriptions, Redis uses a global variable
I’ve described the data structures as “maps” and “sets”: the global
http://redis.io/topics/pubsub
https://davidmarquis.wordpress.com/2013/01/03/reliable-delivery-message-queues-with-redis/
Redis is a high performance key-value datastore that differs from other key-value solutions in the way it handles values. Instead of just storing values as simple strings, it recognizes multiple specific data types such as Lists, Sets, Hashes (maps), Strings or Numbers. Each data type has its own set of features to manipulate the data it contains in an atomic manner, making it an ideal tool for highly distributed system where concurrency is a potential issue.
http://aredko.blogspot.com/2012/09/redis-pubsub-using-spring.html
http://city81.blogspot.com/2014/03/redis-publish-subscribe-and-long.html
Ruby Example: http://tutorials.jumpstartlab.com/topics/asynchronous_messaging_with_pubsub.html
To track subscriptions, Redis uses a global variable
pubsub_channels
which maps channel names to sets of subscribed client objects. A client object represents a TCP-connected client by tracking that connection’s file descriptor.
When a client sends a
SUBSCRIBE
command, its client object gets added to the set of clients for that channel name. To PUBLISH
, Redis looks up the subscribers in the pubsub_channels
map, and for each client, it schedules a job to send the published message to the client’s socket.
Client connections can drop. Perhaps the client closed the connection, or a network cable was pulled. When this happens, Redis must clean up the client’s subscriptions. Let’s say Client A disconnects. To remove the client from the
pubsub_channels
structure, Redis would have to visit every channel (“donuts” and “bagels”) and remove the client from each channel’s subscription set.
But visiting every channel is inefficient: Redis should only need to visit the “donuts” channel, because that is the only one that Client A is subscribed to. To enable this, Redis annotates each client with its set of subscribed channels, and keeps this in sync with the main
pubsub_channels
structure. With this, instead of iterating over every channel, Redis only needs to visit the channels which it knows the client was subscribed to. pubsub_channels
variable is logically a Map<ChannelName, Set<Client>>
, and each client’s subscription set is a Set<ChannelName>
. http://redis.io/topics/pubsub
SUBSCRIBE, UNSUBSCRIBE and PUBLISH implement the Publish/Subscribe messaging paradigm where (citing Wikipedia) senders (publishers) are not programmed to send their messages to specific receivers (subscribers). Rather, published messages are characterized into channels, without knowledge of what (if any) subscribers there may be.
Subscribers express interest in one or more channels, and only receive messages that are of interest, without knowledge of what (if any) publishers there are. This decoupling of publishers and subscribers can allow for greater scalability and a more dynamic network topology.
Subscribers express interest in one or more channels, and only receive messages that are of interest, without knowledge of what (if any) publishers there are. This decoupling of publishers and subscribers can allow for greater scalability and a more dynamic network topology.
For instance in order to subscribe to channels
foo
and bar
the client issues a SUBSCRIBE providing the names of the channels:SUBSCRIBE foo bar
Messages sent by other clients to these channels will be pushed by Redis to all the subscribed clients.
A client subscribed to one or more channels should not issue commands, although it can subscribe and unsubscribe to and from other channels.
The reply of the SUBSCRIBE and UNSUBSCRIBE operations are sent in the form of messages, so that the client can just read a coherent stream of messages where the first element indicates the type of message.
The reply of the SUBSCRIBE and UNSUBSCRIBE operations are sent in the form of messages, so that the client can just read a coherent stream of messages where the first element indicates the type of message.
Pattern-matching subscriptions
The Redis Pub/Sub implementation supports pattern matching. Clients may subscribe to glob-style patterns in order to receive all the messages sent to channel names matching a given pattern.
For instance:
PSUBSCRIBE news.*
Will receive all the messages sent to the channel
news.art.figurative
, news.music.jazz
, etc. All the glob-style patterns are valid, so multiple wildcards are supported.PUNSUBSCRIBE news.*
https://davidmarquis.wordpress.com/2013/01/03/reliable-delivery-message-queues-with-redis/
Redis is a high performance key-value datastore that differs from other key-value solutions in the way it handles values. Instead of just storing values as simple strings, it recognizes multiple specific data types such as Lists, Sets, Hashes (maps), Strings or Numbers. Each data type has its own set of features to manipulate the data it contains in an atomic manner, making it an ideal tool for highly distributed system where concurrency is a potential issue.
- although Redis requires everything you store in it to fit in memory, it supports persistence to disk.
- Redis allowed for all of the implementation characteristics we were looking for, namely:
- Concurrency: Because all operations in Redis are atomic, supporting concurrency without too much of a hassle is straightforward.
- Persistence: Configured properly, we can ensure persistence of our queues to disk using one of the supported Redis persistence strategies.
Why not use Redis Pub/Sub?
- What Redis offers with Pub/Sub is a listener model, where each subscriber receives each messages when it is listening, but won’t receive them when not connected.
- In a clustered environment where you have multiple instances of your consumer component running at the same time, each instance would receive each message produced on the channel. We wanted to make sure any given message got consumed once per logical consumer, even when multiple instances of this component are running.
Hence the name of this post “Reliable Delivery”, because we wanted to make sure every logical consumer eventually receives all messages produced on a queue once and only once, even when not connected – due to, for example, a deployment, a restart or a component failure/crash.
Redis Pub/Sub with Springhttp://aredko.blogspot.com/2012/09/redis-pubsub-using-spring.html
36 | @Bean |
37 | MessageListenerAdapter messageListener() { |
38 | return new MessageListenerAdapter( new RedisMessageListener() ); |
39 | } |
40 |
41 | @Bean |
42 | RedisMessageListenerContainer redisContainer() { |
43 | final RedisMessageListenerContainer container = new RedisMessageListenerContainer(); |
44 |
45 | container.setConnectionFactory( jedisConnectionFactory() ); |
46 | container.addMessageListener( messageListener(), topic() ); |
47 |
48 | return container; |
49 | } |
50 | |
51 | @Bean |
52 | IRedisPublisher redisPublisher() { |
53 | return new RedisPublisherImpl( redisTemplate(), topic() ); |
54 | } |
55 |
56 | @Bean |
57 | ChannelTopic topic() { |
58 | return new ChannelTopic( "pubsub:queue" ); |
59 | } |
11 | public class RedisPublisherImpl implements IRedisPublisher { |
12 | private final RedisTemplate< String, Object > template; |
13 | private final ChannelTopic topic; |
14 | private final AtomicLong counter = new AtomicLong( 0 ); |
15 |
16 | public RedisPublisherImpl( final RedisTemplate< String, Object > template, |
17 | final ChannelTopic topic ) { |
18 | this .template = template; |
19 | this .topic = topic; |
20 | } |
21 |
22 | @Scheduled ( fixedDelay = 100 ) |
23 | public void publish() { |
24 | template.convertAndSend( topic.getTopic(), "Message " + counter.incrementAndGet() + |
25 | ", " + Thread.currentThread().getName() ); |
26 | } |
27 | } |
06 | public class RedisMessageListener implements MessageListener { |
07 | @Override |
08 | public void onMessage( final Message message, final byte [] pattern ) { |
09 | System.out.println( "Message received: " + message.toString() ); |
10 | } |
11 | } |
Ruby Example: http://tutorials.jumpstartlab.com/topics/asynchronous_messaging_with_pubsub.html