#146 - Add example to demonstrate Redis Cluster support.

Example demonstrating the basic usage of Spring Data Redis in a clustered environment using Jedis.
This commit is contained in:
Christoph Strobl
2015-12-21 17:51:23 +01:00
committed by Oliver Gierke
parent 9cb44b3166
commit dfc1bf0390
8 changed files with 400 additions and 2 deletions

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.springdata.redis.cluster;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
/**
* Application context configuration setting up {@link RedisConnectionFactory} and {@link RedisTemplate} according to
* {@link ClusterConfigurationProperties}.
*
* @author Christoph Strobl
*/
@Configuration
@EnableConfigurationProperties(ClusterConfigurationProperties.class)
public class AppConfig {
/**
* Type safe representation of application.properties
*/
@Autowired ClusterConfigurationProperties clusterProperties;
/**
* The connection factory used for obtaining {@link RedisConnection} uses a {@link RedisClusterConfiguration} that
* points to the initial set of nodes.
*/
@Bean
RedisConnectionFactory connectionFactory() {
return new JedisConnectionFactory(new RedisClusterConfiguration(clusterProperties.getNodes()));
}
/**
* {@link RedisTemplate} can be configured with {@link RedisSerializer} if needed. <br />
* <b>NOTE:</b> be careful using JSON @link RedisSerializer} for key serialization.
*/
@Bean
RedisTemplate<String, String> redisTemplate() {
return new StringRedisTemplate(connectionFactory());
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.springdata.redis.cluster;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* Type safe representation of {@code spring.redis.cluster.*} properties in {@literal application.properties}.
*
* @author Christoph Strobl
*/
@Component
@ConfigurationProperties(prefix = "spring.redis.cluster")
public class ClusterConfigurationProperties {
List<String> nodes;
/**
* Get initial collection of known cluster nodes in format {@code host:port}.
*
* @return
*/
public List<String> getNodes() {
return nodes;
}
public void setNodes(List<String> nodes) {
this.nodes = nodes;
}
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.springdata.redis.cluster;
import static org.hamcrest.core.Is.*;
import static org.hamcrest.core.IsCollectionContaining.*;
import static org.junit.Assert.*;
import java.util.Arrays;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import example.springdata.redis.test.util.RequiresRedisServer;
/**
* {@link BasicUsageTests} shows general usage of {@link RedisTemplate} and {@link RedisOperations} in a clustered
* environment.
*
* @author Christoph Strobl
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = { AppConfig.class })
public class BasicUsageTests {
@Autowired RedisTemplate<String, String> template;
public static @ClassRule RequiresRedisServer redisServerAvailable = RequiresRedisServer.listeningAt("127.0.0.1",
30001);
@Before
public void setUp() {
template.execute(new RedisCallback<String>() {
@Override
public String doInRedis(RedisConnection connection) throws DataAccessException {
connection.flushDb();
return "FLUSHED";
}
});
}
/**
* Operation executed on a single node and slot. <br />
* -&gt; {@code SLOT 5798} served by {@code 127.0.0.1:30002}
*/
@Test
public void singleSlotOperation() {
template.opsForValue().set("name", "rand al'thor"); // slot 5798
assertThat(template.opsForValue().get("name"), is("rand al'thor"));
}
/**
* Operation executed on multiple nodes and slots. <br />
* -&gt; {@code SLOT 5798} served by {@code 127.0.0.1:30002} <br />
* -&gt; {@code SLOT 14594} served by {@code 127.0.0.1:30003}
*/
@Test
public void multiSlotOperation() {
template.opsForValue().set("name", "matrim cauthon"); // slot 5798
template.opsForValue().set("nickname", "prince of the ravens"); // slot 14594
assertThat(template.opsForValue().multiGet(Arrays.asList("name", "nickname")),
hasItems("matrim cauthon", "prince of the ravens"));
}
/**
* Operation executed on a single node and slot because of pinned slot key <br />
* -&gt; {@code SLOT 5798} served by {@code 127.0.0.1:30002}
*/
@Test
public void fixedSlotOperation() {
template.opsForValue().set("{user}.name", "perrin aybara"); // slot 5474
template.opsForValue().set("{user}.nickname", "wolfbrother"); // slot 5474
assertThat(template.opsForValue().multiGet(Arrays.asList("{user}.name", "{user}.nickname")),
hasItems("perrin aybara", "wolfbrother"));
}
/**
* Operation executed across the cluster to retrieve cumulated result. <br />
* -&gt; {@code KEY age} served by {@code 127.0.0.1:30001} <br />
* -&gt; {@code KEY name} served by {@code 127.0.0.1:30002} <br />
* -&gt; {@code KEY nickname} served by {@code 127.0.0.1:30003}
*/
@Test
public void multiNodeOperation() {
template.opsForValue().set("name", "rand al'thor"); // slot 5798
template.opsForValue().set("nickname", "dragon reborn"); // slot 14594
template.opsForValue().set("age", "23"); // slot 741;
assertThat(template.keys("*"), hasItems("name", "nickname", "age"));
}
}

View File

@@ -0,0 +1,3 @@
spring.redis.cluster.nodes[0]=127.0.0.1:30001
spring.redis.cluster.nodes[1]=127.0.0.1:30002
spring.redis.cluster.nodes[2]=127.0.0.1:30003