做网站建立数据库,有优惠券网站 怎么做代理,互联网兼职做网站维护,创建一个网站需要做哪些准备文章目录 第5章 Redis分布式缓存5.1 Redis持久化5.1.1 RDB持久化5.1.1.1 执行时机5.1.1.2 bgsave原理 5.1.2 AOF持久化5.1.2.1 AOF原理5.1.2.2 AOF配置5.1.2.3 AOF文件重写 5.1.3 RDB和AOF的对比 5.2 Redis主从5.2.1 搭建主从结构5.2.2 主从数据同步原理5.2.2.1 全量同步5.2.2.… 文章目录 第5章 Redis分布式缓存5.1 Redis持久化5.1.1 RDB持久化5.1.1.1 执行时机5.1.1.2 bgsave原理 5.1.2 AOF持久化5.1.2.1 AOF原理5.1.2.2 AOF配置5.1.2.3 AOF文件重写 5.1.3 RDB和AOF的对比 5.2 Redis主从5.2.1 搭建主从结构5.2.2 主从数据同步原理5.2.2.1 全量同步5.2.2.2 增量同步 5.2.3 小结 第5章 Redis分布式缓存
单机Redis存在四大问题
1数据丢失问题2并发能力问题3故障恢复问题4存储能力问题。
而Redis分布式缓存即基于Redis集群来解决单机Redis存在的问题
1数据丢失问题实现Redis数据持久化2并发能力问题搭建主从集群实现读写分离3故障恢复问题利用Redis哨兵实现健康监测和自动恢复4存储能力问题搭建分片集群利用插槽机制实现动态扩容。
5.1 Redis持久化
Redis有两种持久化方案
RDB持久化AOF持久化
5.1.1 RDB持久化
RDB全称Redis Database Backup fileRedis数据备份文件也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后从磁盘读取快照文件恢复数据。快照文件称为RDB文件默认是保存在当前运行目录。
5.1.1.1 执行时机
RDB持久化在四种情况下会执行执行save命令、执行bgsave命令、Redis停机时、触发RDB条件时。
1执行save命令
127.0.0.1:6379 save
OK执行save命令会立即执行一次RDB。该命令会使用主进程执行RDB从而阻塞其他所有命令。
Redis是单线程的所以执行save命令时整个服务会阻塞不能继对外提供请求数据量小的话肯定影响不大数据量大的时候就相当于停机很长一段时间。
2执行bgsave命令
127.0.0.1:6379 bgsave
Background saving started执行bgsave命令可以异步执行RDB会开启一个独立进程完成RDB主进程可以继续处理用户请求不受影响。
3Redis停机时
Redis停机时会执行一次save命令实现RDB持久化。
4触发RDB条件时
Redis内部有触发RDB的机制可以在redis.conf文件中找到格式如下
# 禁用RDB
save # 3600秒内至少1个Key被修改时执行RDB
# 300秒内至少100个Key被修改时执行RDB
# 60秒内至少10000个Key被修改时执行RDB
save 3600 1 300 100 60 10000# 是否压缩默认yes
# 建议改为no以避免消耗CPU但相应占用磁盘空间会增加
rdbcompression yes# RDB文件名称
dbfilename dump.rdb# 文件保存的路径目录默认是 ./
dir /var/lib/redis达到触发条件时Redis会自动执行bgsave命令进行异步RDB。 而执行RDB后可以在/var/lib/redis目录下看到RDB文件
ll
total 8
-rw-r--r--. 1 root root 88 Apr 10 11:38 dump.rdb
-rw-r--r--. 1 root root 677 Apr 10 11:38 redis.log5.1.1.2 bgsave原理
bgsave命令的原理是fork() Copy-On-Write。
fork()
fork()是Unix和Linux这种操作系统的一个api而不是Redis本身的api。其特点有
1fork()用于创建一个子进程注意是子进程不是子线程。 2fork()出来的子进程共享其父进行的内存数据但仅仅是共享创建完成那一时刻的内存数据后期主进程修改数据对子进程不可见子进程修改的数据对主进程也不可见。 3子进程挂了对主进程完全没影响它依然可以对外提供服务但是主进程挂了子进程也必须跟随一起挂。 4主进程和子进程共享内存空间但为什么它们之后对内存数据的修改操作对彼此不可见呢答案是采取了copy-on-write技术。
Copy-On-Write写时复制技术 如上图所示主进程fork()出子进程之后主进程中的所有内存页表的权限都会被设为read-only然后子进程的地址空间指向主进程这也就是实现了主进程内存空间的共享。
当主进程执行读操作时直接访问共享内存当主进程执行写操作时子进程只负责RDB不会有写操作CPU会检测到要操作的内存页表是read-only的于是触发页表异常中断page-fault进行一个中断例程。
在中断例程中CPU会把异常页表复制一份这里仅仅复制异常页表也就是要修改的那个数据页表而不是内存中的全部数据于是主、子进程各自持有独立的一份页表主进程继续修改自己的那一份子进程继续读取原来那份read-only的页表。
5.1.2 AOF持久化
5.1.2.1 AOF原理
AOF全称为Append Only File追加文件。Redis处理的每一个写命令都会记录在AOF文件可以看做是命令日志文件。
5.1.2.2 AOF配置
AOF默认是关闭的需要修改redis.conf配置文件来开启AOF
# 是否开启AOF功能默认是no
appendonly yes
# AOF文件的名称
appendfilename appendonly.aof# AOF记录的频率
# 表示每执行一次写命令立即记录到AOF文件
# appendfsync always
# 写命令执行完先放入AOF缓冲区然后每隔1秒将缓冲区数据写到AOF文件是默认方案
appendfsync everysec
# 写命令执行完先放入AOF缓冲区由操作系统决定何时将缓冲区内容写回磁盘
# appendfsync noAOF记录的频率三种策略的对比如下 AOF的作用如下例
127.0.0.1:6379 set test:name aaaa
OK此时/var/lib/redis目录下创建了AOF相关目录及文件
cd /var/lib/redis/
ls
appendonlydir dump.rdb redis.logcd appendonlydir/
ll
total 12
-rw-r--r--. 1 root root 88 Apr 10 13:11 appendonly.aof.1.base.rdb
-rw-r--r--. 1 root root 61 Apr 10 13:11 appendonly.aof.1.incr.aof
-rw-r--r--. 1 root root 88 Apr 10 13:11 appendonly.aof.manifestmore appendonly.aof.1.incr.aof
$3
set
$9
test:name
$4
aaaa5.1.2.3 AOF文件重写
AOF文件会记录每一个写命令即使是对同一个Key的多次写操作也会全部记录下来因此文件大小比RDB文件大得多。但是对同一个Key的多次写操作中只有最后一次写操作才是有意义的因此AOF将对同一个Key的全部写操作都记录下来的意义不大。
通过执行bgrewriteaof命令可以让AOF文件执行重写功能用最少的命令达到相同的效果。
Redis也会在触发阈值时自动重写AOF文件。阈值也可以在redis.conf中配置
# AOF文件比上次文件增长超过多少百分比则触发重写
auto-aof-rewrite-percentage 100
# AOF文件体积最小多大以上才触发重写
auto-aof-rewrite-min-size 64mb 5.1.3 RDB和AOF的对比
RDB和AOF各有自己的优缺点如果对数据安全性要求较高在实际开发中往往会结合两者来使用。 5.2 Redis主从
5.2.1 搭建主从结构
单节点Redis的并发能力是有上限的要进一步提高Redis的并发能力就需要搭建主从集群实现读写分离。 由上图可知我们准备搭建的结构包含三个节点一个主节点两个从节点。我们可以在同一台虚拟机中开启3个不同端口的Redis实例来模拟主从集群。
其搭建步骤如下
1在/usr/local/redis目录下创建3个目录名字分别是7001、7002、7003 2分别拷贝配置文件redis.conf到这3个目录下
cp /root/redis-7.2.4/redis.conf /usr/local/redis/7001
cp /root/redis-7.2.4/redis.conf /usr/local/redis/7002
cp /root/redis-7.2.4/redis.conf /usr/local/redis/70033修改3个目录下的配置文件以7001为例7002、7003类推
# 关闭AOF
appendonly no# 开启RDB
# save
save 3600 1 300 100 60 10000# 修改RDB文件保存路径
dir /var/local/redis/7001# 修改端口
port 7001要将7002、7003实例配置为从节点还需要在7002、7003的配置文件中增加两行配置
# 配置为从节点主节点的IP为192.168.146.128端口为7001
slaveof 192.168.146.128 7001
# 配置主节点的密码未设置密码时不需要
masterauth 1233214启动3个实例
/usr/local/bin/redis-server /usr/local/redis/7001/redis.conf
/usr/local/bin/redis-server /usr/local/redis/7002/redis.conf
/usr/local/bin/redis-server /usr/local/redis/7003/redis.conf5查询集群状态
redis-cli -p 7001 -a 123321至此Redis主从集群搭建完成。
另外对于开启主从关系有临时和永久两种模式
永久模式在redis.conf中添加一行配置slaveof masterip masterport即上面使用的模式。
临时模式使用redis-cli客户端连接到redis服务后执行slaveof masterip masterport命令这种模式在Redis重启后失效。
6主从集群测试
利用redis-cli连接7001
127.0.0.1:7001 set test:master 7001
OK
127.0.0.1:7001 get test:master
7001利用redis-cli连接7002
127.0.0.1:7002 set test:slave1 7002
(error) READONLY You cant write against a read only replica.
127.0.0.1:7002 get test:master
7001利用redis-cli连接7003
127.0.0.1:7003 set test:slave2 7003
(error) READONLY You cant write against a read only replica.
127.0.0.1:7003 get test:master
7001由测试结果可知只有在7001这个master节点上可以执行写操作和读操作7002和7003这两个slave节点只能执行读操作。
5.2.2 主从数据同步原理
5.2.2.1 全量同步
主从节点第一次建立连接时会执行全量同步将master节点的所有数据都拷贝被slave节点。 其流程如下 由上图所示全量同步主要有三个阶段 1第一阶段slave节点请求数据同步master节点判断是否是第一次同步如果是第一次同步则返回master节点的数据版本信息slave节点保存版本信息 2第二阶段master节点执行bgsave命令生成RDB文件并记录RDB期间的所有命令到repl_baklog中然后将RDB文件发送给slave节点slave节点收到后清空本地数据加载RDB文件 3第三阶段master节点继续发送到repl_baklog中保存的命令slave节点收到后执行这些命令。
这里有一个问题master如何得知salve是第一次请求数据呢
在解答之前先来了解两个概念 Replication Id简称replid是数据集的标记id一致则说明是同一数据集。每一个master都有唯一的replidslave则会继承master节点的replid。 offset偏移量随着记录在repl_baklog中的命令数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset如果slave的offset小于master的offset说明slave数据落后于master需要更新。
一个节点在变成slave之前也算一个master节点也有自己的replid。在与master建立连接时要发送自己的replid。如果master判断发现slave送过来的replid与自己的不一致说明这是一个全新的slave就知道要做全量同步了。
同步完成后master会将自己的replid和offset都发送给这个slaveslave保存这些信息以后slave的replid就与master一致了。
因此master判断一个节点是否是第一次同步的依据就是看replid是否一致。那么全量同步的流程可以进行如下优化 5.2.2.2 增量同步
全量同步需要先做RDB然后将RDB文件通过网络传输给slave成本是比较高的。因此除了第一次做全量同步其它大多数时候master与slave都是做增量同步。
增量同步就是只更新master与slave存在差异的部分数据其流程如下图 由上图所示增量同步主要有两个阶段 1第一阶段slave节点请求数据同步发送replid和offsetmaster节点收到后判断replid是否一致如果一致说明要进行增量同步回复continue 2第二阶段master节点去repl_baklog中获取offset后的命令并发送给slave节点slave节点收到后执行这些命令即完成了增量同步。
那master怎么知道slave与自己的数据差异在哪里呢很明显就是依靠repl_baklog文件该文件会记录Redis处理过的命令日志及offset包括master当前的offset和slave已经拷贝到的offset。
repl_baklog文件是一个固定大小的环形数组也就是说下标到达数组末尾后会再次从0开始读写这样数组头部的数据就会被覆盖。 如上图所示随着不断有数据写入master的offset逐渐变大slave也不断地拷贝追赶master的offset其中红色部分就是需要增量拷贝的数据直至整个数组被填满。
此时如果有新的数据写入就会覆盖数组中的旧数据。不过旧的数据只要是绿色的说明是已经被同步到slave的数据即便被覆盖了也没什么影响。
但是如果slave出现网络阻塞导致master的offset远远超过了slave的offset。如下图 如果master继续写入新数据其offset就会覆盖还未同步的旧的数据即图中棕色框中的红色部分——尚未同步但是却已经被覆盖的数据。
此时如果slave恢复需要同步却发现自己的offset都没有了已经无法完成增量同步就只能做全量同步。
5.2.3 小结
1简述全量同步和增量同步的区别
全量同步master将完整内存数据生成RDB发送RDB到slave。后续命令则记录在repl_baklog逐个发送给slave。增量同步slave提交自己的offset到mastermaster获取repl_baklog中从offset之后的命令给slave。
2什么时候执行全量同步
slave节点第一次连接master节点时。slave节点断开时间太久repl_baklog中的offset已经被覆盖时。
3什么时候执行增量同步
slave节点断开又恢复并且在repl_baklog中能找到offset时。
…
本节完更多内容请查阅分类专栏Redis从入门到精通
感兴趣的读者还可以查阅我的另外几个专栏
SpringBoot源码解读与原理分析(已完结)MyBatis3源码深度解析(已完结)再探Java为面试赋能(持续更新中…)