redis集群模式
集群的特点
去中心化,客户端与redis节点直连,不需要中间proxy层(不象哨兵)。客户端不需要连接集群所有节点,连接集群中任何一个可用节点(主节点)即可。 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。 分片,把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value映射关系,无需关心数据落到那个节点。 节点的fail是通过集群中超过半数的节点(主节点)检测失效时才生效。 选举容错,自动将节点分成主从,形成主从复制(从只读),数据备份容灾,同时实现读写分离。 集群最少6个节点,3主3从。 选举过程是集群中所有master参与,如果半数以上master节点与master节点通信超过(cluster-node-timeout),认为当前master节点挂掉。 什么时候整个集群不可用(cluster_state:fail),当集群不可用时,所有对集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)错误: a: 如果集群任意master挂掉,且当前master没有slave。集群进入fail状态,也可以理解成进群的slot映射[0-16383]不完成全进入fail状态。 b: 如果进群超过半数以上master挂掉,无论是否有slave集群进入fail状态。
安装Ruby
yum install ruby ruby –v #ruby 1.8.7 yum install rubygems #也可以一句执行 yum install ruby rubygems -y gem install redis #安装redis的接口包 gem list #查看是否安装了gem相关的接口包,检查redis是否已经存在
如果出现:Error installing redis: redis requires Ruby version >= 2.2.2.则执行下面操作: 1.安装curl sudo yum install curl 2安装RVM gpg2 --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3 curl -L get.rvm.io | bash -s stable source /usr/local/rvm/scripts/rvm 3、删除之前安装的ruby ruby --version rvm remove 2.0.0 安装新的ruby 2.3.3版本的 rvm list known rvm install 2.3.3 rvm use 2.3.3 --default gem install redis
gem list #查看是否安装了gem相关的接口包,检查redis是否已经存在
由于cluster的特点,与redis传统主从不同的是,cluster中的节点需要配置在不同的文件夹,否则无法创建集群(尝试过一次,失败)。进入redis根目录,创建节点文件夹,同一个服务器上的不同节点文件夹可以用端口号来命名即可。
1、在redis的安装目录下创建七个目录

2、每个目录都放置一个redis的配置文件redis.conf,修改以下内容
P61 bind 127.0.0.1 //默认ip为127.0.0.1改为其他节点机器可访问的ip P80 protected-mode no //yes修改为no,启动报错就删除它 P84 port 7000 //端口7000 P128 daemonize yes //后台运行 P150 pidfile /usr/local/src/redis/redis3.2.6/redis_7000.pid //pidfile文件对应7000 P593 appendonly yes //默认是rdb方式持久化要改成AOF模式 P163 logfile=7000/redis.log //相对路径,启动时在redis的根目录 P721 cluster-enabled yes //开启集群 P729 cluster-config-file nodes_7000.conf //集群的配置 P735 cluster-node-timeout 15000 //请求超时默认15秒,可自行设置
3、在redis根目录创建快速启动脚本:start.sh,路径为:/home/redis/redis-3.0.7/start.sh
#!/bin/sh //开头必须写它 redis-server 7000/redis.conf& redis-server 7001/redis.conf& redis-server 7002/redis.conf& redis-server 7003/redis.conf& redis-server 7004/redis.conf& redis-server 7005/redis.conf& redis-server 7006/redis.conf&
4、关闭防火墙或打开对应端口:
service iptables stop
5、启动脚本
[root@localhost redis-3.0.7]# bash start.sh
6、查看redis的进程是否正常启动了
ps - ef |grep redis
7、在redis的根目录启动集群
[root@localhost redis-3.0.7]# ./src/redis-trib.rb create --replicas 1 192.168.29.129:7000 192.168.29.129:7001 192.168.29.129:7002 192.168.29.129:7003 192.168.29.129:7004 192.168.29.129:7005 192.168.29.129:7006 #replicas 1 表示希望为集群中的每个主节点创建一个从节点(一主一从) 前几个自动做为主,后面几个做为从,主节点少于从节点,个数不对应时,多从挂接在一个主上。 注意:提示必须敲入yes,不能是y,y则按不接受处理。 注意:redis-trib-rb的路径,可以配置环境变量来解决 export PATH=/usr/local/ruby-2.1.2/bin;&PATH
8、如果上述启动失败需要先删除临时文件方可重新启动

9、登录集群
redis-cli -c -p 7000 #任何一个端口都可以 cluster info #查看集群状态 cluster nodes #查看集群节点状态
#杀掉一个7001,集群继续运行 ps -ef |grep redis kill 5398 127.0.0.1:7000> cluster nodes #被杀的主节点,由从节点顶上成为master redis-server 7001/redis.conf #重新启动的节点会成为slave挂到顶替它的节点后面
10、sprig整合redis集群模式
添加依赖
<!--redis begin--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>2.0.7.RELEASE</version> </dependency> <!--redis end-->
配置配置文件:applicationContext-rediscluster.xml (以spring工厂方式创建redisCluster对象)
<?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"> <!-- jedis 配置--> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig" > <!--最大空闲数--> <property name="maxIdle" value="${redis.maxIdle}" /> <!--最大建立连接等待时间--> <property name="maxWaitMillis" value="${redis.maxWait}" /> <!--是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个--> <property name="testOnBorrow" value="${redis.testOnBorrow}" /> <property name="maxTotal" value="${redis.maxTotal}" /> <property name="minIdle" value="${redis.minIdle}" /> </bean> <bean id="jedisCluster" class="cn.jiaming.chen.utils.RedisClusterFactor" > <property name="addressConfig"> <value>classpath:redis.properties</value> </property> <!-- 属性文件里 key的前缀 --> <property name="addressKeyPrefix" value="redis.cluster" /><property name="timeout" value="${redis.timeout}" /> <property name="maxRedirections" value="6" /> <property name="genericObjectPoolConfig" ref="poolConfig" /> </bean> </beans>
配置redis.properties配置文件
#最小空闲数 redis.minIdle=100 #最大空闲数 redis.maxIdle=300 redis.maxActive=300 #最大连接数 redis.maxTotal=1000 #客户端超时时间单位是毫秒 redis.timeout=1000 #最大建立连接等待时间 redis.maxWait=1000 #是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个 redis.testOnBorrow=true redis.node1.ip=192.168.29.129 redis.node1.port=6379 redis.node2.ip=192.168.29.129 redis.node2.port=6380 redis.node3.ip=192.168.29.129 redis.node3.port=6381 #redis cluster redis.cluster0.host.port=192.168.29.129:7000 redis.cluster1.host.port=192.168.29.129:7001 redis.cluster2.host.port=192.168.29.129:7002 redis.cluster3.host.port=192.168.29.129:7003 redis.cluster4.host.port=192.168.29.129:7004 redis.cluster5.host.port=192.168.29.129:7005 redis.cluster6.host.port=192.168.29.129:7006
添加自定义spring工厂类
package cn.jiaming.chen.utils; import java.util.HashSet; import java.util.Properties; import java.util.Set; import java.util.regex.Pattern; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.io.Resource; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; public class RedisClusterFactor implements FactoryBean<JedisCluster>, InitializingBean { private Resource addressConfig; private String addressKeyPrefix; private JedisCluster jedisCluster; private Integer timeout; private Integer maxRedirections; private GenericObjectPoolConfig poolConfig; private Pattern p = Pattern.compile("^.+[:]\\d{1,5}\\s*$"); public JedisCluster getObject() throws Exception { return jedisCluster; } public Class<? extends JedisCluster> getObjectType() { return (this.jedisCluster != null ? this.jedisCluster.getClass() : JedisCluster.class); } public boolean isSingleton() { return true; } private Set<HostAndPort> parseHostAndPort() { try { Properties prop = new Properties(); prop.load(this.addressConfig.getInputStream()); Set<HostAndPort> haps = new HashSet<HostAndPort>(); for (Object key : prop.keySet()) { if (!((String) key).startsWith(addressKeyPrefix)) { continue; } String val = (String) prop.get(key); boolean isIpPort = p.matcher(val).matches(); if (!isIpPort) { throw new IllegalArgumentException("ip 或 port 不合法"); } String[] ipAndPort = val.split(":"); HostAndPort hap = new HostAndPort(ipAndPort[0], Integer.parseInt(ipAndPort[1])); haps.add(hap); } return haps; } catch (IllegalArgumentException ex) { ex.printStackTrace(); } catch (Exception ex) { ex.printStackTrace(); } return null; } public void afterPropertiesSet() throws Exception { Set<HostAndPort> haps = this.parseHostAndPort(); jedisCluster = new JedisCluster(haps, timeout, maxRedirections, poolConfig); } public void setAddressConfig(Resource addressConfig) { this.addressConfig = addressConfig; } public void setTimeout(int timeout) { this.timeout = timeout; } public void setMaxRedirections(int maxRedirections) { this.maxRedirections = maxRedirections; } public void setAddressKeyPrefix(String addressKeyPrefix) { this.addressKeyPrefix = addressKeyPrefix; } public void setGenericObjectPoolConfig(GenericObjectPoolConfig poolConfig) { this.poolConfig = poolConfig; } }
在需要使用redis集群的地方注入spring工厂创建的类即可
@Autowired private JedisCluster jedisCluster; //测试 jedisCluster.exists(unitKey); jedisCluster.set(unitKey,"123");
posted on 2018-06-06 13:38 javaGreenHand。。。 阅读(100) 评论(0) 收藏 举报
浙公网安备 33010602011771号