什么是Redis-Cluster?
为何要搭建Redis 集群。Redis 是在内存中保存数据的,而我们的电脑一般内存都不大,这也就意味着Redis 不适合存储大数据,适合存储大数据的是Hadoop 生态系统的Hbase 或者是MogoDB。Redis 更适合处理高并发,一台设备的存储能力是很限的,但是多台设备协同合作,就可以让内存增大很多倍,这就需要用到集群。
Redis 集群搭建的方式有多种,例如使用客户端分片、Twemproxy、Codis 等,但从
redis 3.0 之后版本支持redis-cluster 集群, 它是Redis 官方提出的解决方案,
Redis-Cluster 采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所
有节点连接。其redis-cluster 架构图如下:
架构细节:
(1)所有的redis 节点彼此互联(PING-PONG 机制),内部使用二进制协议优化传输速度和带
宽.
(2)节点的fail 是通过集群中超过半数的节点检测失效时才生效.
(3)客户端与redis 节点直连,不需要中间proxy 层.客户端不需要连接集群所有节点,连接
集群中任何一个可用节点即可
理解分布存储机制-槽
(1)redis-cluster 把所有的物理节点映射到[0-16383]slot 上,cluster 负责维护
node<->slot<->value
(2)Redis 集群中内置了16384 个哈希槽,当需要在Redis 集群中放置一个key-value 时,
redis 先对key 使用crc16 算法算出一个结果,然后把结果对16384 求余数,这样每个key
都会对应一个编号在0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映
射到不同的节点。
(1)选举过程是集群中所有master 参与,如果半数以上master 节点与故障节点通信超过(cluster-node-timeout),认为该节点故障,自动触发故障转移操作.
(2)什么时候整个集群不可用(cluster_state:fail)?
a: 如果集群任意master 挂掉,且当前master 没有slave.集群进入fail 状态,也可以理解成集群的slot 映射[0-16383]不完成时进入fail 状态.
b: 如果集群超过半数以上master 挂掉,无论是否有slave 集群进入fail 状态.
搭建redis-cluster
搭建要求
需要6 台redis 服务器。搭建伪集群。
需要6 个redis 实例。
需要运行在不同的端口7001-7006
准备工作
(1)安装gcc 【此步省略】
Redis 是c 语言开发的。安装redis 需要c 语言的编译环境。如果没有gcc 需要在线安装。
yum install gcc-c++
(2)使用yum 命令安装ruby (我们需要使用ruby 脚本来实现集群搭建)【此步省略】
yum install ruby yum install rubygems(3)将redis 源码包上传到linux 系统,解压redis 源码包
(4)编译redis 源码,进入redis 源码文件夹
make看到以下输出结果,表示编译成功
(5)创建目录/usr/local/redis-cluster 目录, 安装6 个redis 实例,分别安装在以下目录
/usr/local/redis-cluster/redis-1 /usr/local/redis-cluster/redis-2 /usr/local/redis-cluster/redis-3 /usr/local/redis-cluster/redis-4 /usr/local/redis-cluster/redis-5 /usr/local/redis-cluster/redis-6
以第一个redis 实例为例,命令如下
make install PREFIX=/usr/local/redis-cluster/redis-1
出现此提示表示成功,按此方法安装其余5 个redis 实例
(5)复制配置文件将/redis-3.0.0/redis.conf 复制到redis 下的bin 目录下
[root@localhost redis-3.0.0]# cp redis.conf /usr/local/redis-cluster/redis-1/bin [root@localhost redis-3.0.0]# cp redis.conf /usr/local/redis-cluster/redis-2/bin [root@localhost redis-3.0.0]# cp redis.conf /usr/local/redis-cluster/redis-3/bin [root@localhost redis-3.0.0]# cp redis.conf /usr/local/redis-cluster/redis-4/bin [root@localhost redis-3.0.0]# cp redis.conf /usr/local/redis-cluster/redis-5/bin [root@localhost redis-3.0.0]# cp redis.conf /usr/local/redis-cluster/redis-6/bin
配置集群
(1)修改配置文件
修改运行端口为7001 (7002 7003 .....)
将cluster-enabled yes 前的注释去掉
(2)启动每个redis 实例
以第一个实例为例,命令如下(可以设置为后台启动)
cd /usr/local/redis-cluster/redis-1/bin/
./redis-server redis.conf
把其余的5 个也启动起来,然后查看一下是不是都启动起来了
[root@localhost ~]# ps -ef | grep redis root 15776 15775 0 08:19 pts/1 00:00:00 ./redis-server *:7001 [cluster] root 15810 15784 0 08:22 pts/2 00:00:00 ./redis-server *:7002 [cluster] root 15831 15813 0 08:23 pts/3 00:00:00 ./redis-server *:7003 [cluster] root 15852 15834 0 08:23 pts/4 00:00:00 ./redis-server *:7004 [cluster] root 15872 15856 0 08:24 pts/5 00:00:00 ./redis-server *:7005 [cluster] root 15891 15875 0 08:24 pts/6 00:00:00 ./redis-server *:7006 [cluster] root 15926 15895 0 08:24 pts/7 00:00:00 grep redis
(3)上传redis-3.0.0.gem ,安装ruby 用于搭建redis 集群的脚本。
(4)使用ruby 脚本搭建集群。
进入
./redis-trib.rb create --replicas 1 192.168.25.135:7001 192.168.25.135:7002 192.168.25.135:7003 192.168.25.135:7004 192.168.25.135:7005 192.168.25.135:7006
出现下列提示信息
连接redis-cluster
客户端工具连接
Redis-cli 连接集群。
redis-cli -p 7004 -c
-c:代表连接的是redis 集群
测试:
SpringDataRedis 连接
(1)创建SpringDataRedis-ClusterDemo 工程引入依赖
<!-- 集中定义依赖版本号--> <properties> <spring.version>4.2.4.RELEASE</spring.version> </properties> <dependencies> <!-- Spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.9</version> </dependency> <!-- 缓存--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.8.1</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.7.2.RELEASE</version> </dependency> </dependencies> <build> <plugins> <!-- java 编译插件--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.2</version> <configuration> <source>1.7</source> <target>1.7</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build>
添加spring 配置文件
applicationContext-redis-cluster.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 加载配置属性文件--> <context:property-placeholder ignore-unresolvable="true" location="classpath:properties/redis-cluster-config.properties" /> <bean id="redis-clusterConfiguration" class="org.springframework.data.redis.connection.redis-clusterConfiguration"> <property name="maxRedirects" value="${redis.maxRedirects}"></property> <property name="clusterNodes"> <set> <bean class="org.springframework.data.redis.connection.redis-clusterNode"> <constructor-arg name="host" value="${redis.host1}"></constructor-arg> <constructor-arg name="port" value="${redis.port1}"></constructor-arg> </bean> <bean class="org.springframework.data.redis.connection.redis-clusterNode"> <constructor-arg name="host" value="${redis.host2}"></constructor-arg> <constructor-arg name="port" value="${redis.port2}"></constructor-arg> </bean> <bean class="org.springframework.data.redis.connection.redis-clusterNode"> <constructor-arg name="host" value="${redis.host3}"></constructor-arg> <constructor-arg name="port" value="${redis.port3}"></constructor-arg> </bean> <bean class="org.springframework.data.redis.connection.redis-clusterNode"> <constructor-arg name="host" value="${redis.host4}"></constructor-arg> <constructor-arg name="port" value="${redis.port4}"></constructor-arg> </bean> <bean class="org.springframework.data.redis.connection.redis-clusterNode"> <constructor-arg name="host" value="${redis.host5}"></constructor-arg> <constructor-arg name="port" value="${redis.port5}"></constructor-arg> </bean> <bean class="org.springframework.data.redis.connection.redis-clusterNode"> <constructor-arg name="host" value="${redis.host6}"></constructor-arg> <constructor-arg name="port" value="${redis.port6}"></constructor-arg> </bean> </set> </property> </bean> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxIdle" value="${redis.maxIdle}" /> <property name="maxTotal" value="${redis.maxTotal}" /> </bean> <bean id="jeidsConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" > <constructor-arg ref="redis-clusterConfiguration" /> <constructor-arg ref="jedisPoolConfig" /> </bean> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jeidsConnectionFactory" /> </bean> </beans>
(4)编写测试类,测试值的存取
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="classpath:spring/applicationContext-redis-cluster. xml") public class TestSet { @Autowired private RedisTemplate<String,String> redisTemplate; @Test public void testSetValue(){ redisTemplate.boundSetOps("nameset").add("liming"); redisTemplate.boundSetOps("nameset").add("liuhu"); redisTemplate.boundSetOps("nameset").add("zhoujian"); } @Test public void testGetValue(){ Set<String> members = redisTemplate.boundSetOps("nameset").members(); System.out.println(members); } }