Subscribe / Unsubscribe Enewsletters | Login | Register

Pencil Banner

Lightning fast NoSQL with Spring Data Redis

Dr. Xinyu Liu | May 25, 2016
6 uses cases for Redis in server-side Java applications

6. Efficient global notifications: Publish/subscribe channels

A Redis publish/subscribe channel works like a fan-out messaging system, or a topic in JMS semantics. A difference between a JMS topic and a Redis pub/sub channel is that messages published through Redis are not durable. Once a message is pushed to all the connected clients, the message is removed from Redis. In other words, subscribers must stay online to accept new messages. Typical use cases for Redis pub/sub channels include realtime configuration distribution, simple chat server, etc.

In a web server cluster, each node can be a subscriber to a Redis pub/sub channel. A message published to the channel is pushed instantaneously to all the connected nodes. This message could be a configuration change or a global notification to all online users. Obviously this push communication model is extremely efficient compared with constant polling.

Performance optimizing Redis

Redis is extremely powerful, and it can be optimized both generally and for specific programming scenarios. Consider the following techniques.

Time-to-live

All Redis data structures have a time-to-live (TTL) attribute. When you set this attribute, the data structure will be removed automatically after it expires. Making good use of this feature will keep memory consumption low in Redis.

Pipelining

Sending multiple commands to Redis in a single request is called pipelining. This technique saves cost on network round-trips, which is important because network latency could be orders of magnitude higher than Redis latency. But there is a catch: the list of Redis commands inside a pipeline must be pre-determined and independent from each other. Pipelining doesn't work if one command's arguments are computed from the results of preceding commands. Listing 5 shows an example of Redis pipelining.

Listing 5. Pipelining


@Override
public List<LeaderboardEntry> fetchLeaderboard(String key, String... playerIds) {
	final List<LeaderboardEntry> entries = new ArrayList<>();
	redisTemplate.executePipelined(new RedisCallback<Object>() {	// enable Redis Pipeline
		@Override 
		public Object doInRedis(RedisConnection connection) throws DataAccessException { 
			for(String playerId : playerIds) {
				Long rank = connection.zRevRank(key.getBytes(), playerId.getBytes());
				Double score = connection.zScore(key.getBytes(), playerId.getBytes());
				LeaderboardEntry entry = new LeaderboardEntry(playerId, 
				score!=null?score.intValue():-1, rank!=null?rank.intValue():-1);
				entries.add(entry);
			}		 
			return null; 
		}
	}); 
	return entries; 
}

Replica set and sharding

Redis supports master-slave replica configuration. Like MongoDB, the replica set is asymmetric, as slave nodes are read-only to share read workloads. As I mentioned at the beginning of this article, it's also possible to implement sharding to scale out Redis throughput and memory capacity. In reality, Redis is so powerful that an internal Amazon benchmark reveals that one EC2 instance of type r3.4xlarge easily handles 100,000 requests per second. Some have informally reported 700,000 requests per second as a benchmark. For small-to-medium applications, you generally will not need to bother with sharding in Redis. 

Transactions in Redis

Although Redis doesn't support full ACID transaction like an RDBMS does, its own flavor of transaction is quite effective. In essence, a Redis transaction is a combination of pipelining, optimistic locking, commits, and rollbacks. The idea is to execute a list of commands in a pipeline, then watch for possible updates on a critical record (optimistic lock). Depending on whether or not the watched record is updated by another process, the list of commands will either commit as a whole or roll back entirely.

 

Previous Page  1  2  3  4  5  6  7  Next Page 

Sign up for CIO Asia eNewsletters.