一文轻松搞懂redis集群原理及搭建与使用

今天早上由于zookeeper和redis集群不在同一虚拟机导致出了点很小错误(人为),所以这里总结一下redis集群的搭建以便日后所需同时也希望能对你有所帮助。

一 redis的安装

Redis是c语言开发的。 安装redis需要c语言的编译环境。如果没有gcc需要在线安装:yum install gcc-c++

第一步:获取源码包:wget http://download.redis.io/releases/redis-3.0.0.tar.gz

第二步:解压缩redis:tar zxvf redis-3.0.0.tar.gz

第三步:编译。进入redis源码目录(cd redis-3.0.0)。执行 make

第四步:安装。make install PREFIX=/usr/local/redis

PREFIX参数指定redis的安装目录。一般软件安装到/usr目录下

这样Redis就成功装在了我们的usr/local/redis目录下。

第五步:设置后台启动: [root@localhost redis-3.0.0]# cp redis.conf /usr/local/redis/bin/ (把/root/redis-3.0.0/redis.conf复制到/usr/local/redis/bin目录下)

修改配置文件:把daemonize后面的参数改为yes

《一文轻松搞懂redis集群原理及搭建与使用》

测试启动:[root@localhost bin]# ./redis-server redis.conf

查看redis进程: [root@localhost bin]# ps aux|grep redis

二 redis集群的搭建

2.1 redis集群(redis-cluster)原理

3.0版本之前的redis是不支持集群的,3.0版本之前想要搭建redis集群的话需要中间件来找到存值和取值的对应节点。

3.0版本以后的redis集群架构图:

《一文轻松搞懂redis集群原理及搭建与使用》

那么这是如何实现的呢???

Redis 集群中内置了 16384个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。

根据下图应该更容易理解了。(图片来源:http://www.cnblogs.com/liyasong/p/redis_jiqun.html)

《一文轻松搞懂redis集群原理及搭建与使用》

redis集群投票机制

redis集群中有多台redis服务器不可避免会有服务器挂掉。redis集群服务器之间通过互相的ping-pong判断是否节点可以连接上。如果有一半以上的节点去ping一个节点的时候没有回应,集群就认为这个节点宕机了。

上面就是我们常说的为了容错而生的redis集群投票机制

《一文轻松搞懂redis集群原理及搭建与使用》

2.2 redis集群(redis-cluster)的搭建

redis集群搭建起来很简单,我们这里用一台虚拟机模拟搭建包含6个redis服务器的集群,实际工作中与使用多台服务器搭建是一个操作。

我们上面已经装好了一个redis实例,现在我们需要把它复制6份并修改相应端口。

第一步: 新建redis-cluster文件夹

《一文轻松搞懂redis集群原理及搭建与使用》

第二步:复制redis实例

[root@Snailclimb local]# cp redis/bin redis-cluster/redis1

如果你复制过去的redis实例有dump.rdb文件的话最好也要删除。

《一文轻松搞懂redis集群原理及搭建与使用》

第三步:修改配置文件

修改bin目录下的redis.conf配置文件

《一文轻松搞懂redis集群原理及搭建与使用》

第四步:继续复制5个redis实例

我们用上面的redis实例复制5个redis实例,然后把他们的配置文件的端口号改为7002-7006

《一文轻松搞懂redis集群原理及搭建与使用》

第五步 :新建一个执行脚本: [root@Snailclimb redis-cluster]# vim start-all.sh 脚本内容如下:

cd redis1/bin

./redis-server redis.conf

cd ..

cd ..

cd redis2/bin

./redis-server redis.conf

cd ..

cd ..

cd redis3/bin

./redis-server redis.conf

cd ..

cd ..

cd redis4/bin

./redis-server redis.conf

cd ..

cd ..

cd redis5/bin

./redis-server redis.conf

cd ..

cd ..

cd redis6/bin

./redis-server redis.conf

为脚本赋予执行权限:

[root@Snailclimb redis-cluster]# chmod u+x start-all.sh

同时启动6个redis实例:

[root@Snailclimb redis-cluster]# ./start-all.sh

第六步:将redis-trib.rb复制到redis-cluster目录下面:

《一文轻松搞懂redis集群原理及搭建与使用》

并为脚本赋予执行权限: [root@Snailclimb redis-cluster]# chmod u+x redis-trib.rb

第七步:安装ruby和ruby运行环境

yum install ruby

yum install rubygems

gem install redis-3.0.0.gem

第八步:使用ruby脚本搭建集群:

[root@Snailclimb redis-cluster]#./redis-trib.rb create –replicas 1 192.168.25.155:7001 192.168.25.155:7002 192.168.25.155:7003 192.168.25.155:7004 192.168.25.155:7005 192.168.25.155:7006

查看集群:

《一文轻松搞懂redis集群原理及搭建与使用》

注意:端口修改错误或者没有将cluster-enabled yes前的注释去掉都会导致集群搭建失败。总的来说,redis集群搭建还是很简单的。

这样一个完整的redis集群就已经搭建完毕了。。。

三 redis单机版与集群版的测试使用

添加Maven依赖:

redis.clientsjedis2.7.2junitjunit4.12test

单机版redis测试:

@TestpublicvoidtestJedis()throwsException{// 创建一个连接Jedis对象,参数:host、portJedis jedis =newJedis(“192.168.25.155”,6379);// 直接使用jedis操作redis。所有jedis的命令都对应一个方法。jedis.set(“bwcx9393″,”欢迎关注Java面试通关手册”);String string = jedis.get(“bwcx9393”);System.out.println(string);//输出内容:欢迎关注微信公众号:Java面试通关手册// 关闭连接jedis.close();}

使用连接池测试单机版redis:

@TestpublicvoidtestJedisPool()throwsException{// 创建一个连接池对象,两个参数host、portJedisPool jedisPool =newJedisPool(“192.168.25.155”,6379);// 从连接池获得一个连接,就是一个jedis对象。Jedis jedis = jedisPool.getResource();// 使用jedis操作redisString string = jedis.get(“bwcx9393”);System.out.println(string);//输出内容:欢迎关注微信公众号:Java面试通关手册// 关闭连接,每次使用完毕后关闭连接。连接池回收资源。jedis.close();// 关闭连接池。jedisPool.close();}

测试集群版redis:

@TestpublicvoidtestJedisCluster()throwsException{// 创建一个JedisCluster对象。有一个参数nodes是一个set类型。set中包含若干个HostAndPort对象。Set nodes =newHashSet<>();nodes.add(newHostAndPort(“192.168.25.155”,7001));nodes.add(newHostAndPort(“192.168.25.155”,7002));nodes.add(newHostAndPort(“192.168.25.155”,7003));nodes.add(newHostAndPort(“192.168.25.155”,7004));nodes.add(newHostAndPort(“192.168.25.155”,7005));nodes.add(newHostAndPort(“192.168.25.155”,7006));JedisCluster jedisCluster =newJedisCluster(nodes);// 直接使用JedisCluster对象操作redis。jedisCluster.set(“test”,”123″);String string = jedisCluster.get(“test”);System.out.println(string);// 关闭JedisCluster对象jedisCluster.close();}

四 如何在JavaWeb项目中实现单机和集群无缝切换使用

我们如何才能在项目中实现自己想用的单机redis就用单机redis想用redis集群就用redis集群而不要修改项目代码呢???

创建相应类和接口

《一文轻松搞懂redis集群原理及搭建与使用》

接口:

import java.util.List;

public interface JedisClient{

String set(String key, String value);

String get(String key);

Booleanexists(String key);

Longexpire(String key,intseconds);

Longttl(String key);Longincr(String key);

Longhset(String key, String field, String value);

Stringhget(String key, String field);

Longhdel(String key, String… field);

Booleanhexists(String key, String field);

Listhvals(String key);

Longdel(String key);

}

集群版使用:

import java.util.List; importredis.clients.jedis.JedisCluster;

publicclassJedisClientClusterimplementsJedisClient{

privateJedisCluster jedisCluster;

public JedisClustergetJedisCluster(){

returnjedisCluster;}publicvoidsetJedisCluster(JedisCluster jedisCluster){this.jedisCluster = jedisCluster;}@OverridepublicStringset(String key, String value){returnjedisCluster.set(key, value);}@OverridepublicStringget(String key){returnjedisCluster.get(key);}@OverridepublicBooleanexists(String key){returnjedisCluster.exists(key);}@OverridepublicLongexpire(String key,intseconds){returnjedisCluster.expire(key, seconds);}@OverridepublicLongttl(String key){returnjedisCluster.ttl(key);}@OverridepublicLongincr(String key){returnjedisCluster.incr(key);}@OverridepublicLonghset(String key, String field, String value){returnjedisCluster.hset(key, field, value);}@OverridepublicStringhget(String key, String field){returnjedisCluster.hget(key, field);}@OverridepublicLonghdel(String key, String… field){returnjedisCluster.hdel(key, field);}@OverridepublicBooleanhexists(String key, String field){returnjedisCluster.hexists(key, field);}@OverridepublicListhvals(String key){returnjedisCluster.hvals(key);}@OverridepublicLongdel(String key){returnjedisCluster.del(key);}}

单机版使用:

importjava.util.List;importredis.clients.jedis.Jedis;importredis.clients.jedis.JedisPool;publicclassJedisClientPoolimplementsJedisClient{privateJedisPool jedisPool;publicJedisPoolgetJedisPool(){returnjedisPool;}publicvoidsetJedisPool(JedisPool jedisPool){this.jedisPool = jedisPool;}@OverridepublicStringset(String key, String value){Jedis jedis = jedisPool.getResource();String result = jedis.set(key, value);jedis.close();returnresult;}@OverridepublicStringget(String key){Jedis jedis = jedisPool.getResource();String result = jedis.get(key);jedis.close();returnresult;}@OverridepublicBooleanexists(String key){Jedis jedis = jedisPool.getResource();Boolean result = jedis.exists(key);jedis.close();returnresult;}@OverridepublicLongexpire(String key,intseconds){Jedis jedis = jedisPool.getResource();Long result = jedis.expire(key, seconds);jedis.close();returnresult;}@OverridepublicLongttl(String key){Jedis jedis = jedisPool.getResource();Long result = jedis.ttl(key);jedis.close();returnresult;}@OverridepublicLongincr(String key){Jedis jedis = jedisPool.getResource();Long result = jedis.incr(key);jedis.close();returnresult;}@OverridepublicLonghset(String key, String field, String value){Jedis jedis = jedisPool.getResource();Long result = jedis.hset(key, field, value);jedis.close();returnresult;}@OverridepublicStringhget(String key, String field){Jedis jedis = jedisPool.getResource();String result = jedis.hget(key, field);jedis.close();returnresult;}@OverridepublicLonghdel(String key, String… field){Jedis jedis = jedisPool.getResource();Long result = jedis.hdel(key, field);jedis.close();returnresult;}@OverridepublicBooleanhexists(String key, String field){Jedis jedis = jedisPool.getResource();Boolean result = jedis.hexists(key, field);jedis.close();returnresult;}@OverridepublicListhvals(String key){Jedis jedis = jedisPool.getResource();List result = jedis.hvals(key);jedis.close();returnresult;}@OverridepublicLongdel(String key){Jedis jedis = jedisPool.getResource();Long result = jedis.del(key);jedis.close();returnresult;}}

applicationContext-redis.xml

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd

http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd”>–>

–>

测试代码:

publicclassJedisClientTest{@TestpublicvoidtestJedisClient()throwsException{//初始化spring容器ApplicationContext applicationContext =newClassPathXmlApplicationContext(“classpath:spring/applicationContext-redis.xml”);//从容器中获得JedisClient对象JedisClient jedisClient = applicationContext.getBean(JedisClient.class);jedisClient.set(“aaa”,”111″);String string = jedisClient.get(“aaa”);System.out.println(string);}}

这样在实际项目中我们无需修改代码就可以实现单机和集群版的相关切换。。

关于Redis的一些常见面试问题总结,我写了另外一篇文章:《面试中关于Redis的问题看这篇就够了》juejin.im/post/5ad6e4…

    原文作者:杜弥
    原文地址: https://www.jianshu.com/p/887c6b84a5a7
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞