目录
1.为什么用缓存?
1.1缓存如何实现高性能?
1.2缓存如何实现高并发?
2.用缓存可能出现的问题
3.redis和memcached的区别
4.redis的单线程模型
4.1为什么redis单线程模型也能效率这么高?
5.redis的数据类型和使用场景
6.redis的过期策略手写LRU算法
6.1假设存有5G大小的数据10分钟过期,为什么10分钟后仍然占有5G内存?
6.2redis中的数据因为惰性删除或没有设置过期时间的key导致大量过期key的内存占用怎么办?
7.怎么保证redis的高并发和高可用?
7.1redis的主从复制原理
7.1.1主要复制流程
7.1.2复制的核心机制
7.1.3断点续传
7.1.4无磁盘化复制
7.1.5过期key处理
7.2redis的哨兵原理
7.3redis来加多台机器怎么保证高并发
7.4redis保证高可用
7.4.1master持久化对于主从架构的安全保障的意义
7.4.2什么是redis的高可用以及如何实现?
7.4.3怎么保证数据不丢
1.为什么用缓存?
高性能,高并发
1.1缓存如何实现高性能?
1.2缓存如何实现高并发?

2.用缓存可能出现的问题
2.1数据不一致
2.2缓存雪崩
2.3缓存穿透
2.4缓存并发竞争
3.redis和memcached的区别
- redis拥有更多的数据结构和丰富的数据操作
- redis内存利用率高于memcached
- redis是单线程,memcached是多线程,在存储大数据的情况下,redis比memcached稍有逊色
- memcached没有原生的集群模式,redis官方支持redis cluster集群模式
4.redis的单线程模型

- redis内部的server socket接收到请求后产生AE_READBLE的事件,多路复用器将事件压缩到队列中。
- 应答器接收到事件分派器的分派的事件后创建一个客户端进行连接的socket01并将AE_READABLE事件与命令请求处理器关联。
- 发送请求给socket01并通过队列到事件分派器,再到命令请求处理器。
- 命令请求处理器读取key完成更新操作后,并将sockect01的AE_WRITABLE事件跟命令回复处理器关联。
- socket01产生AE_WIRTABLE事件,并由队列到事件分派器再到命令回复处理器。
- 命令回复处理器对socket01输出本次操作的一个结果:ok
- 最后返回输出后命令回复处理器会将socket01的AE_WRITABLE事件跟命令回复处理器解除关联。
4.1为什么redis单线程模型也能效率这么高?
- 非阻塞的IO核心是基于非阻塞的IO多路复用机制
- 纯内存操作
- 单线程反而避免了多线程的频繁上下文切换问题(百度)
5.redis的数据类型和使用场景
- string: 普通的set,get,做简单的kv存储
- hash: 这个是类似map的一种结构,这个一般就是可以将结构化的数据,比如一个对象(前提是这个对象没嵌套其他的对象)给缓存在redis里,然后每次读写缓存的时候,可以就操作hash里的某个字段。
- list: 例: 微博,某个大v的粉丝,就可以以list的格式放在redis里去缓存;比如可以通过list存储一些列表型的数据结构,类似粉丝列表了、文章的评论列表了之类的东西
- set: 如果你需要对一些数据进行快速的全局去重,你当然也可以基于jvm内存里的HashSet进行去重,但是如果你的某个系统部署在多台机器上呢?得基于redis进行全局的set去重
- sorted set: 排序的set,去重但是可以排序,写进去的时候给一个分数,自动根据分数排序,这个可以玩儿很多的花样,最大的特点是有个分数可以自定义排序规则
6.redis的过期策略手写LRU算法
6.1假设存有5G大小的数据10分钟过期,为什么10分钟后仍然占有5G内存?
答:redis的定期删除没有删除掉对应的key,所以即使过期仍然存在于内存中,只有在下一次的查询对应的key时redis才会对该key进行删除。
过期策略有哪些?定期删除,惰性删除。
当redis中存有大量的数据,并且都设置了相同的失效时间,若redis在每次删除在同一时间需要对大量数据进行key的查找,则会导致cpu负载很高。
定期删除:实际上redis是默认每隔100ms随机抽取一些key来检查和删除的。
惰性删除:每次再查询时,需要对key进行一次判断是否失效,若失效这时再做删除操作,并不会返回任何数据。
6.2redis中的数据因为惰性删除或没有设置过期时间的key导致大量过期key的内存占用怎么办?
redis的内存淘汰机制:如果内存占用过多,redis会自行删除掉一些数据将内存腾出来。
内存淘汰机制都有哪些?
- noeviction:当内存不足以容纳新写入的数据时,新写入的操作会报错(一般不用)。
- allkeys-lru:当内存不足以容纳新写入的数据时,在键空间中,移除最近最少使用的key(最常用)。
- allkeys-random:当内存不足以容纳新写入的数据时,在键空间中,随机移除某个key(一般不用)
- volatile-lru:当内存不足以容纳新写入的数据时,在设置了过期时间的键空间中,移除最近最少使用的key(一般不太适合)
- volatile-random:当内存不足以容纳新写入的数据时,在设置了过期时间的键空间中,随机移除某个key
- volatile-ttl:当内存不足以容纳新写入的数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除
7.怎么保证redis的高并发和高可用?
7.1redis的主从复制原理
7.1.1主要复制流程
slave先对master进行ping操作,然后进行复制:
- 第一连接复制:复制所有数据
- 中途断开连接后再次连接进行复制:复制部分数据
RDB全量复制的具有体流程:
- master生成快照RDB文件,再将RDB文件发给slave,matser同时在内存中缓存最新的数据
- slave接收到RDB文件,然后将RDB文件保存到磁盘中
- 再进行加载RDB中的数据到内存中
- 最后master再将新缓存的数据发给slave,slave保存到内存中

复制的完整流程:

- slave node启动,仅仅保存master node的信息,包括master node的host和ip,但是复制流程没开始
- master host和ip是从哪儿来的,redis.conf里面的slaveof配置
- slave node内部有个定时任务,每秒检查是否有新的master node要连接和复制,如果发现,就跟master node建立socket网络连接
- slave node发送ping命令给master node(参考RDB复制流程)
- 口令认证,如果master设置了requirepass,那么salve node必须发送masterauth的口令过去进行
- master node第一次执行全量复制(参考RDB复制流程),将所有数据发给slave node
- master node后续持续将写命令,异步复制给slave node(注意不是直接复制数据,而是通过命令进行异步复制)
7.1.2复制的核心机制
replication的核心机制:
- redis采用异步方式复制数据到slave节点,不过redis 2.8开始,slave node会周期性地确认自己每次复制的数据
- 一个master node是可以配置多个slave node
- slave node也可以连接其他的slave node
- slave node做复制的时候,是不会block master node的正常工作(异步)
- slave node在做复制的时候,也不会block对自己的查询操作,它会用旧的数据集来提供服务; 但是复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务(暂停时间在ms到s之间,具体和数据量有关)
- slave node主要用来进行横向扩容,做读写分离,扩容的slave node可以提高读的吞吐量
主要复制的方式模块:
master会在自身不断累加offset,slave也会在自身不断累加offset
slave每秒都会上报自己的offset给master,同时master也会保存每个slave的offset
这个倒不是说特定就用在全量复制的,主要是master和slave都要知道各自的数据的offset,才能知道互相之间的数据不一致的情况
master node有一个backlog,默认是1MB大小
master node给slave node复制数据时,也会将数据在backlog中同步写一份
backlog主要是用来做全量复制中断后的增量复制的(即上上图的部分数据复制)
info server,可以看到master run id

如果根据host+ip定位master node,是不靠谱的,如果master node重启或者数据出现了变化,那么slave node应该根据不同的run id分,run id不同就做全量复制

如果需要不更改run id重启redis,可以使用redis-cli debug reload命令
从节点使用psync从master node进行复制,psync runid offset
master node会根据自身的情况返回响应信息,可能是FULLRESYNC runid offset触发全量复制,可能是CONTINUE触发增量复制
master默认每隔10秒发送一次heartbeat,salve node每隔1秒发送一个heartbeat
7.1.3断点续传
- 从redis 2.8开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份
- master node会在内存中常见一个backlog,master和slave都会保存一个replica offset还有一个master id,offset就是保存在backlog中的。如果master和slave网络连接断掉了,slave会让master从上次的replica offset开始继续复制
- 但是如果没有找到对应的offset,那么就会执行一次resynchronization
7.1.4无磁盘化复制
- master在内存中直接创建rdb,然后发送给slave,不会在自己本地落地磁盘了
- repl-diskless-sync:是否开启无磁盘化复制
- repl-diskless-sync-delay,等待一定时长再开始复制,因为要等更多slave重新连接过来
7.1.5过期key处理
slave不会过期key,只会等待master过期key。如果master过期了一个key,或者通过LRU淘汰了一个key,那么(master)会模拟一条del命令发送给slave。
7.2redis的哨兵原理
7.3redis来加多台机器怎么保证高并发
redis的高并发的瓶颈:单机(最多几万并发),所以需要进行多机的redis解决高并发问题

如果redis要支撑10万+:多个redis
大多数情况是解决高并发的读操作
读写分离,主从复制:主负责写,从负责读

7.4redis保证高可用
7.4.1master持久化对于主从架构的安全保障的意义
如果采用了主从架构,那么建议必须开启master node的持久化!
- 如果: master -> RDB和AOF都关闭了 -> 全部在内存中
master宕机,重启,是没有本地数据可以恢复的,然后就会直接认为自己IDE数据是空的
master就会将空的数据集同步到slave上去,所有slave的数据全部清空
100%的数据丢失
所以master节点,必须要使用持久化机制
- master的各种备份方案,要不要做,万一说本地的所有文件丢失了
从备份中挑选一份rdb去恢复master; 这样才能确保master启动的时候,是有数据的
即使采用了后续讲解的高可用机制,slave node可以自动接管master node,但是也可能sentinal还没有检测到master failure,master node就自动重启了,还是可能导致上面的所有slave node数据清空故障
7.4.2什么是redis的高可用以及如何实现?
redis的高可用:即redis的master node在挂掉之后,会有其他的slave node变为master node继续提供服务。

哨兵简介:
sentinal,中文名是哨兵
哨兵是redis集群架构中非常重要的一个组件,主要功能:
- 集群监控,负责监控redis master和slave进程是否正常工作
- 消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理
- 故障转移,如果master node挂掉了,会自动转移到slave node
- 配置中心,如果故障转移发生了,通知client客户端新的master地址
7.4.3怎么保证数据不丢
数据丢失的情况:
- 异步复制导致数据的丢失
- 集群脑裂导致数据丢失
情况1:
当master中的数据还没来的及复制给slave node,这时master node挂了,哨兵将slave node升级为master node后会丢失还没来得及复制的那部分数据。

解决方案:
针对还没来得及复制数据主要是因为大量数据同时进入master node,所以这时client可以做降级处理,在本地进行缓存,或限流等,减慢请求的速度。

情况2:
当master node和和哨兵集群网络故障断开后,只有client可以对master进行写入操作,但是master不能对这时写入的数据进行备份,同时哨兵检测不到master会自动将slave node升级为master node,但实际上两个master node都还活着。 当网络恢复后,将之前的master node降级为slave node,此时slave node只能从新的master node进行同步,而没有将之前client写入的数据备份到新的master node中导致数据丢失。

解决方案:
出现脑裂时旧的master node拒绝client端的写入请求,而client端进行降级方案本地缓存(同情况1的解决),等网络恢复后再由client对新的master进行写入之前的本地缓存数据。
