Redis

作者: biaoqianwo | 来源:发表于2021-10-29 16:40 被阅读0次

    1、Redis 是什么?
    Redis 是一个使用 C 语言开发的数据库,不过与传统数据库不同的是 Redis 的数据是存在内存中的 ,所以读写速度非常快,因此 Redis 被广泛应用于缓存方向。

    2、分布式缓存有哪些方案?
    memcache和redis

    3、为什么要使用缓存?
    主要是为了提升用户体验(响应速度更快)以及应对更多的用户(查询并发量更大)。

    4、redis除了缓存,还能做什么?
    分布式锁限流、消息队列、某些业务(通过 sorted set 维护排行榜)等。

    5、常见的数据结构及其使用场景是什么?
    在线 redis 环境学习命令。

    5.1 String
    简单的 key-value 类型,自己构建了一种简单动态字符串(simple dynamic string,SDS),不光可以保存文本数据还可以保存二进制数据,不会造成缓冲区溢出。
    一般常用在需要计数的场景,比如用户的访问次数、热点文章的点赞转发数量等等。

    5.2 list
    链表,易于数据元素的插入和删除并且可以灵活调整链表长度,但是链表的随机访问困难。Redis 的 list 的实现为一个 双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销。
    用于发布与订阅或者说消息队列。

    5.3 hash
    内部实现也差不多(数组 + 链表)。hash 是一个 string 类型的 field 和 value 的映射表,适合用于存储对象,后续操作的时候,你可以直接仅仅修改这个对象中的某个字段的值。 比如存储用户信息,商品信息等等。

    5.4 set
    一种无序集合,集合中的元素没有先后顺序。当你需要存储一个列表数据,又不希望出现重复数据时,set 是一个很好的选择,可以基于 set 实现交集、并集、差集的操作。比如:你可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合,可以非常方便的实现如共同关注、共同粉丝等功能,这个过程也就是求交集的过程。

    5.5 sorted set
    sorted set 增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列,还可以通过 score 的范围来获取元素的列表。适用于需要对数据根据某个权重进行排序的场景。

    5.6 bitmap
    bitmap 存储的是二进制数字(0 和 1),通过 bitmap, 只需要一个 bit 位来表示某个元素对应的值或者状态,key 就是对应元素本身。 bitmap 本身会极大的节省储存空间。
    适合需要保存状态信息并需要进一步对这些信息进行分析的场景。比如用户签到情况、活跃用户情况、用户行为统计(比如是否点赞过某个视频)。

    6、Redis开始为什么不使用多线程?4.0之后为什么又开始使用多线程?

    不使用多线程的原因:

    1. 单线程编程和维护容易
    2. Redis的瓶颈不在CPU,主要是内存和网络
    3. 多线程存在死锁,线程上下文切换等问题。

    4.0增加的多线程主要是针对一些大键值对的删除操作的命令,使用这些命令就会使用主处理之外的其他线程来“异步处理”。
    6.0引入多线程主要是为了提高网络 IO 读写性能,只是在网络数据的读写这类耗时操作上使用了,执行命令仍然是单线程顺序执行。因此,不需要担心线程安全问题。默认是禁用的,只适用主线程,需要在配置文件中开启io-threads-do-reads yes,且需要设置线程数,否则是不生效的 io-threads 4 #官网建议4核的机器设置为2或3,8核的建议设置为6

    7、过期时间有什么用?

    1. 有助于缓解内存的消耗,避免内存不足。
    2. 有的业务场景就是需要某个数据只在某一时间段内存在,比如短信验证码可能只在 1 分钟内有效,用户登录的 token 可能只在 1 天内有效。

    8、假设设置了一批 key 只能存活 1 分钟,那么 1 分钟后,Redis 是怎么对这批 key 进行删除的呢?

    1. 惰性删除 :在取出 key 的时候才对数据进行过期检查。这样对 CPU 最友好,但是可能会造成太多过期 key 没有被删除。
    2. 定期删除 : 每隔一段时间抽取一批 key 执行删除过期 key 操作。且Redis 底层会通过限制删除操作执行的时长和频率来减少删除操作对 CPU 时间的影响。
      定期删除对内存更加友好,惰性删除对 CPU 更加友好。两者各有千秋,所以 Redis 采用的是 定期删除+惰性/懒汉式删除 。

    仅仅通过给 key 设置过期时间还是有问题的,可能存在定期删除和惰性删除漏掉了很多过期 key 的情况。这样就导致一定过期 key 堆积在内存里,久而久之可能内存不足。

    怎么解决这个问题呢?答案就是:内存淘汰机制。

    9、内存淘汰策略有哪些?

    1. volatile-lru(least recently used):从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
    2. volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰
    3. volatile-random:从已设置过期时间的数据集中任意选择数据淘汰
    4. volatile-lfu(least frequently used):从已设置过期时间的数据集中挑选最不经常使用的数据淘汰
    5. allkeys-lru(least recently used):当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)
    6. allkeys-random:从数据集中任意选择数据淘汰
    7. no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。
    8. allkeys-lfu(least frequently used):当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的 key
      1和4的差异和选择。

    10、怎么做到持久化的?
    一种持久化方式叫快照(snapshotting,RDB),另一种方式是只追加文件(append-only file, AOF)。

    RDB:
    通过创建快照来获得存储在内存里面的数据在某个时间点上的副本。Redis 创建快照之后,对快照进行备份。默认开启。

    AOF:
    每执行一条会更改 Redis 中的数据的命令,Redis 就会将该命令写入到内存缓存 server.aof_buf 中,然后再根据 appendfsync 配置来决定何时将其同步到硬盘中的 AOF 文件。三种:

    appendfsync always    #每次有数据修改时都会写入AOF文件,这样会降低Redis的速度
    appendfsync everysec  #每秒钟同步一次,显示地将多个写命令同步到硬盘(常用)
    appendfsync no        #让操作系统决定何时进行同步
    

    11、Redis的事务是怎样的?
    Redis 事务提供了一种将多个命令请求打包的功能。然后,再按顺序执行打包的所有命令,并且不会被中途打断。
    可以通过 MULTI,EXEC,DISCARD 和 WATCH 等命令来实现。

    12、什么是缓存穿透?如何解决?
    是大量请求的 key 不存在于缓存中,导致请求直接到了数据库上,没有经过缓存这一层。

    1. 缓存无效 key,缓存时间设置短一点
    2. 布隆过滤器

    13、什么是缓存雪崩?如何解决?
    缓存在同一时间大面积的失效,后面的请求都直接落到了数据库上,造成数据库短时间内承受大量请求。 这就好比雪崩一样,摧枯拉朽之势。

    1. 集群,避免单机宕机无法使用
    2. 设置不同的缓存时间避免大量key同一时间过期。

    14、如何保证缓存和数据库数据的一致性?
    Cache Aside Pattern(旁路缓存模式),遇到写请求是这样的:更新 DB,然后直接删除 cache 。如果更新数据库成功,而删除缓存这一步失败的情况的话,常用的解决方案是增加 cache 更新重试机制: 如果 cache 服务当前不可用导致缓存删除失败的话,我们就隔一段时间进行重试,重试次数可以自己定。如果多次重试还是失败的话,我们可以把当前更新失败的 key 存入队列中,等缓存服务可用之后,再将缓存中对应的 key 删除即可。如果redis做到了高可用,那么就不用考虑缓存删除失败了。

    15、进一步深入学习

    相关文章

      网友评论

          本文标题:Redis

          本文链接:https://www.haomeiwen.com/subject/kfrpaltx.html