(七)使用jedis连接单机和集群(一步一个坑踩出来的辛酸泪)

时间:2021-12-19 17:26:47

环境准备:

  • 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、构建以下目录

(七)使用jedis连接单机和集群(一步一个坑踩出来的辛酸泪)

解释:

redis-cli:客户端,方便调试用

reids-trib.rb:集群的ruby脚本,去源码包复制过来

start-all-nodes.h:shell脚本,启动所有节点(参考下图)

stop-all-nodes.h:shell脚本,关闭集群(参考下图)

redis-cluster-configure.sh:开始集群部署,需要node节点全部启动(参考下图)

(七)使用jedis连接单机和集群(一步一个坑踩出来的辛酸泪)

(七)使用jedis连接单机和集群(一步一个坑踩出来的辛酸泪)

(七)使用jedis连接单机和集群(一步一个坑踩出来的辛酸泪)

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配置文件中手动注入