9 redis杂谈

  1. redis单线程原理:
    9 redis杂谈_第1张图片

  2. redis持久化的意义,在于故障恢复.
    比如你部署了一个redis,作为cache缓存,当然也可以保存一些较为重要的数据。如果没有持久化的话,redis遇到灾难性故障的时候,就会丢失所有的数据
    如果将数据持久化在磁盘上,然后定期比如说同步和备份到一些云存储服务上去,那么就可以保证数据不丢失全部,还是可以恢复一部分数据回来的.

    1. RDB和AOF两种持久化机制的工作原理:
      对于一个企业级的redis架构来说,持久化是不可减少的.
      企业级redis集群架构支撑:海量数据、高并发、高可用.
      (1) RDB和AOF两种持久化机制的介绍:
      RDB持久化机制,对redis中的数据执行周期性的持久化
      AOF机制对每条写入命令作为日志,以append-only的模式写入一个日志文件中,在redis重启的时候,可以通过回放AOF日志中的写入指令来重新构建整个数据集
      注意: 如果我们想要redis仅仅作为纯内存的缓存来用,那么可以禁止RDB和AOF所有的持久化机制
      通过RDB或AOF,都可以将redis内存中的数据给持久化到磁盘上面来,然后可以将这些数据备份到别的地方去,比如说阿里云,云服务
      如果redis挂了,服务器上的内存和磁盘上的数据都丢了,可以从云服务上拷贝回来之前的数据,放到指定的目录中,然后重新启动redis,redis就会自动根据持久化数据文件中的数据,去恢复内存中的数据,继续对外提供服务
      如果同时使用RDB和AOF两种持久化机制,那么在redis重启的时候,会使用AOF来重新构建数据,因为AOF中的数据更加完整.
      (2)RDB持久化机制的优点:
      ①RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,这种多个数据文件的方式,非常适合做冷备,可以将这种完整的数据文件发送到一些远程的安全存储上去
      ②RDB对redis对外提供的读写服务,影响非常小,可以让redis保持高性能,因为redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可
      ③相对于AOF持久化机制来说,直接基于RDB数据文件来重启和恢复redis进程,更加快速
      (3)RDB持久化机制的缺点:
      ①如果想要在redis故障时,尽可能少的丢失数据,那么RDB没有AOF好。一般来说,RDB数据快照文件,都是每隔5分钟,或者更长时间生成一次,这个时候就得接受一旦redis进程宕机,那么会丢失最近5分钟的数据
      ②RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒.
      (4)AOF持久化机制的优点:
      ①AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据
      ②AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复
      ③AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。因为在rewrite log的时候,会对其中的指导进行压缩,创建出一份需要恢复数据的最小日志出来。再创建新日志文件的时候,老的日志文件还是照常写入。当新的merge后的日志文件ready的时候,再交换新老日志文件即可。
      ④AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据
      (5)AOF持久化机制的缺点:
      ①对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大
      ②AOF开启后,支持的写QPS会比RDB支持的写QPS低,因为AOF一般会配置成每秒fsync一次日志文件,当然,每秒一次fsync,性能也还是很高的
      ③以前AOF发生过bug,就是通过AOF记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来。所以说,类似AOF这种较为复杂的基于命令日志/merge/回放的方式,比基于RDB每次持久化一份完整的数据快照文件的方式,更加脆弱一些,容易有bug。不过AOF就是为了避免rewrite过程导致的bug,因此每次rewrite并不是基于旧的指令日志进行merge的,而是基于当时内存中的数据进行指令的重新构建,这样健壮性会好很多。
      (6)RDB和AOF到底该如何选择?
      ①不要仅仅使用RDB,因为那样会导致你丢失很多数据
      ②也不要仅仅使用AOF,因为那样有两个问题,第一,你通过AOF做冷备,没有RDB做冷备,来的恢复速度更快; 第二,RDB每次简单粗暴生成数据快照,更加健壮,可以避免AOF这种复杂的备份和恢复机制的bug
      ③综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择; 用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复.
  3. 9 redis杂谈_第2张图片

  4. RDB配置:
    (1) 在redis.conf配置文件中配置如下:
    save 60 1000
    每隔60s,如果有超过1000个key发生了变更,那么就生成一个新的dump.rdb文件,就是当前redis内存中完整的数据快照,这个操作也被称之为snapshotting,快照.
    也可以手动调用save或者bgsave命令,同步或异步执行rdb快照生成
    save可以设置多个,就是多个snapshotting检查点,每到一个检查点,就会去check一下,是否有指定的key数量发生了变更,如果有,就生成一个新的dump.rdb文件

3.1 RDB持久化机制的工作流程:
(1)redis根据配置自己尝试去生成rdb快照文件
(2)fork一个子进程出来
(3)子进程尝试将数据dump到临时的rdb快照文件中
(4)完成rdb快照文件的生成之后,就替换之前的旧的快照文件
dump.rdb,每次生成一个新的快照,都会覆盖之前的老快照(如果没有对旧的快照进行覆盖的话,那么则会出现大量的重复快照文件,占用不必要的磁盘空间)

4 AOF的配置及使用详解(AOF的日志文件就一个):
(1)AOF持久化,默认是关闭的,默认打开RDB持久化
(2)appendonly yes,可以打开AOF持久化机制,在生产环境里面,一般来说AOF都是要打开的,除非你说随便丢个几分钟的数据也无所谓
(3)打开AOF持久化机制之后,redis每次接收到一条写命令,就会写入日志文件中,当然是先写入os cache的,然后每隔一定时间再fsync一下
(4)即使AOF和RDB都开启了,redis重启的时候,也是优先通过AOF进行数据恢复的,因为aof数据比较完整
(5)AOF的fsync持久化策略(只有fsync到磁盘中了,才是安全的):
(always)每次写入一条数据就执行一次fsync(每次写入一条数据,立即将这个数据对应的写日志fsync到磁盘上去,性能非常非常差,吞吐量很低; 确保说redis里的数据一条都不丢);
一种是每隔一秒执行一次fsync(常用生产环境配置);
一种是不主动执行fsync(仅仅redis负责将数据写入os cache就撒手不管了,然后后面os自己会时不时有自己的策略将数据刷入磁盘,不可控了);
4.1 redis的rewrite操作: redis中的数据很多都会自动过期,以及用户会自己删除.很多数据不存在但是数据的写操作可能还记录在aof中,所以为了防止aof文件的不断膨胀,也为了清理redis中冗余的内存空间,需要对aof文件进行rewrite操作.
4.2 redis aof rewrite : redis2.4版本之后,后台定时自动去进行rewrite操作,比如日志里已经存放了针对100w数据的写日志了; redis内存只剩下10万; 基于内存(而不基于之前的aof文件)中当前的10万数据构建一套最新的日志,到AOF中; 覆盖之前的老日志; 确保AOF日志文件不会过大,保持跟redis内存数据量一致.
9 redis杂谈_第3张图片
5 生产环境下的持久化配置:
5.1 根据你自己的应用和业务的数据量,save 60 10000
5.2 AOF一定要打开,fsync,everysec

  1. 缓存架构的设计:
    在高并发的系统要求下,缓存架构设计必不可少,mysql的高并发,通过分库分表等一系列操作,QPS达到几万的话,算是不错的选择了,但是考虑到电商等系统的并发,那么除了整体架构之外,缓存架构的设计显得尤为重要.(多级缓存架构,热点数据缓存等)
    6.1 redis不能支持高并发的瓶颈在哪里?
    单机,内存,网络带宽
    6.2 redis要支撑超过10万+的并发,how?
    单机的redis几乎不太可能说QPS超过10万+,除非一些特殊情况,比如你的机器性能特别好,配置特别高,物理机,维护做的特别好,而且你的整体的操作不是太复杂,单机在几万
    –读写分离:
    一般来说,对缓存,一般都是用来支撑读高并发的,写的请求是比较少的,可能写请求也就一秒钟几千,一两千
    主从架构 -> 读写分离 -> 支撑10万+读QPS的架构

  2. redis replication的核心机制:主从架构,数据在主从之间进行同步,复制不仅仅作用于在读写分离方面,同时对于redis的高可用来说,同样意义重大.
    7.1 主从复制的操作流程:
    (1)redis采用异步方式复制数据到slave节点
    (2)一个master node是可以配置多个slave node的
    (3)slave node也可以连接其他的slave node
    (4)slave node做复制的时候,是不会block master node的正常工作的.
    (5)slave node在做复制的时候,也不会block对自己的查询操作,它会用旧的数据集来提供服务; 但是复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务了
    (6)slave node主要用来进行横向扩容,做读写分离,扩容的slave node可以提高读的吞吐量

8 redis集群–读写分离:
8.1 主从复制中,数据的迁移是单向的,只能从主节点到从节点.master只负责写,slave只负责读.
一个主节点可以存在0或者多个从节点,但是一个从节点只能存在一个主节点.
默认情况下,每一台redis服务器都是主节点,主机不用配置,只需要从机配置主机即可(认定老大)
SLAVEOF host 6379(从机配置主机的地址,端口,命令的方式配置,真实的生产环境配置需要在配置文件中配置,这样才是永久生效的)

8.1.1主从架构的核心原理:
当启动一个slave node的时候,它会发送一个PSYNC命令给master node.
如果这时slave node重新连接master node,那么master node仅仅会复制给slave部分缺少的数据; 否则如果是slave node第一次连接master node,那么会触发一次full resynchronization(全量)
开始full resynchronization的时候,master会启动一个后台线程,开始生成一份RDB快照文件,同时还会将从客户端收到的所有写命令缓存在内存中。RDB文件生成完毕之后,master会将这个RDB发送给slave,slave会先写入本地磁盘,然后再从本地磁盘加载到内存中。然后master会将内存中缓存的写命令发送给slave,slave也会同步这些数据。(将rdb文件同步之后,再同步后续的写产生的同步数据)
slave node如果跟master node有网络故障,断开了连接,会自动重连。master如果发现有多个slave node都来重新连接,仅仅会启动一个rdb save操作,用一份数据服务所有slave node.
8.1.2 主从复制的断点续传
从redis 2.8开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份
master node会在内存中常见一个backlog,master和slave都会保存一个replica offset还有一个master id,offset就是保存在backlog中的。如果master和slave网络连接断掉了,slave会让master从上次的replica offset开始继续复制
但是如果没有找到对应的offset,那么就会执行一次resynchronization

8.1.3 redis主从复制的方式有两种:
(1)磁盘化同步:Redis主进程创建一个编写RDB的新进程放入磁盘文件。稍后,文件由父进程传输进 程以增量的方式传递给从进程
(2)内存RDB: master在内存中生成RDB文件,并且通过socket传输给slave节点,不会经过磁盘
默认是磁盘化传输,如果需要改为内存传输的话,需要修改配置.无磁盘化的方式适用于网络好的情况

8.1.4 从节点过期key的处理: 丛节点不会主动的过期key,只会等待master过期key。如果master过期了一个key,或者通过LRU淘汰了一个key,那么会模拟一条del命令发送给slave.

8.2 哨兵模式–架构:
9 redis杂谈_第4张图片
在这里插入图片描述
哨兵是redis集群架构中非常重要的一个组件,主要功能如下
(1)集群监控,负责监控redis master和slave进程是否正常工作
(2)消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员
(3)故障转移,如果master node挂掉了,会自动转移到slave node上
(4)配置中心,如果故障转移发生了,通知client客户端新的master地址
哨兵本身也是分布式的,作为一个哨兵集群去运行,互相协同工作
哨兵冷知识:
在故障转移之前,如果master挂了,那么不会立即进行故障转移,当其他哨兵节点服务器都去连接master的时候,发现master确实宕机,那么才会进行故障转移,根据配置选举算法,从从机中选中一台机器作为主机.
(1) 哨兵至少需要3个实例,来保证自己的健壮性
(2) 哨兵 + redis主从的部署架构,是不会保证数据零丢失的,只能保证redis集群的高可用性
8.2.0: redis哨兵主备切换的数据丢失问题:异步复制、集群脑裂
(1)异步复制导致的数据丢失
因为master -> slave的复制是异步的,所以可能有部分数据还没复制到slave,master就宕机了,此时这些部分数据就丢失了
(2)脑裂导致的数据丢失
脑裂,也就是说,某个master所在机器突然脱离了正常的网络,跟其他slave机器不能连接,但是实际上master还运行着
此时哨兵可能就会认为master宕机了,然后开启选举,将其他slave切换成了master
这个时候,集群里就会有两个master,也就是所谓的脑裂
此时虽然某个slave被切换成了master,但是可能client还没来得及切换到新的master,还继续写向旧master的数据可能也丢失了
因此旧master再次恢复的时候,会被作为一个slave挂到新的master上去,自己的数据会清空,重新从新的master复制数据
解决方案:
min-slaves-to-write 1
min-slaves-max-lag 10
要求至少有1个slave,数据复制和同步的延迟不能超过10秒
如果说一旦所有的slave,数据复制和同步的延迟都超过了10秒钟,那么这个时候,master就不会再接收任何请求了
上面两个配置可以减少异步复制和脑裂导致的数据丢失
(1)减少异步复制的数据丢失
有了min-slaves-max-lag这个配置,就可以确保说,一旦slave复制数据和ack延时太长,就认为可能master宕机后损失的数据太多了,那么就拒绝写请求,这样可以把master宕机时由于部分数据未同步到slave导致的数据丢失降低的可控范围内
(2)减少脑裂的数据丢失
如果一个master出现了脑裂,跟其他slave丢了连接,那么上面两个配置可以确保说,如果不能继续给指定数量的slave发送数据,而且slave超过10秒没有给自己ack消息,那么就直接拒绝客户端的写请求
这样脑裂后的旧master就不会接受client的新数据,也就避免了数据丢失
上面的配置就确保了,如果跟任何一个slave丢了连接,在10秒后发现没有slave给自己ack,那么就拒绝新的写请求
因此在脑裂场景下,最多就丢失10秒的数据(通过配置尽量减少脑裂导致的数据丢失)

8.2.1 redis高可用架构: 又称故障转移,failover,也叫做主切换(同上),如果系统在一年的时间内,99.99%时间内都是可用状态,那么就成为高可用.

9 redis杂谈_第5张图片
9 redis缓存穿透与雪崩:
缓存穿透与击穿的区别在于:穿透意味真大面积的缓存失效,那么应用则会跳过缓存去访问数据库,而击穿则是某个人热点key,被大量的访问所请求,导redis服务器宕机.

缓存击穿的解决方案:

  1. 热点数据不设置过期时间.(避免过期时间导致缓存击穿的情况)
  2. 互斥锁

缓存穿透解决方案:

  1. 布隆过滤
    9.1雪崩: 在某一个时间段内,缓存集中失效.或者redis宕机了.

9 redis杂谈_第6张图片
在事务队列中的命令s,如果执行过程中,有一条命令报错了,那么则会抛出异常,但是还是会继续执行事务队列中的其他命令,所以redis事务是不能保证一组命令的原子性的.

2 redis实现乐观锁:
原理: 使用watch命令,去监控key,操作key之前,会比较key的值是否改变.假设clientA开启事务,并进行业务操作
multi
Incr balance 1000
Decr account 100
… //假设这个时候,在exec执行之前,clentB对balance进行update
exec
那么clientA对key的操作就会失败.
解决方案: 需要进行unwatch解锁操作,重新使用watch命令加乐观锁.

3 redis实现分布式锁:
set key value nx,必须是这个key此时是不存在的,才能设置成功,如果说key要是存在了,此时设置是失败的
比如说有很多台机器,要竞争一把锁,此时你可以让他们对同一个锁的key,比如lock_key,设置一个value,而且都是要加上nx选项的,此时redis可以通过nx选项,保证说只有一台机器可以设置成功,可以加锁成功,其他机器都是会失败的.

你可能感兴趣的:(redis,redis,缓存,数据库)