Redis主从模式

1、概念

主从复制,主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主。数据的复制是单向的,只能由主服务器到从服务器。

通过主从复制,我们就可以随机的从服务器上读数据,从而大大降低了主服务器的压力,提高系统的性能,当主服务器正常关闭的时候,从服务器也可以待机,要是主服务器非正常关闭的话,也可以切换为其中的一台从服务器代替原来的主服务器,(作为灾备)以保证系统继续正常稳定运行,所以也有利于系统运行的安全性。

2、原理

1)主从复制理论

① 若启动一个Slave机器进程,则它会向Master机器发送一个sync_command命令,请求同步连接

② 无论是第一次连接还是重新连接,Master机器都会启动一个后台进程,将数据快照(RDB)保存到
数据文件中(执行rdb操作),同时Master还会记录修改数据的所有命令并缓存在数据文件中。

③ 后台进程完成缓存操作之后,Master机器就会向Slave机器发送数据文件,Slave端机器将数据
文件保存到硬盘上,然后将其加载到内存中,接着Master机器就会将修改数据的所有操作一并发送给Slave端机器。若Slave出现故障导致宕机,则恢复正常后会自动重新连接。

④ Master机器收到slave端机器的连接后,将其完整的数据文件发送给Slave端机几器,如果Mater同时收到多个slave发来的
同步请求则Master会在后台启动一个进程以保存数据文件,然后将其发送给所有的Slave端机器,确保所有的Slave端机器都正常。

1)主从复制大致流程

1、从-》主发送sync同步数据请求
2、主redis 会fork 一个子进程,然后产生RDB文件(完全备份)的过程
2.1客户端还在持续的写入Redis
3、RDB文件持久化完成后,主redis会将RDB文件和缓存起来的命令推送给从服务器
4、复制、推送完成后,主redis会持续的同步操作命令->利用AOF(增备的部分)持久化功能
5、在下一台从REDIS接入主从复制集群之前,会持续利用aof的方式同步数据给从redi

3、搭建Redis主从复制

( 1)安装Redis
三台服务器都需要安装
#按需求关闭安全策略
systemctl stop firewalld
systemctl disable firewalld
setenforce o
yum -y install gcc gcc-c++ make
cd / opt
wget -p /opt http://download.redis.io/releases/redis-5.0.9.tar.gz
tar -zxvf redis-5.0 .9.tar.gz
cd redis-5.0 .9
make && make PREFIX=/usr/ local/ redis install
#Redis源码包中直接提供了makefile文件直接执行make与make install命令进行安装
cd / opt / redis-5.o.9/utils/
./install server.sh
#回车,直到出现以下选项,手动修改为"/usr/local/redis/bin/redis-server"Please select the redis executable path [/usr/local/bin/redis-serverI
/usr/ local/ redis/bin/ redis-server
ln -s /usr/ local/redis/bin/*/usr/ local/bin/
#检查服务状态
Netstat -natp l grep “redis”

(2)修改Redis配置文件
①Master节点
vim /etc/ redis/ 6379.conf
bind 127.0.0.0.1 192.168.10.20
#70行,修改监听地址为

在这里插入图片描述
daemonize yes
#137行,开启守护进程
logfile /var/ 1oglredis_6379.1og
#172行,指定日志文件目录
dir /var/ lib/ redis/ 6379
#264行,指定工作目录
appendonly yes
#700行,开启AOF持久化功能

在这里插入图片描述 
/etc/ init.d/ redis_6379 restart
#重启服务使配置生效

在这里插入图片描述

(3)验证主从效果
主节点输入
tail -f /var/ log / redis_6379.log

在这里插入图片描述
redis-cli info replication

 在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

#Replication
role:master
connected_slaves : 2
slave0:ip=192.168.10.31,port=6379,state=online,offset=42,lag=1
slave1:ip=192.168.10.21,port=6379,state=online,offset=42,lag=1
#master启动时生成的40位16进制的随机字符串,用来标识master节点
master_replid:e920ac8821584bd21f9edbff2eeef48eabd3499c
#切换主从的时候master节点标识会有更改
master_replid2:0000000000000000000000000000000000000000
#复制流中的一个偏移量,master处理完写入命令后,会把命令的字节长度做累加记录,统计在该字段。该字段也是实现部分复制的关键字段。
master_repl_offset:42
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:42
#无论主从,都表示自己上次主实例repid1和复制偏移量;用于兄弟实例或级联复制,主库故障切换bsvlcvs

在这里插入图片描述

在这里插入图片描述

 4、客户端配置实现读写分离

SpringBoot 操作Redis主从复制

1. 主从复制配置 application.yml

2. 主要代码

  • RedisTempla

  • /**
     * 自定义相关的主从 template
     *
     * @author xgk
     */
    @Configuration
    @EnableConfigurationProperties({RedisMasterSlavesProperties.class})
    public class RedisConfig {
    
        /**
         * Master主机 template
         *
         * @param properties 配置
         */
        @Bean("redisMasterTemplate")
        public RedisTemplate<String, Object> redisMasterTemplate(RedisMasterSlavesProperties properties) {
            RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
            // master
            RedisMaster master = properties.getRedisMaster();
            // 连接工厂
            RedisConnectionFactory factory = connectionFactory(master.getHost(), master.getPort(), master.getPassword());
            redisTemplate.setConnectionFactory(factory);
            // 序列化
            return serializerTemplate(redisTemplate);
        }
    
        /**
         * Slaves从机 template
         *
         * @param properties
         * @return
         */
        @Bean("redisSlaveTemplateList")
        public List<RedisTemplate<String, Object>> redisSlaveTemplateList(RedisMasterSlavesProperties properties) {
            List<RedisTemplate<String, Object>> redisTemplates = new ArrayList<>();
            for (RedisSlave slave : properties.getRedisSlaves()) {
                RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
                // 连接工厂
                RedisConnectionFactory factory = connectionFactory(slave.getHost(), slave.getPort(), slave.getPassword());
                redisTemplate.setConnectionFactory(factory);
                // 序列化并放置集合
                redisTemplates.add(serializerTemplate(redisTemplate));
            }
            return redisTemplates;
        }
        ...
    }
  • RedisUtils

  • /**
     * 主机Master 只进行写操作, 从机Slave 只进行读操作
     *
     * @author xgk
     */
    @Component
    public class RedisUtils {
        // 主机
        @Autowired
        @Qualifier("redisMasterTemplate")
        public RedisTemplate<String, Object> redisMasterTemplate;
        // 从机
        @Autowired
        @Qualifier("redisSlaveTemplateList")
        public List<RedisTemplate<String, Object>> redisSlaveTemplateList;
    
        private int slaveIndex = 0;
    
        // 选择用那台从机(通过取余方式决定)
        private int buildSlaveIndex() {
            this.slaveIndex++;
            return this.slaveIndex % 2;
        }
    
        // 定义的写操作方法 ------------------------------------------
        public boolean set(String key, Object value) {
            try {
                redisMasterTemplate.opsForValue().set(key, value);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
        // 定义的读操作方法 ------------------------------------------
        public Object get(String key) {
            return key == null ? null : redisSlaveTemplateList.get(buildSlaveIndex()).opsForValue().get(key);
        }
        
        ...
    }
    

      5、主从复制的缺点

  • 主节点故障,集群则无法进行工作,可用性比较低,从节点升主节点需要人工手动干预。

    因为只有主节点能进行写操作,一旦主节点宕机,整个服务就无法使用。当然此时从节点仍可以进行读操作,但是对于整个服务流程来说,是无法使用的。

    Master的写的压力难以降低。

    如果写操作比较多,那么只有一个主节点的话,无法分担压力。

    主节点存储能力受到单击限制。

    主节点只能有一个,因此单节点内存大小不会太大,因此存储数据量受限。

    主从数据同步,可能产生部分的性能影响甚至同步风暴。

    风暴问题,对于任何集群分布式来说都存在,要合理分布节点。

  • 注意点:

  • 1)主从数据同步的延迟问题?

  • 2)如何保证读写的数据一致性?

问:为什么会出现不一致?

1.延迟

答:主从同步有时延,这个时延期间读从库,可能读到不一致的数据。

 

如上图:

(1)服务发起了一个写请求

(2)服务又发起了一个读请求,此时同步未完成,读到一个不一致的脏数据

(3)数据库主从同步最后才完成

画外音:任何数据冗余,必将引发一致性问题。

2.宕机

我们知道Redis Setnx(SET if Not eXists) 命令在指定的 key 不存在时,为 key 设置指定的值。特点是先加锁成功后,后续的加锁命令会失败,一般用来做分布式锁,但是在系统宕机时,会存在问题。

以Redission分布式锁为例,就是如果你对某个redis master实例,写入了myLock这种锁key的value,此时会异步复制给对应的master slave实例。

假设客户端1对master写了一条锁数据,正往slave实例同步,尚未完成,但是这个过程中一旦发生redis master宕机,主备切换,redis slave变为了redis master。

接着就会导致,客户端2来尝试加锁的时候,在新的redis master上完成了加锁,而客户端1也以为自己成功加了锁。此时就会导致多个客户端对一个分布式锁完成了加锁。这时系统在业务上一定会出现问题,导致脏数据的产生。所以这个就是redis cluster,或者是redis master-slave架构的主从异步复制导致的redis分布式锁的最大缺陷:在redis master实例宕机的时候,可能导致多个客户端同时完成加锁。

如何解决:

参考:

redis面试:由于主从延迟导致读取到过期数据怎么处理_OceanStar的学习笔记的博客-CSDN博客_redis主从延迟

(2条消息) redis 主从库如何实现数据一致?_wzp、、、的博客-CSDN博客_redis 主从数据一致性实现
 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Angus sonder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值