上節學習了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