缓存技术-Redis

时光毁灭记忆、已成空白 提交于 2020-02-12 12:29:58

1. Redis的了解

1.1 NoSQL

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

1.2 Redis

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

  • 高性能:用户第一次访问数据后,数据存储在缓存中,之后再访问直接从缓存中获得,相当于直接操作内存。数据库数据改变后,同步改变缓存数据。
  • 高并发:直接操作缓存能承受的请求远大于直接访问数据库,将部分数据放在33 redis中,让用户请求直接到缓存中寻找,不用访问数据库。

1.3 Redis和map区别

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

1.4 Redis和memcached区别

答:主要是四点:

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

1.5 Redis的数据类型和应用场景

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

  • string:最大为512M,用作计数功能的缓存;
  • list:字符串列表,基于链表实现,用作分页查询或者列表功能;
  • set:自动去重的列表,用作全局去重等功能,比如共同好友;
  • sorted set:多了权重参数,用来进行有序排列,用作排行榜功能;
  • hash:键值对集合,用来存储特定结构的信息,比如用户信息。

1.6 配置文件了解

答:配置文件是redis.window.conf,其中对redis是分模块配置。

  • network:配置服务器地址、端口、超时时间等;
  • general:日志文件路径、级别等;
  • snap shotting:持久化配置;
  • replication:集群配置;
  • memory management:内存管理,数据过期删除等;
  • append only mode:日志持久化方式配置。

2. Redis线程模型

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

2.1 为什么执行速度快?

答:总结如下:

  • 基于内存实现,轻量级数据库;
  • 单线程操作,避免切换上下文;
  • 多路IO复用的线程模型,一个线程监控多个IO流。

3. Redis的过期策略和内存淘汰机制

3.1 过期回收策略

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

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

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

3.2 内存淘汰机制

答:redis提供了6种数据淘汰策略。注:这个问题可以引申到redis如何保证数据都是热点数据。

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

3.3 更新一致性

  • 读请求:先读缓存,缓存没有,读数据库,写入缓存;
  • 写请求:先删除缓存,再更新数据库

4. 持久化机制

答:保证redis挂掉后再重启,数据能恢复。有两种持久化方式。

4.1 RDB-快照持久化

答:将当前内存中的数据集创建快照写入磁盘,恢复时将快照载入内存。默认采用。

触发方式

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

快照恢复

将备份文件.rdb移动到redis安装目录并启动服务,快照文件自动加载进内存。

4.2 AOF-增量持久化

答:通过记录redis所执行的写命令来记录数据库状态,恢复时将AOF文件载入内存。一般采用每秒钟同步一次的方式。

4.3 AOF重写

答:AOF文件随着服务器运行时间而越来越大,AOF重写能减小文件大小,而且数据库状态一致。AOF重写通过读取数据库现有的键值对状态实现,然后用一条命令替代之前对键值对操作的多条命令,再用bgrewriteaof实现重写。

4.3.1 重写流程-如何保持一致性

答:redis是单线程工作,所以将AOF重写放在子进程中执行。为了防止在重写期间,数据库状态发生改变。redis会维护一个AOF重写缓冲区,在子进程创建AOF期间,记录写命令;当子进程重写完成后,服务器将重写缓冲区内的内容添加到AOF文件的末尾,以保持状态一致。
总结:用个缓冲区,暂时存操作,完成重写后,再添文件末。

4.4 RDB和AOF选择

答:看区别:

  • AOF更安全,秒级持久化,但需要更多的IO资源,AOF文件也较大,恢复慢;
  • RDB安全性差,没法实时持久化(频繁执行bgsave资源消耗大),RDB文件较小,恢复快。
    注:redis4.0后,支持RDB和AOF的混合持久化,RDB作为全量备份,AOF作为增量备份。

5. 主从复制和哨兵机制

5.1 主从复制机制

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

过程

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

5.2 哨兵模式

答:哨兵(Sentinel)模式,用于管理多个Redis服务器。主要有三个功能:

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

节点下线

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

Leader选举

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

6. 事务支持

答:redis对事务的支持主要在两方面:

  • 隔离性:事务不会中断而是一直运行,直到执行完命令为止。
  • 命令序列化:redis会将事务的命令序列化不会在一个事务的执行中插入另一个请求。

6.1 相关命令

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

6.2 内部实现

答:redis以MULTI开始一个事务,再将所有命令入队,最后EXEC执行事务,所以redis不支持回滚。只有命令有语法错误或操作类型不规范才会执行失败。

7. 缓存雪崩,缓存穿透和双写一致性

7.1 缓存雪崩

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

解决方案

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

7.2 缓存穿透

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

解决方案

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

7.3 数据库和缓存的双写一致性

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

解决方案

  1. 强一致性
    如果一定要保证数据库和缓存时刻相同,可以将读写请求串行化,每次只能进行一个操作。
  2. 最终一致性
    数据库和缓存可以存在不一致的情况。
  • 双删延迟:先删除缓存数据,再更新数据库数据,最后隔段时间再删除缓存。
    原理:如果数据库更新失败,那么数据库中是旧数据,缓存中是空的,数据不会不一致。因为读的时候没有缓存,所以去读了数据库中的旧数据,然后更新到缓存中。
  • 更新数据库订阅:记录变化的key,不断尝试去删除缓存,直到成功。

7.4 并发竞争key

答:多个系统同时对一个key进行操作,最后执行顺序和期望顺序不同,导致结果不同。

解决方案

分布式锁,当然推荐使用zookeeper。思想是:每个客户端对方法加锁时,在zookeeper和指定目录下生成唯一的瞬时有序节点。根据有序节点中的序号大小,判断是否获得锁,序号最小获得锁释放锁时,直接将这个瞬时节点删除

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!