上节学习了cluster的搭建及redis-cli终端下如何操作,但是更常用的场景是在程序代码里对cluster读写,这需要redis-client对cluster模式的支持,目前spring-data-redis(1.6.4)还不支持cluster,最新的1.7.0 RC1已经有cluster的相关实现了,不过目前尚未正式发布,所以现阶段要使用redis-cluster的话,client最好还是选用原生的jedis,示例代码如下:
配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="jedisCluster" class="redis.clients.jedis.JedisCluster"> <constructor-arg index="0"> <set> <bean class="redis.clients.jedis.HostAndPort"> <constructor-arg name="host" value="127.0.0.1"/> <constructor-arg name="port" value="7000"/> </bean> <bean class="redis.clients.jedis.HostAndPort"> <constructor-arg name="host" value="127.0.0.1"/> <constructor-arg name="port" value="7001"/> </bean> <bean class="redis.clients.jedis.HostAndPort"> <constructor-arg name="host" value="127.0.0.1"/> <constructor-arg name="port" value="7002"/> </bean> <!--<bean class="redis.clients.jedis.HostAndPort">--> <!--<constructor-arg name="host" value="127.0.0.1"/>--> <!--<constructor-arg name="port" value="7003"/>--> <!--</bean>--> <!--<bean class="redis.clients.jedis.HostAndPort">--> <!--<constructor-arg name="host" value="127.0.0.1"/>--> <!--<constructor-arg name="port" value="7004"/>--> <!--</bean>--> <!--<bean class="redis.clients.jedis.HostAndPort">--> <!--<constructor-arg name="host" value="127.0.0.1"/>--> <!--<constructor-arg name="port" value="7005"/>--> <!--</bean>--> </set> </constructor-arg> </bean> </beans>
注:上面的这些节点,不需要配全,最少可以只保留一个cluster中的节点信息,运行时,jedis会自动发现其它节点,但是为了防止某个节点挂掉,所以建议配置时,还是多配置几个,保证这一堆节点中,至少有一个能连接上。
示例代码:
package com.cnblogs.yjmyzz.redis; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPool; import java.util.List; import java.util.Map; import java.util.Set; public class AppDemo { private static Logger logger = LoggerFactory.getLogger(AppDemo.class); private static JedisCluster jc = null; private static final String KEYS_STRING = "STRING"; private static final String KEYS_SET = "SET"; private static final String KEYS_LIST = "LIST"; private static final String KEYS_HASH = "HASH"; private static final String KEYS_ZSET = "ZSET"; private static void addKey(final String conainter, final String key) { if (!jc.exists(conainter)) { jc.sadd(conainter, key); } else { if (!jc.smembers(conainter).contains(key)) { jc.sadd(conainter, key); } } } /** * 写入字符串缓存 * * @param key * @param value * @return */ private static String set(final String key, final String value) { String result = jc.set(key, value); addKey(KEYS_STRING, key); return result; } /** * 写入Set缓存 * * @param key * @param member * @return */ private static Long sadd(final String key, final String... member) { Long result = jc.sadd(key, member); addKey(KEYS_SET, key); return result; } /** * 从左侧写入List * * @param key * @param string * @return */ private static Long lpush(final String key, final String... string) { Long result = jc.lpush(key, string); addKey(KEYS_LIST, key); return result; } /** * 写入HashMap缓存 * * @param key * @param field * @param value * @return */ private static Long hset(final String key, final String field, final String value) { Long result = jc.hset(key, field, value); addKey(KEYS_HASH, key); return result; } /** * 写入ZSet缓存 * * @param key * @param score * @param member * @return */ private static Long zadd(final String key, final double score, final String member) { Long result = jc.zadd(key, score, member); addKey(KEYS_ZSET, key); return result; } private static Long zadd(final String key, final String member) { Long result = jc.zadd(key, 0d, member); addKey(KEYS_ZSET, key); return result; } public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-redis.xml"); jc = ctx.getBean(JedisCluster.class); Map<String, JedisPool> nodes = jc.getClusterNodes(); for (Map.Entry<String, JedisPool> entry : nodes.entrySet()) { logger.info(entry.getKey() + " => " + entry.getValue().toString()); //清空所有数据 try { entry.getValue().getResource().flushDB(); } catch (Exception e) { logger.info(e.getLocalizedMessage());//slave节点上执行flushDB会报错 } //entry.getValue().getResource().keys("*");//慎用,缓存数量较大时,会引起性能问题. } //检测key是否存在 logger.info(jc.exists("a").toString()); //字符串写入测试 logger.info(set("a", "hello world!")); logger.info(set("b", "hello redis!")); //字符串读取测试 logger.info(jc.get("a")); //set写入操作 logger.info("set写入测试 ==>"); logger.info(sadd("set1", "a", "b", "c") + ""); //缓存类型测试 logger.info(jc.type("set1")); //set读取测试 logger.info("set读取测试 ==>"); Set<String> set1 = jc.smembers("set1"); for (String s : set1) { logger.info(s); } //list写入测试 logger.info("list写入测试 ==>"); logger.info(lpush("list1", "1", "2", "3") + ""); //list读取测试 logger.info("list读取测试 ==>"); List<String> list1 = jc.lrange("list1", 0, 999); for (String s : list1) { logger.info(s); } //hash写入测试 logger.info("hash写入测试 ==>"); logger.info(hset("hash1", "jimmy", "杨俊明") + ""); logger.info(hset("hash1", "CN", "中国") + ""); logger.info(hset("hash1", "US", "美国") + ""); //hash读取测试 logger.info("hash读取测试 ==>"); Map<String, String> hash1 = jc.hgetAll("hash1"); for (Map.Entry<String, String> entry : hash1.entrySet()) { logger.info(entry.getKey() + ":" + entry.getValue()); } //zset写入测试 logger.info("zset写入测试 ==>"); logger.info(zadd("zset1", "3") + ""); logger.info(zadd("zset1", "2") + ""); logger.info(zadd("zset1", "1") + ""); logger.info(zadd("zset1", "4") + ""); logger.info(zadd("zset1", "5") + ""); logger.info(zadd("zset1", "6") + ""); //zset读取测试 logger.info("zset读取测试 ==>"); Set<String> zset1 = jc.zrange("zset1", 0, 999); for (String s : zset1) { logger.info(s); } //遍历所有缓存项的key logger.info("遍历cluster中的所有key ==>"); logger.info(jc.smembers(KEYS_STRING).toString()); logger.info(jc.smembers(KEYS_HASH).toString()); logger.info(jc.smembers(KEYS_SET).toString()); logger.info(jc.smembers(KEYS_LIST).toString()); logger.info(jc.smembers(KEYS_ZSET).toString()); } }
注:建议尽量避免用jedis对节点做keys的模糊搜索,该操作在缓存项较多时,可能会导致redis性能急剧下降,改进办法是自己弄一个集合,记录所有缓存的key,具体可参考上面的办法。此外,jedis提供的命令非常之多,但是没有详细的说明文档(估计,作者认为代码就是最好的文档),大体可以从方法前缀猜测出来,比如sXXX表示是对Set的操作,hXXX表示是对hash的操作,lXXX或rXXX是对list的操作,zXXX是对zset的操作,什么前缀都没有的,比如set/get是对字符串的操作。
有网友把jedis的操作整理了一份文档,请参见:http://blog.csdn.net/zhu_xun/article/details/16806285
最后,附加上文中示例的源码:https://github.com/yjmyzz/redis-cluster-demo