目录
这是关于redis缓存实战的博客,希望对大家有帮助,写的不好的,请多指教:
https://blog.csdn.net/weixin_44291453/article/details/107326253
1,redis是什么
1、redis的定义
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。
redis有五种类型的数据结构, 字符串(string)、散列(hash)、 列表(list)、 集合(set)、 有序集合(sorted set)。
2、讲到redis不得不讲nosql
NoSQL(f非关系性数据库)是不同于传统的关系数据库的数据库管理系统的统称。其两者最重要的区别是NoSQL不使用SQL作为查询语言。NoSQL数据存储可以不需要固定的表格模式。NoSQL是基于键值对的,可以想象成表中的主键和值的对应关系。
NoSQL:redis、memcached、mongodb、guava(loadingCache)
3、关系性数据库(mysql):设定了表结构,使用SQL对其进行增删改查
4、让我们看看,mysql,mencached,redis之间的比较
2、redis的内存管理机制
(1),redis使用现场申请内存的方式来存储数据,并且很少使用free-list等方式来优化内存分配,会在一定程度上产生内存碎片
解释:redis会查找空闲内存,存储进去,如果存储利用的内存比较少,就会剩余内存,下一个存储的数据比剩余的内存大,就会重新申请内存,导致上面的内存成为内存碎片
如图:
(2)Redis 定时、定期等多种缓存失效机制,减少内存泄漏,过期策略通常有以下三种:
定时删除:每个设置过期时间的key都需要创建一个定时器(timer),到过期时间就会立即清除。
该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。
惰性删除:只有当访问一个key时,才会判断该key是否已过期,过期则清除。
该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。
定期删除:每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。
该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。(expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。)我们知道通过expire来设置key 的过期时间。
* 例如Redis每秒处理:
(1). 测试随机的20个keys进行相关过期检测。
(2). 删除所有已经过期的keys。
(3). 如果有多于25%的keys过期,重复步奏1.
Redis服务器实际使用的是惰性删除和定期删除两种策略:通过配合使用这两种删除策略,服务器可以很好地在合理使用CPU时间和避免浪费内存空间之间取得平衡。
惰性删除策略是怎么实现?通过expireIfNeeded函数,当我们操作key的时候进行判断key是否过期
定期删除策略是怎么实现的?通过activeExpireCycle函数,serverCron函数执行时,activeExpireCycle函数就会被调用,规定的时间里面分多次遍历服务器的expires字典随机检查一部分key的过期时间,并删除其中的过期key
课外知识
memcached:默认使用Slab Allocation机制管理内存,其主要思想是按照预先规定的大小, 将分配的内存分割成特定长度的块 以存储相应长度的key-value数据记录,以完全解决内存碎片问题。
Memcached 在删除失效主键时也是采用的消极方法,即 Memcached 内部也不会监视主键是否失效,而是在通过 Get 访问主键时才会检查其是否已经失效
3、redis常被用于缓存
Redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。
4、redis作为缓存的使用,搭配数据库使用的两种方案
(1)jedis整合使用方案
(2)作为mybatis/hibernate二级缓存使用方案,一级缓存:sqlSession,进程缓存,单次链接有效
5,redis的五种数据类型
这里我给大家推荐一个网站,可以不用去安装redis,就可以去使用redis的各个命令。
网站:try.redis.io
如图:
6.string数据结构讲解与实战演练
简介:String是最常用的一种数据类型,普通的key/value存储都可以归为此类
1.当登陆时,适合用于对token的存储
(1)、set/get
设置key对应的值为String类型的value,获取key对应的值
> set name "魔笑"
OK
> get name
"魔笑"
(2)、mget
批量获取多个key的值,如果可以不存在则返回nil
> set name "魔笑"
OK
> set age 25
OK
> mget name age
1) "魔笑"
2) "25"
(3)、incr && incrby ( i++)
incr对key对应的值进行加加操作,并返回新的值;incrby加指定值
> get age
"25"
> incr age
(integer) 26
> incrby age 4
(integer) 30
> get age
"30"
(4)、decr && decrby(i--)
decr对key对应的值进行减减操作,并返回新的值;decrby减指定值
> get age
"30"
> decr age
(integer) 29
> decrby age 2
(integer) 27
> get age
"27"
(5)、setnx (set if not exist)
设置key对应的值为String类型的value
如果key已经存在,返回0,set失败。如果不存在,返回1,set成功
> setnx name "魔笑2"
(integer) 0
> setnx sex '男'
(integer) 1
(6)、setex (set expire 单位:秒 10秒,11秒的时候拿到null)
设置key对应的值为String类型的value,并设定有效期
> setex name1 10 "魔笑"
OK
> get name1
"魔笑"
> get name1
(nil)
(7)getrange 获取key对应value的子字符串
> set name3 "redisdemo"
OK
> getrange name3 0 3
"redi"
> getrange name3 0 8
"redisdemo"
(8)mset,批量设置多个key的值,如果成功表示所有值都被设置,否则返回0表示没有任何值被设置
(9)msetnx,同mset,不存在就设置,不会覆盖已有的key
(10)getset ,设置key的值,并返回key旧的值
(11)append ,给指定key的value追加字符串,并返回新字符串的长度
7、手把手进行Hash类型讲解
1、redis的Hash数据类型的key(hash表名称)对应的value实际的内部存储结构为一个HashMap
2、Hash特别适合存储对象。相对于把一个对象的每个属性存储为String类型,将整个对象存储在Hash类型中会占用更少内存。
3、运用场景:如用一个对象来存储用户信息,商品信息,订单信息等等。
(1)、 hset——设置key对应的HashMap中的field的value
(2)、 hget——获取key对应的HashMap中的field的value
> hset hashDemo name "魔笑"
(integer) 1
> hget hashDemo name
"魔笑"
(3)、 hgetall——获取key对应的HashMap中的所有field的value
> hset hashDemo name 魔笑
(integer) 1
> hset hashDemo age 25
(integer) 1
> hset hashDemo sex 男
(integer) 1
> hgetall hashDemo
1) "name"
2) "魔笑"
3) "age"
4) "25"
5) "sex"
6) "男"
(4)、hlen--返回key对应的HashMap中的field的数量
> hlen hashDemo
5
(5)、hmset,批量存储
> hmset hashDemo address "北京" work "java"
OK
(6),hmget 批量拿取
> hmget hashDemo name age sex address work
1) "魔笑"
2) "25"
3) "男"
4) "北京"
5) "java"
8、手把手进行List类型讲解
1,list是从两端压入或弹出元素
2,适合存储一些列表型的数据结构,类似文章的评论
3,从下面的命令就能看出来
(1),lpush——在key对应的list的头部添加一个元素
> lpush demolist "魔笑"
(integer) 1
> lpush demolist "魔笑2"
(integer) 2
#也可以一次 性存多个
> lpush demolist "魔笑3" "魔笑4"
(integer) 4
(2),lrange——获取key对应的list的指定下标范围的元素,-1表示获取所有元素
> lrange demolist 0 -1
1) "魔笑4"
2) "魔笑3"
3) "魔笑2"
4) "魔笑"
(3),lpop——从key对应的list的头部删除一个元素,并返回该元素
> lpop demolist
"魔笑4"
(4),rpush——在key对应的list的尾部添加一个元素
> rpush demolist 魔笑5
(integer) 4
> lrange demolist 0 -1
1) "魔笑3"
2) "魔笑2"
3) "魔笑"
4) "魔笑5"
(5),rpop——从key对应的list的尾部删除一个元素,并返回该元素
> rpop demolist
"魔笑5"
(6),llen 获取存储的长度
> llen demolist
(integer) 3
(7),lindex 指定下标获取元素
> lrange demolist 0 -1
1) "魔笑3"
2) "魔笑2"
3) "魔笑"
> lindex demolist 0
"魔笑3"
4、手把手进行Set类型讲解
1,set底层是HashMap,所以他是一个无序的集合,
2,可以交集,并集,差集的操作,可以用于两人的共同好友
(1),sadd——在key对应的set中添加一个元素,如下,当元素重复,所以添加不了
> sadd demoSet "魔笑1" "魔笑2" "魔笑3"
(integer) 3
> sadd demoSet "魔笑1"
(integer) 0
(2),smembers——获取key对应的set的所有元素
> smembers demoSet
1) "魔笑3"
2) "魔笑2"
3) "魔笑1"
(3),spop——随机返回并删除key对应的set中的一个元素
> spop demoSet
"魔笑2"
> spop demoSet
"魔笑2"
> smembers demoSet
1) "魔笑3"
2) "魔笑1"
(4),sunion——求给定key对应的set并集,
> smembers demoSet
1) "魔笑3"
2) "魔笑1"
> sadd demoSet1 "冬瓜1" "魔笑1" "冬瓜2"
(integer) 3
> smembers demoSet1
1) "冬瓜1"
2) "冬瓜2"
3) "魔笑1"
> sunion demoSet demoSet1
1) "魔笑3"
2) "冬瓜1"
3) "冬瓜2"
4) "魔笑1"
(5),sinter——求给定key对应的set交集
> sinter demoSet demoSet1
1) "魔笑1"
(6),sdiff——求差集
> sdiff demoSet1 demoSet
1) "冬瓜1"
2) "冬瓜2"
9、手把手进行SortSet类型讲解
1,sortset是怎么存储并实现排序的呢,在set的基础增加顺序score,再根据score进行排序,可以实现排行榜的功能
2,hashmap存储,还加了一层跳跃表
3,跳跃表:相当于双向链表,在其基础上添加前往比当前元素大的跳转链接
(1),zadd ——在key对应的zset中添加一个元素
> zadd demozset 2 "魔笑2"
(integer) 1
> zadd demozset 6 "魔笑6"
(integer) 1
> zadd demozset 4 "魔笑4"
(integer) 1
> zadd demozset 10 "魔笑10"
(integer) 1
(2),zrange——获取key对应的zset中指定范围的元素,-1表示获取所有元素
> zrange demozset 0 -1 withscores
1) "魔笑2"
2) 2.0
3) "魔笑4"
4) 4.0
5) "魔笑6"
6) 6.0
7) "魔笑10"
8) 10.0
(3),zrem——删除key对应的zset中的一个元素
> zrem demozset "魔笑6"
1
> zrange demozset 0 -1
1) "魔笑2"
2) "魔笑4"
3) "魔笑10"
(4),zrangebyscore——返回有序集key中,指定分数范围的元素列表,排行榜中运用
> zrangebyscore demozset 4 10
1) "魔笑4"
2) "魔笑10"
(5),zrank——返回key对应的SortSet中指定member的排名。其中member按score值递增(从小到大);
排名以0为底,也就是说,score值最小的成员排名为0,排行榜越高的,值越大,排行榜中运用
> zrange demozset 0 -1 withscores
1) "魔笑2"
2) 2.0
3) "魔笑4"
4) 4.0
5) "魔笑10"
6) 10.0
> zadd demozset 7 "魔笑7"
(integer) 1
> zadd demozset 6 "魔笑6"
(integer) 1
> zadd demozset 8 "魔笑8"
(integer) 1
"#从如下能看出来他们的是有序排列"
> zrange demozset 0 -1 withscores
1) "魔笑2"
2) 2.0
3) "魔笑4"
4) 4.0
5) "魔笑6"
6) 6.0
7) "魔笑7"
8) 7.0
9) "魔笑8"
10) 8.0
11) "魔笑10"
12) 10.0
"#排名最小"
> zrank demozset "魔笑2"
0
"#排名最大"
> zrank demozset "魔笑10"
5
> zrank demozset "魔笑6"
2
(6),zcard——有多少个元素
> zcard demozset
6
10,redis消息订阅发布
简介:发布订阅类似于信息管道,用来进行系统之间消息解耦,类似于mq,rabbitmq、rocketmq、kafka、activemq,主要有消息发布者和消息订阅者。
如图:
解释:publisher(发送者)将msg(信息)发送到channel(管道),subscriber(消息订阅者)就可以订阅这个channel,拿到msg,channel就可以
1、PUBLISH :将信息message发送到指定的频道channel。返回收到消息的客户端数量
2、SUBSCRIBE :订阅给指定频道的信息
(1).首先我发布订阅,结果是没有订阅者
(2).我在另一台,模拟订阅了 channel
(3),我再发送PUBLISH这个命令就可以看到,他的客户端数量是1,就是有一个订阅者订阅了该channel
3、UNSUBSCRIBE:取消订阅指定的频道,如果不指定,则取消订阅所有的频道。
11,redis事务机制
我们可以去先看一下,mysql的事务机制:https://blog.csdn.net/weixin_44291453/article/details/106821493
1,讲解redis事务基本命令
1、 MULTI 与 EXEC命令—— 以 MULTI 开始一个事务,然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令
> MULTI
OK
> set name "魔笑"
QUEUED
> get name
QUEUED
> EXEC
1) OK
2) "魔笑"
2、 DISCARD命令—— DISCARD 命令用于取消一个事务, 它清空客户端的整个事务队列, 然后将客户端从事务状态调整回非事务状态, 最后返回字符串 OK 给客户端, 说明事务已被取消。
> MULTI
OK
> set name "魔笑"
QUEUED
> get name
QUEUED
> DISCARD
OK
"在执行这个命令,报没有事务"
> EXEC
(error) ERR EXEC without MULTI
3、WATCH命令—— WATCH 命令用于在事务开始之前监视任意数量的键: 当调用 EXEC 命令执行事务时, 如果任意一个被监视的键已经被其他客户端修改了, 那么整个事务不再执行, 直接返回失败。
(1)如图:我们监听了name,开启了事务
(2)我们在另一个客户端修改了 该name
(3)我们继续执行EXEC该事务,如图报错
12,讲解redis事务ACID
这是有关mysql事务的讲解:https://blog.csdn.net/weixin_44291453/article/details/106821493
(1)、 原子性(Atomicity)
单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。如果一个事务队列中的所有命令都被成功地执行,那么称这个事务执行成功。
(2)、 一致性(Consistency)
入队错误
在命令入队的过程中,如果客户端向服务器发送了错误的命令,比如命令的参数数量不对,等等, 那么服务器将向客户端返回一个出错信息, 并且将客户端的事务状态设为 REDIS_DIRTY_EXEC 。
执行错误
如果命令在事务执行的过程中发生错误,比如说,对一个不同类型的 key 执行了错误的操作, 那么 Redis 只会将错误包含在事务的结果中, 这不会引起事务中断或整个失败,不会影响已执行事务命令的结果,也不会影响后面要执行的事务命令, 所以它对事务的一致性也没有影响。
(3)、隔离性(Isolation)
WATCH 命令用于在事务开始之前监视任意数量的键: 当调用 EXEC 命令执行事务时, 如果任意一个被监视的键已经被其他客户端修改了, 那么整个事务不再执行, 直接返回失败。
(4)、持久性(Durability)
因为事务不过是用队列包裹起了一组 Redis 命令,并没有提供任何额外的持久性功能,所以事务的持久性由 Redis 所使用的持久化模式决定
13,redis的持久化
redis持久化,就是将数据永久保存,有两种方式,一种是rdb,一种是AOF
rdb:属于全量数据备份,备份的是数据
RDB是Redis默认的持久化方式。按照一定的时间将内存的数据以快照的形式保存到硬盘中,对应产生的数据文件为dump.rdb。通过配置文件中的save参数来定义快照的周期。
优点:
(1)、只有一个文件 dump.rdb,方便持久化。
(2)、容灾性好,一个文件可以保存到安全的磁盘。
(3)、性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO 最大化。
使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis 的高性能
(4).相对于数据集大时,比 AOF 的启动效率更高。
缺点:
(1)、数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。
所以这种方式更适合数据要求不严谨的时候)
aof:append only if,增量持久化备份,备份的是指令
AOF持久性记录服务器接收的每个写入操作,将在服务器启动时再次播放,重建原始数据集。使用与Redis协议本身相同的格式以仅追加方式记录命令。当Redis太大时,Redis能够重写日志背景。
优点:
(1),数据更加安全
(2),当Redis AOF文件太大时,Redis能够在后台自动重写AOF
(3)AOF以易于理解和解析的格式一个接一个地包含所有操作的日志
缺点:
(1).AOF文件通常比同一数据集的等效RDB文件大
RDB 和 AOF ,我应该用哪一个?
一般来说,如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。如果你非常关心你的数据,但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。有很多用户都只使用 AOF 持久化, 但我们并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快
当两种方式同时开启时,数据恢复Redis会优先选择AOF恢复。
在线上我们到底该怎么做?
(1),RDB持久化与AOF持久化同步使用
(2),如果Redis中的数据并不是特别敏感或者可以通过其它方式重写生成数据,可以关闭持久化,如果丢失数据可以通过其它途径补回;
(3),自己制定策略定期检查Redis的情况,然后可以手动触发备份、重写数据;
(4),采用集群和主从同步
14.缓存的收益和成本
(1)、缓存带来的回报
高速读写:缓存加速读写速度
降低后端负载:后端服务器通过前端缓存降低负载: 业务端使用Redis降低后端MySQL负载等
2、缓存带来的代价
数据不一致:缓存层和数据层有时间窗口不一致,和更新策略有关
代码维护成本:原本只需要读写MySQL就能实现功能,但加入了缓存之后就要去维护缓存的数据,增加了代码复杂度。
11,堆内缓存和远程服务器缓存redis的选择
(1),堆内缓存可能带来内存溢出的风险影响用户进程,如ehCache、loadingCache
JVM的构成:堆、java虚拟机栈、方法区、本地方法栈、程序计数器
(2),堆内缓存一般性能更好,远程缓存需要套接字传输
(3),用户级别缓存尽量采用远程缓存
(4),大数据量尽量采用远程缓存,服务节点化原则
14,面试题之缓存雪崩
1,什么是缓存雪崩?你有什么解决方案来防止缓存雪崩?
如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。由于原有缓存失效,新缓存未到期间所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU 和内存造成巨大压力,严重的会造成数据库宕机
2、你有什么解决方案来防止缓存雪崩?
(1)、加锁排队 key: whiltList , value:1000w个uid 指定setNx whiltList “nullValue”
上面我已经说了,setnx命令怎么用了,这里再强调一下
setnx (set if not exist)
设置key对应的值为String类型的value
如果key已经存在返回0,set失败。如果不存在,返回1,set成功
mutex互斥锁解决,Redis的SETNX去set一个mutex key,
当操作返回成功时,说明缓存失效,再进行load db的操作并回设缓存;
否则,缓存还存在,就重试整个get缓存的方法
(2)、数据预热
缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,
先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!
可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存不同的key
(3)、双层缓存策略
C1为原始缓存,C2为拷贝缓存,C1失效时,可以访问C2,C1缓存失效时间设置为短期,C2设置为长期。
(4)、定时更新缓存策略
失效性要求不高的缓存,容器启动初始化加载,采用定时任务更新或移除缓存
(5)、设置不同的过期时间,让缓存失效的时间点尽量均匀
15,试题之缓存穿透
(1)、什么是缓存穿透?你有什么解决方案来防止缓存穿透?
缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,
在缓存中找不到对应key的value,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次
无用的查询)。这样请求就绕过缓存直接查数据库
(2)、你有什么解决方案来防止缓存穿透?
1、缓存空值
如果一个查询返回的数据为空(不管是数据不 存在,还是系统故障)我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。 通过这个直接设置的默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库
2、采用布隆过滤器BloomFilter 优势占用内存空间很小,bit存储。性能特别高。
将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个
bitmap 拦截掉,从而避免了对底层存储系统的查询压力
15, 分布锁
分布式锁是什么
1.分布式锁是控制分布式系统或不同系统之间共同访问共享资源的一种锁实现
2.如果不同的系统或同一个系统的不同主机之间共享了某个资源时,往往通过互斥来防止彼此干扰。
分布锁设计目的
可以保证在分布式部署的应用集群中,同一个方法在同一操作只能被一台机器上的一个线程执行。
如图:
设计要求
1.这把锁要是一把可重入锁(避免死锁)
2.这把锁有高可用的获取锁和释放锁功能
3.这把锁获取锁和释放锁的性能要好…
分布锁实现方案分析
获取锁的时候,使用 setnx(SETNX key val——当且仅当 key 不存在时)
set 一个 key 为 val 的字符串,返回 0,则 key 存在,则什么都不做。返回 1加锁,锁的 value 值为当前占有锁服务器内网IP编号拼接任务标识,在释放锁的时候进行判断。
并使用 expire 命令为锁添 加一个超时时间,超过该时间则自动释放锁。 返回1则成功获取锁。
还设置一个获取的超时时间, 若超过这个时间则放弃获取锁。setex(key,value,expire)过期以秒为单位
释放锁的时候,判断是不是该锁(即Value为当前服务器内网IP编号拼接任务标识),若是该锁,则执行 delete 进行锁释放
16,如何实现高性能
采用分离读写,实现高性能
mysql数据库:我们可以采用,主从库的方式实现分离读写,主库负责写功能,从库只负责读的功能
redis已经发现了这个读写分离场景特别普遍,自身集成了读写分离供用户使用。我们只需在redis的配置文件里面加上一条,【slaveof host port】语句。port是主服务器的port,那么该服务器,作为从服务器,只负责读的功能,主服务期负责写
如图:
17,Redis读写分离是怎么做数据同步的吗?
数据同步:进行复制中的,主从服务器双方的数据库将保存相同的数据
(1),redis2.8版本之前使用旧版复制功能SYNC
SYNC是一个非常耗费资源的操作
当再次连接后:主服务器需要执行BGSAVE命令来生成RDB文件,同对增量持久化进行备份(AOF),这个生成操作会耗费主服务器大量的的CPU、内存和磁盘读写资源,随后主服务器将RDB文件发送给从服务器,这个发送操作会耗费主从服务器大量的网络带宽和流量,并对主服务器响应命令,再将AOF发送给从服务器
请求的时间产生影响:接收到RDB文件的从服务器在载入文件的过程是阻塞的,无法处理命令请求
(2),redis2.8之后使用PSYNC
PSYNC命令具有完整重同步(full resynchronization)和部分重同步(partial resynchronization1)两种模式
第一种模式,处理初次复制
和redis2.8版本之前使用旧版复制功能SYNC一样
第二种模式,部分重同步
从服务期从主服务器断开后,住服务器会将断开后的命令放入缓冲区
从服务期连上住服务器后,将断开的写命令发送给从服务器
如图:
部分重同步功能由以下三个部分构成:
(1)主服务的复制偏移量(replication offset)和从服务器的复制偏移量(存储断开时的命令)
解释:当主从断开后,主服务器会继续接收命令,假如是100条,那么这100条命令就是偏移量,那么从服务器就会去接收这100条偏移量
(2)主服务器的复制积压缓冲区(replication backlog),默认大小为1M,当断开的时间过长,存储的命令大于1M那么就会去进行完整同步
(3)服务器的运行ID(run ID)用于存储服务器标识,服务器的运行ID(run ID),用于存储服务器标识,如从服务器断线重新连接,取到主服务器的运行ID与重接后的主服务器运行ID进行对比,从而判断是执行部分重同步还是执行完整重同步
如图:首先判断它是不是第一次执行复制,如果是那么就会去执行完整重同步,如果不是,那么从服务会再次判断,重新连接的主服务器,是不是断开前的主服务器,如果不是,就会执行完整重同步,恢复的数据大于1M那么也会进行完整重同步