缓存技术-Redis

1. 基础知识

1.1 NoSQL

答:NoSQL(Not Only SQL),泛指非关系型的数据库,目的是解决高并发、高拓展和大数据储存问题。细分为:键值型(Redis),列存储(HBase),文档型(MongoDB),图形(Neo4j)。

1.2 Redis

答:Redis(Remote Dictionary Server远程字典服务)是一款高性能、高并发key-value型分布式内存数据库,基于内存运行且支持持久化的NoSQL数据库。常被用于缓存和消息队列。

1.2.1 优缺点

优点

  • 高性能/读写性能优异。用户第一次访问数据后,数据存储在缓存中,之后再访问直接从缓存中获得,相当于直接操作内存。
  • 高并发。操作缓存能承受的请求远大于直接访问数据库,将部分数据放在redis中,能提高并发程度。
  • 支持数据持久化,AOF和RDB两种方式。
  • 支持事务,所有操作都是原子性的。
  • 数据类型丰富,string、hash、set、list、sorted set。
  • 支持集群模式,如主从复制做到读写分离。

缺点

  • 数据库容量受到物理内存的限制;
  • 不具备自动容错和恢复功能。如主机宕机,部分数据未能同步到从机,切换IP后会导致数据不一致;
  • 扩容难。

1.2.2 为什么执行速度快

答:总结如下:

  • 基于内存实现,轻量级数据库;
  • 单线程操作,避免切换上下文,也没有线程安全问题;
  • 多路IO复用模型,一个线程监控多个IO流,事件放队列,派发器分发,对应处理器处理。

1.2.3 Redis和map区别

答:缓存分为本地缓存和分布式缓存。

  • map是本地缓存,优点是轻量快速,缺点是多实例情况下,每个实例都有一个缓存。
  • Redis是分布式缓存,多实例情况下,每个实例共用一个缓存,具有一致性,缺点是架构复杂。

1.2.4 Redis和memcached区别

答:主要是四点:

  • Redis数据类型丰富,memcached只支持String类型;
  • Redis支持数据持久化,RDB和AOF,memcached全部存在内存;
  • Redis支持集群模式(主从,哨兵),memcached没有原生的集群模式;
  • Redis是单线程的多路IO复用模型,memcached是多线程的非阻塞IO复用模型

1.3 数据类型和应用场景

答:支持五种数据类型作为value,key值都是字符串类型。

  • string:最大为512M。用作计数器,缓存,用户的Session等;
  • list:有序列表,基于链表实现。用作分页查询,列表功能,消息队列/异步队列(左进右出);
  • set:自动去重的列表。用作全局去重等功能,比如共同好友;
  • sorted set:多了权重参数。用来做排序,比如排行榜Top10功能,延时队列(时间戳做排序,内容做key,消费者根据score获取数据);
  • hash:存储特定结构的信息/结构化数据。比如用户信息。
  • pub/sub:主题订阅者模式,实现1:N的消息队列,但消费者下线后,生产的消息就丢失了。

1.4 Redis线程模型

答:Redis是单线程的。

  • 内部使用了单线程的文件事件处理器 file event handler。
  • 采用IO多路复用机制同时监听多个socket,将socket上的事件放入队列,事件派发器每次从队列中取出一个事件,交给对应的事件处理器处理。
  • 文件事件处理器包含4个部分:多个socket,IO多路复用程序,文件事件派发器,事件处理器。

总结:一对多监听,事件放队列,派发器分发,对应处理器处理

2. 持久化

答:把内存数据写入磁盘,保证宕机再重启数据能恢复。有RDB和AOF两种持久化方式。

2.1 RDB-快照持久化

答:将内存中的数据集以快照形式写入磁盘,恢复时载入快照到内存。 Redies默认采用

2.1.1 触发方式

  • 自动触发:每隔多少秒,有多少数据发生变化,就自动触发持久化;
  • 手动触发:bgsave命令,异步进行创建快照。

2.1.2 优缺点

  • 优点:只有一个.rdb文件,恢复快,随时可以转移,性能好。
  • 缺点:安全性差,没法实时持久化。(隔段时间持久化一次,频繁手动性能低)

2.1.3 原理

  • fork:redis通过创建子进程来进行RDB操作
  • cow:copy on write,子进程创建后,父子进程共享数据段,父进程继续提供读写服务,写脏的页面数据会逐渐和子进程分离开来。

2.2 AOF-增量持久化

答:将redis执行的所有写命令记录到日志文件中,恢复时将AOF文件载入内存。一般采用每秒钟同步一次everysec的方式。默认关闭,appendonly yes 开启配置。

2.2.1 AOF重写

答:AOF文件随着服务器运行时间增长而越来越大,AOF重写能减小文件大小,而且数据库状态一致

  • 读取数据库现有的键值对状态,用一条命令替代之前对键值对操作的多条命令,再用bgrewriteaof实现重写。
  • 子进程中执行。redis会维护一个AOF重写缓冲区,在子进程创建AOF期间,记录写命令;当子进程重写完成后,服务器将重写缓冲区内的内容添加到AOF文件的末尾,以保持状态一致。

流程

  • 从主进程中fork出子进程,并拿到fork时的AOF文件数据写到一个临时AOF文件中
  • 在重写过程中,redis收到的命令会同时写到AOF缓冲区和重写缓冲区中,这样保证重写不丢失重写过程中的命令
  • 重写完成后通知主进程,主进程会将AOF缓冲区中的数据追加到子进程生成的文件中
  • redis会原子的将旧文件替换为新文件,并开始将数据写入到新的aof文件上

总结:用个缓冲区,暂时存操作,完成重写后,再添文件末。

2.2.2 优缺点

  • 优点:安全性好,秒级持久化。
  • 缺点:需要更多的IO资源,AOF文件也较大,恢复慢;

注:redis4.0后,支持RDB和AOF的混合持久化,RDB作为全量备份,AOF作为增量备份。

3. 过期策略和内存淘汰

Redis是键值型数据库,缓存的key总是会有过期时间,过期策略就是回收这些过期的key。

内存淘汰是在Redis缓存内存不足时,又有新写入,需要淘汰过期内存的策略。

注:过期回收针对过期key,内存淘汰针对内存不足。

3.1 过期回收策略

答:redis中的数据过期使用了定期删除和惰性删除相结合的方式。

  • 定期删除:redis默认每隔100ms就随机抽取一定量的数据判断是否过期,过期就删除;
  • 惰性删除:在获取一个key时,redis会检查这个key是否过期,若过期则删除。

如果定期删除漏掉很多过期key,用户也没及时去查,没用惰性删除,导致大量过期key积压在内存中,消耗资源,所以需要内存淘汰。

3.2 内存淘汰/保存热点数据

3.2.1 淘汰策略

答:redis提供了6种数据淘汰策略。

设置过期时间的key

  • volatile-lru:用LRU算法移除设置了过期时间的key;
  • volatile-ttl:移除设置了过期时间的有更早过期时间的key;
  • volatile-random:随机移除设置了过期时间的key;
    全局的key
  • allkeys-lru:内存不足时,用LRU算法移除任意key;
  • allkeys-random:随机移除任意key;
  • no-eviction:不移除任何key,只返回错误信息。默认。

3.2.2 回收流程

  1. 客户端执行新命令
  2. Redis检查内存使用情况,大于maxmemory则按设定的内存淘汰策略回收内存
  3. 继续执行命令

4. 事务

4.1 Redis事务

答:redis事务本质是通过MULTI、EXEC、WATCH和DISCARD等一组命令集合执行。执行过程是一次性的(不会中断一直运行),顺序性的(串行化执行),排他性的(不会在中间插入别的命令)。

4.2 相关命令

  • MULTI:标记一个事务块的开始。
  • EXEC:执行所有事务块内的命令。
  • DISCARD:取消事务,放弃执行事务块内的所有命令。
  • UNWATCH:取消 WATCH 命令对所有 key 的监视。
  • WATCH key [key …]:监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

4.3 内部实现

  1. redis不支持回滚,不保证原子性,事务失败也继续执行。
  2. 单条命令是原子性,但整个事务不是原子性。
  3. 命令语法错误或操作类型不规范才停止执行。

5. 集群方案

5.1 主从复制机制

答:主从(Master-Slave)机制,主机以写为主,从机以读为主,有效避免单点故障导致的数据丢失,主从数据库的数据实时同步。

过程

  1. 从数据库启动,向主数据库发送同步请求;
  2. 主数据库收到后,进行RDB快照,并将快照过程中的收到命令缓存起来;
  3. 快照完成后,将.rdb文件和所有缓存的命令发给从数据库;
  4. 从数据库收到后,进行快照同步并执行收到的缓存命令。
    在这里插入图片描述

5.2 哨兵模式

答:哨兵(Sentinel)模式,用于管理多个Redis服务器。哨兵至少需要3个实例才能保持健壮性。一般都使用哨兵 + 主从架构保证高可用

5.2.1 功能

主要有三个功能:

  • 监控:哨兵会不断检查主机和从机是否运行正常;
  • 通知:当被监控的某个redis发生问题,哨兵会发送通知;
  • 故障迁移:当主机不能正常工作,哨兵会选择主机的一个从机升级为主机,让其他从机改为复制新主机。旧主机复活时,将其变为新主机的从机,最后向客户端通知主机的变化。

5.2.2 节点下线

  • 主观下线:哨兵认为此redis节点发生了故障,就主观下线该节点。通过心跳包检测实现。
  • 客观下线:所有哨兵中的多数(>quorum)认为此redis节点主观下线,则该节点客观下线。

5.2.3 Leader选举

故障转移时,需要哨兵选出一个leader进行后续操作。

流程为:每个主管下线的哨兵向其他哨兵发出设置他为Leader的命令,当票数达到设定值时,称为领导者。若有多个哨兵当选Leader,则等待一段时间再选举。
在这里插入图片描述

6. 分布式锁

当多客户端并发操作Redis,可能出现并发竞争,需要分布式锁帮助管理顺序。

6.1 实现

  • 用 setnx (set if not exists)争抢锁。key不存在就设为value,存在不做动作。
  • 抢到后,用 expire 给锁加一个过期时间防止锁忘记了释放。
  • 可以通过参数将setnx和expire合成一条指令。

6.2 举例

  1. 每个系统通过 Zookeeper 获取分布式锁,确保同一时间,只能有一个系统实例在操作某个Key。
  2. 写入/查询MySQL时必须保存一个时间戳,每次都要判断当前 Value 的时间戳是否比缓存里的 Value 的时间戳要新。如果是的话,那么可以写,否则,就不能用旧的数据覆盖新的数据。

7. 缓存异常

7.1 缓存雪崩

答:缓存雪崩是指缓存同一时间大面积失效,这时有一波请求访问数据库,导致数据库崩掉。

解决方案

  • 事前:保证redis服务器的高可用,发现宕机就立马补上,内部选择恰当的内存淘汰机制,设置随机的key失效时间(保证不会同时大面积失效);
  • 事中:本地ehcache缓存 + 限流和降级处理,避免数据库崩溃;
  • 事后:redis持久化尽快恢复缓存数据。
    在这里插入图片描述

7.2 缓存穿透

答:故意请求不在缓存也不在数据库中的数据,导致大量请求直接打到数据库上,导致崩溃。

解决方案

  • 参数校验:将不合法的参数请求直接抛异常。
  • 缓存无效key:若缓存和数据库都查不到数据,就写一个到redis中并设置过期时间。
  • 布隆过滤器:把所有可能的请求值放在布隆过滤器中,用户请求时先判断是否存在,不存在直接返回错误信息。
    在这里插入图片描述

7.3 缓存击穿

答:缓存击穿是指缓存中没有但数据库中有的数据,同时大并发去数据库查询同一条数据,导致崩溃。比如缓存热点数据key失效后的处理。

解决方案

  • 设置热点数据永不过期
  • 对缓存查询加互斥锁。key不存在就加锁查DB写缓存,然后解锁;其他进程发现有锁就等待,等解锁后从缓存中拿数据。

7.4 缓存降级

答:缓存降级是指服务出现问题或非核心服务影响到核心流程的性能时,弃车保帅,保证核心服务可用,即使是有损服务。

解决方案

  • 必须对系统进行梳理排序,从而确定可以降级的模块。
  • 一般对不重要的缓存数据,可以直接返回默认值,而不去访问数据库。

7.5 双写一致性

答:高并发情况下很容易因为操作失败而导致数据不一致。

解决方案

  1. 强一致性
    读写请求串行化,每次只能进行一个操作,保证数据库和缓存时刻相同。
  2. 最终一致性
    数据库和缓存可以存在不一致的情况。
  • 双删延迟:先删除缓存数据,再更新数据库数据,最后隔段时间再删除缓存。
  • 原理:如果数据库更新失败,那么数据库中是旧数据,缓存中是空的,数据不会不一致。因为读的时候没有缓存,所以去读了数据库中的旧数据,然后更新到缓存中。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值