Redis是一個開源的使用ANSI C語言編寫、支持網絡、可基於內存亦可持久化的日誌型、Key-Value數據庫,並提供多種語言的APIjava
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
#redis cluster mc.cluster=192.168.10.20:6000,192.168.10.20:6001,192.168.10.20:6002,192.168.10.20:6003,192.168.10.20:6004,192.168.10.20:6005 mc.commandTimeout=5000
import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; import java.util.HashSet; import java.util.List; import java.util.Set; @Configuration @ConditionalOnClass({JedisCluster.class}) public class JedisClusterConfig { @Value("#{'${mc.cluster}'.split(',')}") private List<String> clusterIpPortList; @Value("${mc.commandTimeout:5000}") private Integer commandTimeout; @Bean public JedisCluster getJedisCluster() { Set<HostAndPort> nodes = new HashSet<>(); for (String ipPort : clusterIpPortList) { String[] ipPortPair = ipPort.split(":"); nodes.add(new HostAndPort(ipPortPair[0].trim(), Integer.valueOf(ipPortPair[1].trim()))); } return new JedisCluster(nodes, commandTimeout); } }
Maven 依賴node
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
Junitweb
import org.apache.log4j.Logger; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import com.cl.config.Application; import redis.clients.jedis.JedisCluster; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = Application.class) // 指定spring-boot的啓動類 @WebAppConfiguration public class TestJedis { private Logger logger = Logger.getLogger(getClass()); @Autowired private JedisCluster jedisCluster; @Test public void testJedis() { jedisCluster.set("test_jedis_cluster", "38967"); String string = jedisCluster.get("test_jedis_cluster"); logger.info(string); jedisCluster.del("test_jedis_cluster"); } }
須要注意keys要在相同的Slot可考慮使用 hash tag 即在key中加入{相同標識}redis
/** * 執行lua腳本 * <p> * 須要注意keys要在相同的Slot * 可考慮使用 hash tag 即在key中加入{相同標識} * </p> */ @Override public Object eval(final String script, final List<String> keys, final List<String> args) { return new JedisClusterCommand<Object>(connectionHandler, maxAttempts) { @Override public Object execute(Jedis connection) { return connection.eval(script, keys, args); } }.run(keys.size(), keys.toArray(new String[keys.size()])); }
public T run(int keyCount, String... keys) { if (keys == null || keys.length == 0) { throw new JedisClusterException("No way to dispatch this command to Redis Cluster."); } // For multiple keys, only execute if they all share the // same connection slot. if (keys.length > 1) { int slot = JedisClusterCRC16.getSlot(keys[0]); for (int i = 1; i < keyCount; i++) { int nextSlot = JedisClusterCRC16.getSlot(keys[i]); if (slot != nextSlot) { throw new JedisClusterException("No way to dispatch this command to Redis Cluster " + "because keys have different slots."); } } }
JedisClusterCRC16.getSlot(String key)spring
public static int getSlot(String key) { key = JedisClusterHashTagUtil.getHashTag(key); // optimization with modulo operator with power of 2 // equivalent to getCRC16(key) % 16384 return getCRC16(key) & (16384 - 1); }
JedisClusterHashTagUtil.getHashTag(String key)數據庫
public final class JedisClusterHashTagUtil { private JedisClusterHashTagUtil() { throw new InstantiationError("Must not instantiate this class"); } public static String getHashTag(String key) { return extractHashTag(key, true); } public static boolean isClusterCompliantMatchPattern(String matchPattern) { String tag = extractHashTag(matchPattern, false); return tag != null && !tag.isEmpty(); } private static String extractHashTag(String key, boolean returnKeyOnAbsence) { int s = key.indexOf("{"); if (s > -1) { int e = key.indexOf("}", s + 1); if (e > -1 && e != s + 1) { return key.substring(s + 1, e); } } return returnKeyOnAbsence ? key : null; } }