Redis
2021-06-02 19:59:05 3 举报
AI智能生成
redis
作者其他创作
大纲/内容
Redis架构
主从架构
核心机制
redis replication的核心机制
(1) redis采用异步方式复制数据到slave节点,不过redis2.8开始,slave node 会周期性地确认自己每次复制的数据量<br>(2)一个master node是可以配置多个slave node的<br>(3)slave node也可以连接其他的slave node<br>(4)slave node做复制的时候,是不会block master node 的正常工作的<br>(5)slave node在做复制的时候,也不会block对自己的查询操作,它会有旧的数据集来提供服务;但是复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务了<br>(6)slave node主要用来进行横向扩容,做读写分离,扩容的slave node 可以提高读的吞吐量
主从架构的核心原理
当启动一个slave node 重新连接master node,那么master node仅仅会复制给slave部分缺少的数据;否则如果是slave node 第一次连接的master node,那么会出发一次full resynchronization<br>开始full resyncronization的时候,master会启动一个后台线程,开始生成一份RDB快照i文件,同还会将从客户端收到的所有写命令缓存到内存中。RDB文件生成完毕之后,master会将这个RDB发送给slave,slave会先写入本地磁盘,然后在从本地磁盘加载到内存中,然后master会将内存中缓存的写命令发送给slave,slave也会同步这些数据。<br>slave node 如果跟master node有网络故障,断开了连接,会自动重连接,master如果发现有多个alave node 都来重新连接,仅仅会启动一个rdb save操作,用一份数据服务所有alave node
主从复制的断点续传
从redis 2.8开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份<br>master node会在内存中常见能与i个backlog。master和slave都会保存一个replica offset还有一个master<br>id,offset就是保存在backlog中的,如果master和slave网络连接断掉了,slave会让master从上次的replica offset开始继续复制<br>但是如果没有找到对应的offset,那么就会执行一次resynchronization
无磁盘化复制
master在内存中直接创建rdb,然后发送给slave,不会要等更多slave重新连接过来<br>repl-diskless-sync<br>repl-diskless-sync-delay,等待一定时长再开始复制,因为要等更多slave重新连接起来
过期key处理
slave不会过期key,只会等待master过期key.如果master过期了一个key,或者通过LRU淘汰了一个key,那么会模拟一条del命令发送给slave<br><br>
redis 哨兵模式
主要功能
集群监控,负责监控redis master 和slave进程是否正常工作
消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报告通知给管理员
故障转移,如果master node挂掉了,会自动转移到slave node 上
配置中心,如果故障转移发生了,通知clent客户端新的master地址
分布式
1、故障转移时,判断一个master node 是宕机了,需要大部分的哨兵都同意才行,涉及刀片了分布式选举的问题
即使部分哨兵节点挂掉了,哨兵集群还是能正常工作的,因为如果一个作为高可用机制重要组成部分的故障转移系统本身是单机的,那就完蛋了
核心知识
1、哨兵至少需要三个实例,来保证自己的健壮性
2、哨兵 + redis 主从的部署架构,是不会保证数据零丢失的,只能保证redis集群的高可用性
3、对于哨兵 + redis主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测试和演练
数据丢失
异步复制导致的数据丢失
因为 master -> slave 的复制是异步的,所以可能有部分数据还没有复制到slave,master就宕机了,此时这些部分数据就丢失了
脑裂导致的数据丢失
脑裂,也就是说,某个master 所在机器突然脱离了正常的网络,跟其他slave机器不能连接,但是实际上master还运行着<br>此时哨兵可能会认为master宕机了,然后开启选举,将其他slave切换成master<br>这个时候,集群里就会有两个master,也就是所谓的脑裂<br>此时虽然某个slave被切换成了master,但是可能client还没来的及切换到新的master,还继续写向旧master的数据可能也丢失了,因此旧maseter再次恢复的时候,会被作为一个slave挂到新的master上去,自己的数据会清空,重新从新的master复制数据
解决异步复制和脑裂导致的数据丢失
min-slaves-to-write 1<br>min-slaves-max-lag 10<br>要求至少有1个slave,数据的复制和同步的延迟不能超过10秒<br>如果说一旦所有的slave,数据复制和同步的延迟都超过了10秒钟,那么这个时候,master就不会在接受任何请求了<br>上面两个配置可用减少异步复制和脑裂导致的数据丢失
(1)减少异步复制的数据丢失<br>有了min-slaves-max-lag这个配置,就可以确保说,一旦slave复制数据和ack延时太长,就认为可能master宕机后损失的数据太多了,那么久拒绝写请求,这样久可以吧master宕机时由于部分数据未同步到slave导致的数据丢失降低的可控范围内
(2)减少脑裂的数据丢失<br>如果master出现了脑裂,跟其他slave丢失连接,那么上面两个配置可以确保说,如果不能继续给指定数量的slave发送数据,而且slave超过10秒没有给自己ack消息,那么久直接拒绝客户端的写请求<br>这样脑裂后的旧master就不会接受client的新数据,也就避免了数据丢失
底层原理
sdown和odown
sdown是主观宕机,就一个哨兵如果自己觉得一个master宕机了,那么就是主观宕机<br>odown是客观宕机,如果quorum数量的哨兵都觉得一个master宕机了,那么就是客观宕机<br>sdown达成的条件很简单,如果一个哨兵ping一个master,超过了is-master-down-after-milliseconds指定的毫秒数之后,就主观认为master宕机<br>sdown到odown转换的条件很简单,如果一个哨兵在指定时间内,收到了quorum指定数量的其他哨兵也认为那个master是sdown了,那么久认为是odown了,客观认为master宕机
哨兵机制的自动那个发现机制
哨兵互相之间的发现,是通过redis的pub/sub系统实现的,每隔哨兵都会往___sentinel__:hello这个channel里发送一个消息,这时候所有其他哨兵都可以消费到这个消息,并感知到其他哨兵的存在,<br>每隔两秒钟,每隔哨兵都会往自己监控的某个master+slaves对应的__sentinel__:hello channel里发送一个消息,内容是自己的host、ip和runid还有对这个master的监控配置<br>每个哨兵也会去监听自己监控的每个master+slaves对应的__sentinel__:hello channel,然后去感知到同样在监听这个master+slaves的其他哨兵的存在<br>每个哨兵还会跟其他哨兵交换对master的监控配置,互相进行监控配置的同步
slave配置的自动纠正
哨兵会负责自动纠正slave的一些配置,比如slave如果要成为潜在的master候选人,哨兵会确保slave在复制现有master的数据;
salve -> master 选举算法
如果一个master被认为odown了,而且majority哨兵都允许了主备切换,那么某个哨兵就会执行主备切换操作,此时首先要选举一个slave来,会考虑slave的一些信息<br>(1)跟master 断开连接的时长<br>(2)slave优先级<br>(3)复制offset<br>(4)run id<br>如果一个slave跟master断开连接已经超过了down-after-milliseconds的10倍,外加master宕机的时长,那么slave就被认为不适合选举为master<br>(down-after-milliseconds * 10) + millisenconds_since_master_is_in_do_SDOWN_state<br>接下来就会slave进行排序<br>(1)按照slave优先级进行排序,slave priority越低,优先级越高<br>(2)如果slave priority相同,那么看replica offset,哪个slave复制的越多的数据,offset越靠后,优先级越高<br>(3)如果上面两个条件都相同,那么选择一个run id比较小的那个slave<br>
瓶颈
如果你的数据量很少,主要是承接高并发高性能的场景,比如你的缓存一般就是几个G,哪单机就足够了
replication 一个master、多个slave,要几个salve跟你的额要求的读吞吐量有关系,然后自己搭建一个sentinal集群,去保证中架构的高可用性,就可以了
redis cluster
介绍
cluster
自动将数据进行分片,每个master上放一部分数据<br><br>提供内置的高可用支持,部分master不可用时,还是可以继续工作的
cluster 端口
每个redis 要放开两个端口,比如一个是6379,另外一个就是加10000的端口号,比如16379<br>16379端口号是用来进行节点间通信的,也就是cluster bus的东西,集群总线,cluster bus的通信,用来进行检测,配置更新,故障转移授权<br>cluster bus 用了另外一种二进制的协议,主要用于节点间进行高效的数据交换,占用更少的网络带宽和处理时间
hash slot算法
redis cluster有固定的16384个hash slot,对每个key计算的CRC16值,然后对16384取模,可以获取key队形的hash solt<br>redis cluster中每个master 都会持有部分slot,比如有3个master ,那么可能每个master 持有5000多个hash slot<br>hash slot让node 的增加和移除很简单,增加一个master ,就将其他master 的hash slot移动部分过去,减少master ,就将它的hash slot移动到其他master 上去<br>移动hash slot 的成本是非常低的<br>客户端的api,可以对指定的数据,让他们走同一个hash slot,通过hash tag 来实现0
核心原理-节点内部通信
基础通信原理
节点间采取gossip协议进行通信
跟集中式不同,不是将集群元数据(节点信息、故障、等等)集中存储在某个节点上,而是互相之间不断通信,保持整个集群所有节点的数据是完整的维护集群的元数据用得 ,集中式,gossip
集中式:好处在于,元数据的更新和读取,时效性非常好,一旦元数据出现了变更,立即就更新到集中式的存储中,其他节点读取的时候立即就可以感知到;
不好在于,所有的元数据的更新压力全部集中在一个地方,可能会导致元数据的存储有压力
gossip:好处在于,元数据的更新比较分散,不是集中在一个地方,更新请求会陆陆续续,打到所有节点上去更新,有一定的延时,降低了压力;
缺点,元数据有延时,可能导致集群的一些操作会有一些滞后
我们刚才做reshard,去做另外一个操作,会发现说,configuration error,达成一致
10000端口
每个节点都有一个专门用于节点间通信的端口,就是自己提供服务的端口号+ 10000,比如7001,那么用于节点间通信的就是17001端口
每隔节点每隔一段时间都会往另外几个节点发送ping消息,同时其他几点接收到ping之后返回pong
交换的信息
故障信息,节点的增加和移除,hash slot信息,等等
gossip协议
gossip协议包换多种消息,包括ping,pong,meet,fail,等等
meet:某个节点发送meet给新加入的节点,让新节点加入集群中,然后新接待你就会开始与其他节点进行通信
redis-trib.rb add-node
其实内部就是发送一个gossip meet消息,给新加入的节点,通知那个节点去加入我们的集群
ping:每个节点都会频繁给其他节点发送ping,其中包含自己的状态还有自己维护的集群元数据,互相通过ping交换元数据
频繁的互相之间交换数据,互相进行元数据的更新
pong:返回ping和meet,包含自己的状态和其他信息,也可以用于信息广播和更新
接到ping就返回pong.
fail:某个节点判断另一个节点fail之后,就发送fail给其他节点,通知其他节点,指定的节点宕机了
ping消息深入
ping很频繁,而且要携弹一些元数据,所以能回加重网络负担
每个节点每秒会执行10次ping,每次会选择5个最久没有通信的其他节点
当然如果发现某个节点通信延时达到了cluster_node_timeout/2 ,那么立即发送ping,避免数据交换延时过长
比如说,两个节点之间都10分钟没有交换数据了,那么整个集群处于严重的原属久不一致的情况,就会有问题
所有cluster_node_timeout可以调节,如果调节比较大,那么会降低发送的频率
每次ping,一个是带上自己节点的信息,还有就是带上1/10其他节点的信息,发送出去,进行数据交换
至少包含3个其他节点的信息,最多包含总结点-2个其他节点的信息
redis 回收算法
介绍
redis是会在数据达到一定程度之后,超过了一个最大的限度之后,就会将数据进行一定的清理,从内存中清理掉一些数据<br>Redis默认情况下就是使用LRU策略的,因为内存是有限的<br>LRU:least Recently userd 最近最少使用算法<br>将最近一段时间内,最少使用的一些数据,给干掉,比如说有一个key,在最近1个小时内,只被访问了一次,还有一个key在最近1个小时内,被访问了1万次
缓存清理设置
maxmermory,设置redis用来存放数据的最大的内存大小,一旦超出这个内存大小之后,就会立即使用LRU算法清除掉部分数据<br>对于64bit的机器,如果maxmemory设置为0,那么就默认不限制内存的使用,直到耗尽机器中所有的内存位置<br>maxmemoiry-policy,可以设置内存达到最大闲置后,采取什么策略来处理
清理策略
可以通过maxmemory-policy key 来设置内存达到最大内存后,采取什么策略来处理<br><br>volatile-lru -> 根据LRU算法删除设置了超时属性(expire)的键,直到腾出足够空间为止。如果没有可删除的键对象,回退到noeviction策略。<br>allkeys-lru -> 根据LRU算法删除键,不管数据有没有设置超时属性,直到腾出足够空间为止。<br>volatile-lfu -> 根据LFU算法删除设置了超时属性(expire)的键,直到腾出足够空间为止。如果没有可删除的键对象,回退到noeviction策略。<br>allkeys-lfu -> 根据LFU算法删除键,不管数据有没有设置超时属性,直到腾出足够空间为止。<br>volatile-random -> 随机删除过期键,直到腾出足够空间为止。<br>allkeys-random -> 随机删除所有键,直到腾出足够空间为止。<br>volatile-ttl -> 根据键值对象的ttl属性,删除最近将要过期数据。如果没有,回退到noeviction策略。<br>noeviction -> 不会删除任何数据,拒绝所有写入操作并返 回客户端错误信息,此 时Redis只响应读操作。<br>
缓存设计
缓存更新
1、先删除redis中的缓存<br>2、更新mysql 的数据<br>3、查询的时候在增加redis的缓存
缓存穿透
描述
缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求。由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。
在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。
如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
解决
接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
缓存击穿
描述
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。
解决
1、设置热点数据永远不过期。
2、接口限流与熔断,降级。重要的接口一定要做好限流策略,防止用户恶意刷接口,同时要降级准备,当接口中的某些 服务 不可用时候,进行熔断,失败快速返回机制。
3、布隆过滤器。bloomfilter就类似于一个hash set,用于快速判某个元素是否存在于集合中,其典型的应用场景就是快速判断一个key是否存在于某容器,不存在就直接返回。布隆过滤器的关键就在于hash算法和容器大小
4、加互斥锁
雪崩击穿
1、redis集群彻底崩溃
2、缓存服务大量对redis的请求hang住,占用资源
3、缓存服务大量的请求打到源头服务去查询mysql,直接打死mysql
4、源头服务因为mysql被打死也崩溃,对源服务的请求也hang住,占用资源
5、缓存服务大量的资源全部耗费在访问redis和源服务无果,最后自己被拖死,无法提供服务
6、nginx无法访问缓存服务,redis和源服务,只能基于本地缓存提供服务,但是缓存过期后,没有数据提供
7、网站崩溃
描述
缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是, 缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案
1、缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
2、如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
3、设置热点数据永远不过期。
预防措施
事前
发生缓存雪崩之前,怎么去避免redis彻底挂掉<br>redis本身的高可用性,复制,主从架构,操作主节点,读写,数据同步到从节点,一旦主节点挂掉,从节点跟上<br>双机房部署,一套redis cluster,部分机器在一个机房,另一部分机器在另外一个机房<br>还有一种部署方式,两套redis cluster,两套redis cluster 之间做一个数据的同步,redis集群时可以搭建成树状的结构的<br>一旦说单个机房出了故障,至少说另外一个机房还能做些redis实例提供服务
事中
redis cluster已经彻底崩溃了,已经开始大量的访问无法访问到redis了
(1) ehcache本地缓存
所做的多级缓存架构的作用上了,ehcache的缓存,应对零散的redis中数据被清除掉的现象,另外一个主要是预防redis彻底崩溃
多台机器上部署的缓存服务实例的内存中,还有一套ehcache的缓存
ehcache的缓存还能支撑一阵
(2)对redis访问的资源隔离
(3)对源服务访问的限流以及资源隔离
事后
(1)redis数据可以恢复,做了备份,redis数据备份和恢复,redis重新启动起来
(2)redis数据彻底丢失了,或者数据过旧,快速缓存预热,redis重新启动起来
数据类型
String
数据结构:key-value
常用操作:set、get、decr、incr、mget回、msetnc加锁
应用场景:incr点赞计数器
hash
数据结构:Hashmap
常用操作:hget、hset、hgetall
<span style="font-size: inherit;">应用场景:</span><font color="#c41230" style="font-size: inherit;">数据对象存储</font><span style="font-size: inherit;">、session、短网址追踪、更新博客</span><br>
list
数据结构:双向链表,可重复有序集合
常用操作:lpush、rpush、lpop、rpop、lrange
应用场景:消息队列类型,阻塞式发送邮件、<font color="#c41230"><b>lrange:分页查询、数据id保存</b></font>
set
数据结构:value永远为null的Hashmap不可重复无序集合
常用操作:sadd、spop、snenbers、sunion
其它扩展判断某个成员是否在一个set集合内
应用场景:粉丝、关注、抽奖、投票、UV、多个关键词搜索商品
其他扩展-交集、并集、差集
Z-Set
数据结构:使用HashMap和跳跃表(Skiplis)来保证数据的存储和有序不可重复有序集合
常用操作:zadd、zrange、zrem、zcard
子主题
geo
数据结构:
常用操作:geoadd、georadiusByMember、geodist
应用场景:附近人、用户到商家的距离
sorted set
数据结构:zSet
常用操作:zadd、zincrby、zrevrangeWithScores、zrevrangeBySoreWithScores
应用场景:音乐排行榜、商品推荐
Redis持久化意义
1、是做灾难恢复、数据恢复,也可以归类到高可用的一个环节里面去,比如你redis整个挂了,然后redis就不可用了,你要做的事情是让redis 变得可用,或者尽快得可用
2、大量的请求过来,缓存全部无法命中,在redis里根本找不到护具,这个时候就死定了,缓存雪崩问题,所有请求,没有在redis 命中,就会去mysql数据库这种数据源头去找,一下子这么多请求,mysql可能也会挂了
3、redis持久化做好,备份和恢复方案做到企业及的程度、那么即使你的redis故障了,也可以通过备份数据,快速恢复,一旦恢复立即对外提供服务
Redis持久化RDB
优点
1、RDB会经过一段时间复制一份数据快照,这种数据快照非常适合做冷备,能够快速将完整文件发送到一些远程的redis中
2、RDB时 redis依然对外提供读写服务,性能影响非常小,可以让redis保持高性能,redis主进程只是fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可
3、相对于AOF持久化机制来说,redis通过RDB文件恢复的更快,在redis重启时能更快恢复redis可用
缺点
1、redis发生故障的时候,RDB可能会丢失数据,因为RDB是每隔5分钟备份一次快照,或者更长时间,那么这期间的数据就会丢失
2、RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别的大,可能会导致客户端提供的服务暂停数毫秒,或者数秒
配置
redis.conf文件,也就是//usr/local/redis-6.2.1/conf/redis.conf,去配置持久化<br>save 60 1000<br>每间隔60s,如果有超过1000key发生了变更,那么就生成一个新的dump.rdb文件,就是当前redis内存中完整的数据快照,这个操作也可以手动调用save或者bgsave命令,同步或者异步执行RDB快照生成<br>save可以设置多个,就是多个snapshotting检查点,每到一个检查点,就会去check一下,是否有指定的key数量发生了变更,如果有,就生成一个新的dump.rdb文件
工作流程
(1)redis根据配置自己尝试去生成rdb快照文件<br>(2)fork一个子进程出来<br>(3)子进程尝试去将数据dump到rdb快照文件中<br>(4)完成rdb快照文件的生成之后,就替换之前的旧的快照文件<br>dump.rdb 每次生成一个新的快照,都会覆盖之前老的快照
模拟实验
(1)在redis中保存几条数据,立即停掉redis进程,然后重启redis,看看刚才插入的数据还在不在<br>数据还在,为什么?
此处出现一个知识点,通过redis-cli SHUTDOWN这种方式去停掉redis,其实是一种安全退出的模式,redis在退出的时候会将内存中的数据立即生成一份完整的rdb快照
2、在redis中在保存几条新的数据,用kill -9 粗暴杀死redis进程,模拟redis故障异常退出,导致内存数据丢失的场景<br> 数据不存在了.最新数据没保存到<br>(2)手动奢姿一个sava检查点,sava5 1<br>这次就发现 redis进程异常被杀掉,数据没有进dump文件,几条最新的数据就丢失<br>(3)写入几条数据,等待5秒钟<br>(4)停掉redis进程,在重新启动redis,看刚才插入的数据还在不在<br>存在了<br>
Redis持久化AOF
优点
1、AOF可以更好的保护数据不丢失,一般AOF会每隔1秒通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据
2、AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破碎,也很容易修复
3、AOF文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写,因为在rewrite log的时候,会对其中的指令进行压缩,创建出一份需要恢复数据的最小日志出来,在创建新的日志的同时,老的日志文件还是照常写入,当新的merge后的日志文件ready的时候,在交换新老日志文件即可
4、AOF日志文件的命令通常可读,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall 命令清空了所有数据,只要这个时候后台rewiter还没有发生,那么就可以离职拷贝AOF文件,把最后一条fulshall 命令删除掉。
缺点
1、对于同一份数据来说,AOF的文件要比RDB数据快照更大
2、AOF开启后,支持的QPS会比RDB支持写QPS低,因为AOF一般会配置成每秒fsync一次日志文件,每秒一次fsync性能还是很高的
3、通过AOF记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来,所以说,类似AOF这种较为复杂的基于命令日志/merge/回放的方式,比基于RDB每次持久化一份完整的数据快照文件的方式,更加脆弱一些,容易有bug。不过AOF就是避免rewrite过程导致的bug,因此每次rewrite并不是基于旧的指令日志进行merge的,而是基于当时内存中的数据进行指令的重新构建,这样健壮性会好很多
4、唯一的比较大的缺点,其实就是做数据恢复的时候,会比较慢,还要做冷备,定期的备份,不太方便,可能要自己手写复杂的脚本去做,做冷备不太合适
配置
1、AOF持久化,默认是关闭的,默认是打开RDB持久化,appendonly yes,可以打开AOF持久化机制,在生产环境里面,一般来说AOF都是要打开的,除非你说随便丢个几分钟的数据也无所谓,打开AOF持久化机制之后,redis每次接收到一条写命令,就会写入日志文件中,当然是先写os cahce的,然后每隔一定时间在fsycn一下
2、而且即使AOF和RDB都开启了,redis重启的时候,也是优先通过AOF进行数据恢复的,因为AOF数据比较完整
3、可以配置AOF的fsync策略,有三种策略可以选择,一种是每次写入一条数据执行一次fsync,一种是每隔一秒执行和一次fsync,一种是不主动执行fsync
always:每次写入一条数据,立即将这个数据对应的写日志fsync到磁盘上去,性能非常差,吞吐量很低,确保将redis里的数据一条都不丢,那就只能这样了
mysql -> 内存策略,大量磁盘,QPS到多少,一两K,QPS,每秒钟的请求数量<br>redis -> 内存,磁盘持久化,QPS到多少,单机,一般来说,上万QOS没问题
everysec 每秒将 os cache中数量fsync到磁盘,这个最常用的,生成环境一般都这么配置,性能很高,QPS还是可以上万的
no:仅仅redis负责将数据写入os cache 就撒手不管了,然后后面os 自己会时不时有自己的策略将数据刷入磁盘,不可控了
模拟实验
1、开启appendonly yes,kill -9 杀掉redis进程,重新启动redis 进场,发现数据被恢复回来了,就是AOF文件中恢复回来的<br>redis进程启动的时候,直接会从appendonly.aof 中加载所有的日志,把内存中数据恢复回来
2、redis进程启动的时候,直接就会从appendonly.aof中加载所有的日志,把内存中的数据恢复回来<br>redis中的数据其实有限的,很多数据可能会自动过期,可能会被用户删除,可能会被redis用缓存的算法清理掉
3、redis中的数据会不断淘汰掉旧的数据,只有常用的数据会被保留在redis 内存中,其他的数据会被redis用缓存清除算法清除掉
AOF rewrite
redis中的数据其实是有限的,很多数据可能会自动过期,可能会被用户删除,可能会被redis用缓存清除的算法清理掉<br>redis中数据会不断淘汰掉旧的数据,只有一部分常用数据会自动保存在redis内存中<br>所以可能很多之前的已经被清理掉的数据,对应的写日志还停留在AOF中,AOF日志文件就一个,会不断的膨胀到很大很大 <br>所以AOF会自动在后台每隔一定时间做rewrite操作,比如日志里已经存放了针对100w数据的写日志了;redis内存只剩下10万;基于内存中当前的10万数据构建一套最新的日志到aof中,覆盖之前的老日志;确保AOF日志文件不会太大
在redis.conf中,可以配置rewrite策略<br>auto-aof-rewrite-percentage 100<br>auto-aof-rewrite-min-size 64mb<br>比如说上一次AOF rewrite之后,是128mb<br>然后就会接着128mb继续写AOF的日志,比如发现增长的比例,超过了之前的100%(percentage 100 代表比原来大100%),256mb,就可能回去出发一次rewrite<br>但是此时还是要去跟min-size,64mb去比较,256mb > 64mb,(需要当前文件大小大于min-size)才会去触发rewrite<br>
工作流程
1、redis fork一个子进程<br>2、子进程基于当前内存中的数据,构建日志,开始往一个新的临时的AOF文件中写日志<br>3、redis主流程,接收到client新的写操作之后,在内存中写入日志,同时新的日志也继续写入旧的AOF文件<br>4、子进程写完新的日志文件之后,redis主进程将内存中的新日志再此追加到新的AOF文件中<br>5、 用新的日志文件替换掉旧的日志文件
RDB VS AOF
区别
1、RDB也可以做冷备,生成多个文件,每个文件都代表了某一个时刻的完整的数据快照<br>2、AOF也可以坐冷备,只有一文件,但是可以,每隔一定的时间,会copy一份这个文件出来
2、RDB,每次写,都是直接写redis内存,只是在一定的时候 ,才会将数据写入磁盘中<br>AOF,每次都是要写文件的,虽然可以快速些人 os cache中,但是还是有一定的时间开销的,速度肯定比RDB略慢一些
3、AOF,存放的指令日志,做数据恢复的时候,其实是要回放和执行所有的指令日志,未恢复出来内存中的所有数据的<br>RDB,就是一份数据文件,恢复的时候,直接拉取到内存中既可
同时工作
1、不要仅仅使用RDB,因为那样会导致你丢失很多数据
2、也不要仅仅使用AOF,因为那样会有两个问题,第一通过AOF做冷备,没有RDB做冷备,来的恢复速度快<br>第二、RDB每次简单粗暴生成数据快照,更加健壮,可以避免AOF这种复杂的备份和恢复机制的bug
3、综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择,用RDB来做不同的成都的冷备,在AOF文件都丢失或损坏的不可用的时候,还可用RDB来进行快速的数据恢复
0 条评论
下一页