環境准備:
-
redis-4.0.9,最新版了
-
ruby:redis-x.x.x.gem 這個gem什么版本都行,我redis4用3.0.0的gem正常跑
-
jedis-2.9.0.jar,最新版
偽集群搭建:這里省略了,需要的看我前面的文檔,這里只貼出來一些關鍵點
1、下載、解壓
1 # make 2 # make install PREFIX=/usr/local/bin/
2、創建集群工作目錄,把redis/bin復制進去,需要幾台集群自己看着辦
3、修改每個節點的配置文件
1 port 7001 //端口7001,7002,7003... 2 bind 本機ip //默認ip為127.0.0.1 需要改為其他節點機器可訪問的ip 否則創建集群時無法訪問對應的端口,無法創建集群,直接注釋掉 3 daemonize yes //redis后台運行 4 cluster-enabled yes //開啟集群 把注釋#去掉
protect_mode no //如果bind注釋掉了,那么就把保護模式關掉
5 #可選項 6 cluster-config-file nodes.conf //集群的配置 配置文件首次啟動自動生成,默認就行
cluster-node-timeout 15000 //請求超時 默認15秒,可自行設置
appendonly yes //aof日志開啟 有需要就開啟,它會每次寫操作都記錄一條日志
4、安裝ruby、rubygems、redis.x.x.x.gem
1 # yum install ruby 2 # yum install rubygems 3 # 去官網下redis-x.x.x.gem,3.0以上都行 4 # gem install redis-4.0.1.gem
5、構建以下目錄
解釋:
redis-cli:客戶端,方便調試用
reids-trib.rb:集群的ruby腳本,去源碼包復制過來
start-all-nodes.h:shell腳本,啟動所有節點(參考下圖)
stop-all-nodes.h:shell腳本,關閉集群(參考下圖)
redis-cluster-configure.sh:開始集群部署,需要node節點全部啟動(參考下圖)
6、依次執行shell即可(start-all-nodes.sh ---> redis-cluster-configure.sh ---> input "yes")
集群測試:
1 @Test 2 public void testCluster() throws IOException, InterruptedException { 3 Set<HostAndPort> nodes = new HashSet<>(); 4 nodes.add(new HostAndPort("47.100.101.31", 7001)); 5 nodes.add(new HostAndPort("47.100.101.31", 7002)); 6 nodes.add(new HostAndPort("47.100.101.31", 7003)); 7 nodes.add(new HostAndPort("47.100.101.31", 7004)); 8 nodes.add(new HostAndPort("47.100.101.31", 7005)); 9 nodes.add(new HostAndPort("47.100.101.31", 7006)); 10 JedisCluster cluster = new JedisCluster(nodes); 11 try { 12 String res = cluster.get("name"); 13 System.out.println(res); 14 cluster.close(); 15 } catch (Exception e) { 16 e.printStackTrace(); 17 cluster.close(); 18 } 19 }
遇到的坑:
1)連接報錯:Connection refused。
錯誤原因:遠程拒絕鏈接,單機版和集群都報錯。
解決方案:當時bind 127.0.0.1。於是乎注釋掉,不行,提示沒有bind於是啟動了保護模式,所以配置:protect_mode no,單機版ok,redis客戶端連集群ok。
2)通過jedis連接redis單機成功,使用JedisCluster連接redis集群一直報Could not get a resource from the pool,但是使用redis客戶端可以連接集群(我使用的redis desktop manager)在java中通過jedis連接redis單機也成功,但使用JedisCluster連接redis集群一直報Could not get a resource from the pool,
錯誤原因:未知,以為jar包版本問題,換最新版2.9.0.jar,無效。糾結了好幾天,最后看一個博客說把127.0.0.1換成公網ip
解決:127.0.0.1換成公網IP,於是直接跑通。
疑問:127.0.0.1表示的就是本地,啟動后對外網來說127就是公網ip了,不知道為啥會錯,因為用其他客戶端都沒問題,懷疑是jedis內部機制導致的。
附錄:Spring集成redis
1 <!-- Jedis連接池配置, 可以寫在資源文件中 --> 2 <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> 3 <!-- 最大連接數 --> 4 <property name="maxTotal" value="30" /> 5 <!-- 最大空閑連接數 --> 6 <property name="maxIdle" value="10" /> 7 <!-- 每次釋放連接的最大數目 --> 8 <property name="numTestsPerEvictionRun" value="1024" /> 9 <!-- 釋放連接的掃描間隔(毫秒) --> 10 <property name="timeBetweenEvictionRunsMillis" value="30000" /> 11 <!-- 連接最小空閑時間 --> 12 <property name="minEvictableIdleTimeMillis" value="1800000" /> 13 <!-- 連接空閑多久后釋放, 當空閑時間>該值 且 空閑連接>最大空閑連接數 時直接釋放 --> 14 <property name="softMinEvictableIdleTimeMillis" value="10000" /> 15 <!-- 獲取連接時的最大等待毫秒數,小於零:阻塞不確定的時間,默認-1 --> 16 <property name="maxWaitMillis" value="1500" /> 17 <!-- 在獲取連接的時候檢查有效性, 默認false --> 18 <property name="testOnBorrow" value="true" /> 19 <!-- 在空閑時檢查有效性, 默認false --> 20 <property name="testWhileIdle" value="true" /> 21 <!-- 連接耗盡時是否阻塞, false報異常,ture阻塞直到超時, 默認true --> 22 <property name="blockWhenExhausted" value="false" /> 23 </bean> 24 <!-- jedis客戶端單機版 --> 25 <bean id="jedisPool" class="redis.clients.jedis.JedisPool"> 26 <constructor-arg name="host" value="47.100.101.31" /> 27 <constructor-arg name="port" value="6379" /> 28 <constructor-arg name="poolConfig" ref="jedisPoolConfig" /> 29 </bean> 30 <!-- Jedis集群版 --> 31 <bean id="jedisCluster" class="redis.clients.jedis.JedisCluster"> 32 <constructor-arg name="nodes"> 33 <set> 34 <bean class="redis.clients.jedis.HostAndPort"> 35 <constructor-arg name="host" value="47.100.101.31"/> 36 <constructor-arg name="port" value="7001"/> 37 </bean> 38 <bean class="redis.clients.jedis.HostAndPort"> 39 <constructor-arg name="host" value="47.100.101.31"/> 40 <constructor-arg name="port" value="7002"/> 41 </bean> 42 <bean class="redis.clients.jedis.HostAndPort"> 43 <constructor-arg name="host" value="47.100.101.31"/> 44 <constructor-arg name="port" value="7003"/> 45 </bean> 46 <bean class="redis.clients.jedis.HostAndPort"> 47 <constructor-arg name="host" value="47.100.101.31"/> 48 <constructor-arg name="port" value="7004"/> 49 </bean> 50 <bean class="redis.clients.jedis.HostAndPort"> 51 <constructor-arg name="host" value="47.100.101.31"/> 52 <constructor-arg name="port" value="7005"/> 53 </bean> 54 <bean class="redis.clients.jedis.HostAndPort"> 55 <constructor-arg name="host" value="47.100.101.31"/> 56 <constructor-arg name="port" value="7006"/> 57 </bean> 58 </set> 59 </constructor-arg> 60 <constructor-arg name="poolConfig" ref="jedisPoolConfig"/> 61 </bean>
使用集群請注釋掉單機版的
最后還有點小bug,7001節點不能出現在jediscluster的構造函數中,不然訪問7001節點內容會超時,原因未知。我用3.2.9重裝一遍沒發現任何問題,待大佬們解決吧
1 public interface JedisClient { 2 3 String get(String key); 4 5 String set(String key, String value); 6 7 long ttl(String key); 8 9 long expire(String key, int second); 10 11 long incr(String key); 12 13 long hset(String hkey, String key, String value); 14 15 String hget(String hkey, String key); 16 17 long del(String key); 18 19 long hdel(String hkey, String key); 20 }
1 public class JedisClientCluster implements JedisClient { 2 3 @Resource 4 private JedisCluster jedisCluster; 5 6 @Override 7 public String get(String key) { 8 return jedisCluster.get(key); 9 } 10 11 @Override 12 public String set(String key, String value) { 13 return jedisCluster.set(key, value); 14 } 15 16 @Override 17 public long ttl(String key) { 18 return jedisCluster.ttl(key); 19 } 20 21 @Override 22 public long expire(String key, int second) { 23 return jedisCluster.expire(key, second); 24 } 25 26 @Override 27 public long incr(String key) { 28 return jedisCluster.incr(key); 29 } 30 31 @Override 32 public long hset(String hkey, String key, String value) { 33 return jedisCluster.hset(hkey, key, value); 34 } 35 36 @Override 37 public String hget(String hkey, String key) { 38 return jedisCluster.hget(hkey, key); 39 } 40 41 @Override 42 public long del(String key) { 43 return jedisCluster.del(key); 44 } 45 46 @Override 47 public long hdel(String hkey, String key) { 48 return jedisCluster.del(hkey, key); 49 } 50 }
1 public class JedisClientSingle implements JedisClient { 2 3 @Resource 4 private JedisPool jedisPool; 5 6 @Override 7 public String get(String key) { 8 Jedis jedis = jedisPool.getResource(); 9 String string = jedis.get(key); 10 jedis.close(); 11 return string; 12 } 13 14 @Override 15 public String set(String key, String value) { 16 Jedis jedis = jedisPool.getResource(); 17 String string = jedis.set(key, value); 18 jedis.close(); 19 return string; 20 } 21 22 @Override 23 public String hget(String hkey, String key) { 24 Jedis jedis = jedisPool.getResource(); 25 String string = jedis.hget(hkey, key); 26 jedis.close(); 27 return string; 28 } 29 30 @Override 31 public long hset(String hkey, String key, String value) { 32 Jedis jedis = jedisPool.getResource(); 33 Long result = jedis.hset(hkey, key, value); 34 jedis.close(); 35 return result; 36 } 37 38 @Override 39 public long incr(String key) { 40 Jedis jedis = jedisPool.getResource(); 41 Long result = jedis.incr(key); 42 jedis.close(); 43 return result; 44 } 45 46 @Override 47 public long expire(String key, int second) { 48 Jedis jedis = jedisPool.getResource(); 49 Long result = jedis.expire(key, second); 50 jedis.close(); 51 return result; 52 } 53 54 @Override 55 public long ttl(String key) { 56 Jedis jedis = jedisPool.getResource(); 57 Long result = jedis.ttl(key); 58 jedis.close(); 59 return result; 60 } 61 62 @Override 63 public long del(String key) { 64 Jedis jedis = jedisPool.getResource(); 65 Long result = jedis.del(key); 66 jedis.close(); 67 return result; 68 } 69 70 @Override 71 public long hdel(String hkey, String key) { 72 Jedis jedis = jedisPool.getResource(); 73 Long result = jedis.hdel(hkey, key); 74 jedis.close(); 75 return result; 76 } 77 }
如果集群版和主從復制版想要共存,那么就在spring配置文件中手動注入