Redis主从复制的功能非常强大,它有以下好处:
1.避免Redis单点故障
2.构建读写分离架构,满足读多写少的应用场景
主从架构
1.1、Redis主从架构拓扑结构图
1.2、搭建步骤
Redis集群不用安装多个Redis,只需复制多个配置文件,修改即可。所以如果要进行主从结构搭建,需先安装单机版Redis。
1.2.1、下载redis 3.2.8
root@shuyizhi-VirtualBox:/6381# wget http://download.redis.io/releases/redis-3.2.8.tar.gz
1.2.2、解压
root@shuyizhi-VirtualBox:/6381# tar -zxzf redis-3.2.8.tar.gz
1.2.3、进入Redis所在的目录
root@shuyizhi-VirtualBox:/6381# cd redis-3.2.8/
1.2.4、新建三个目录
root@shuyizhi-VirtualBox:/6381# mkdir 6379
root@shuyizhi-VirtualBox:/6381# mkdir 6380
root@shuyizhi-VirtualBox:/6381# mkdir 6381
1.2.5、复制三份配置文件
root@shuyizhi-VirtualBox:/6381# cp redis-3.2.8/redis.conf 6379/6379.conf
root@shuyizhi-VirtualBox:/6381# cp redis-3.2.8/redis.conf 6380/6380.conf
root@shuyizhi-VirtualBox:/6381# cp redis-3.2.8/redis.conf 6381/6381.conf
1.2.6、分别修改6379~6380的conf文件
root@shuyizhi-VirtualBox:/6381# vi 6379.conf
# Redis使用后台模式
daemonize yes
# 关闭保护模式
protected-mode no
# 注释以下内容开启远程访问# bind 127.0.0.1# 修改启动端口为6379
port 6379
# 修改pidfile指向路径pidfile
pidfile /6381/redis_6381.pid
以此类推,修改端口6380及6381配置。
1.2.7、分别启动三个redis实例
root@shuyizhi-VirtualBox:/6381# /redis-3.2.8/bin/redis-server /6379/6379.conf
root@shuyizhi-VirtualBox:/6381# /redis-3.2.8/bin/redis-server /6380/6380.conf
root@shuyizhi-VirtualBox:/6381# /redis-3.2.8/bin/redis-server /6381/6381.conf
查看是否启动成功
root@shuyizhi-VirtualBox:/6381# netstat -tnlp
1.2.8、设置主从
在Redis中设置主从有2种方式:
1.在redis.conf中设置slaveof a)
slaveof <masterip> <masterport>
2、 使用redis-cli客户端连接到redis服务,执行slaveof命令
a) slaveof <masterip> <masterport>第二种方式在重启后将失去主从复制关系。
我们这里使用第二种方式设置主从:
使用Redis客户端连接上6380端口# redis-cli -h 192.168.56.101 -p 6380
设置6380端口Redis为6379的从
192.168.56.101:6380> slaveof 192.168.56.101 6379
OK
使用Redis客户端连接上6381端口#
redis-cli -h 192.168.56.101 -p 6381
设置6381端口Redis为6379的从
192.168.56.101:6381> slaveof 192.168.56.101 6379
OK
1.2.9、查看Redis主从关系
使用redis客户端连接上6379端口
root@shuyizhi-VirtualBox:/6381# redis-cli -h 192.168.56.101 -p 6379
查看redis主从关系
192.168.56.101:6379> info replication
role:角色信息
slaveX:从库信息
connected_slaves:从库数量
2、测试
主Redis写入:
192.168.56.101:6379> set test test1
OK
从Redis读取:
192.168.56.101:6381> get test
"test1"
192.168.56.101:6388> get test
"test1"
3、Java代码实现
RedisUtils:
package com.example.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.JedisPool;
/**
* @Author: shuyizhi
* @Date: 2018/4/17 14:49
* @Description:
*/
public class RedisUtils {
private final static Logger logger = LoggerFactory.getLogger(RedisUtils.class);
private JedisPool masterJedisPool;
private JedisPool slaveJedisPool;
public void setMasterJedisPool(JedisPool masterJedisPool) {
this.masterJedisPool = masterJedisPool;
}
public void setSlaveJedisPool(JedisPool slaveJedisPool) {
this.slaveJedisPool = slaveJedisPool;
}
public String setString(final String key, final String value) {
String ret = masterJedisPool.getResource().set(key, value);
logger.info("key: " + key + ",value: " + value + ",ret: " + ret);
return ret;
}
public String getString(final String key) {
String ret = slaveJedisPool.getResource().get(key);
logger.info("key: " + key + ",value: " + ret);
return ret;
}
}
spring-datasource.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!--最大连接数-->
<property name="maxTotal" value="100"></property>
<!--最大空闲数-->
<property name="maxIdle" value="50"></property>
<!--最小空闲连接数-->
<property name="minIdle" value="20"></property>
<!--当池中连接耗尽,调用者最大阻塞时间,超出此时间将抛出异常。(单位:ms,默认:-1,永不超时)-->
<property name="maxWaitMillis" value="1000"></property>
<!-- 参考:http://biasedbit.com/redis-jedispool-configuration/ -->
<!--调用者获取连接时,是否检测当前连接有效性,无效则从连接池中移除,并尝试继续获取(默认为false)-->
<property name="testOnBorrow" value="true"></property>
<!--向连接池中归还连接时,是否检测连接有效性(默认为false)-->
<property name="testOnReturn" value="true"></property>
<!--调用者获取连接时,是否检测空闲有效,如果超时,则会被移除(默认为false)-->
<property name="testWhileIdle" value="true"></property>
<!--空闲连接检测线程一次运行多少条连接-->
<property name="numTestsPerEvictionRun" value="10"></property>
<!--空闲连接检测线程调用周期,如果为负值,表示不运行检测线程(单位:ms,默认为-1)-->
<property name="timeBetweenEvictionRunsMillis" value="60000"></property>
<!--连接获取方式,队列:false;栈:true-->
<!--<property name="lifo" value="false"></property>-->
</bean>
<bean id="masterJedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg index="0" ref="poolConfig"></constructor-arg>
<constructor-arg index="1" value="192.168.56.101" type="java.lang.String"></constructor-arg>
<constructor-arg index="2" value="6379" type="int"></constructor-arg>
</bean>
<bean id="slaveJedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg index="0" ref="poolConfig"></constructor-arg>
<constructor-arg index="1" value="192.168.56.101" type="java.lang.String"></constructor-arg>
<constructor-arg index="2" value="6380" type="int"></constructor-arg>
</bean>
<bean id="redisUtils" class="com.example.Utils.RedisUtils">
<property name="masterJedisPool" ref="masterJedisPool"></property>
<property name="slaveJedisPool" ref="slaveJedisPool"></property>
</bean>
</beans>
测试代码:
package com.example; import com.example.Utils.RedisUtils; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @Author: shuyizhi * @Date: 2018/4/17 15:22 * @Description: */ public class RedisUtilTest { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-datasource.xml"); System.out.println(ctx); RedisUtils utils = (RedisUtils) ctx.getBean("redisUtils"); utils.setString("springboot", "springbootredis"); System.out.println(utils.getString("springboot")); } }
结果查看
6381端口:
6380端口: