zoukankan      html  css  js  c++  java
  • Redis 最常见的问题

    Redis 常用的五种数据结构

    字符串 String

    • 概念:字符串主要用于管理 Redis 字符串值。
    • 容量:最大为数据长度是 512M

    列表 List

    • 概念:列表是简单的字符串列表,按照插入顺序排序,可以从列表的头部或尾部插入一个元素。
    • 容量:一个列表最多可以包含 2^32 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。

    集合 Set

    • 概念:集合是 String 的无序集合,集合元素是唯一的。
    • 容量:集合中最大可存储的元素数量为 2^32 - 1 (40 多亿)。

    哈希 Hash

    • 概念:哈希是一个 String 类型的 field 和 value 的映射表,适合存储对象。
    • 容量:每个 Hash 可以存储 2^32 - 1 键值对 (40 多亿)。

    有序集合 Sorted Set

    • 概念:有序集合也是 String 的集合,但每个元素会关联一个 double 类型的分数 (score) 且集合中的元素是从小到大排序的。
    • 容量:有序集合中最大可存储的元素数量为 2^32 - 1 (40 多亿)。

    Redis 常见问题

    说一说 Redis 哈希槽的概念 ?

    Redis 集群没有使用一致性 hash,而是引入了哈希槽的概念。
    Redis 集群中有 16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定存储在那个槽。
    集群的每个节点负责一部分 hash 槽。

    Redis 为什么选择单线程?

    • 多线程会频繁切换上下文消耗大量的 CPU。
    • 单线程支持原子操作,不会存在锁竞争问题。

    为什么不使用 Redis 的事务?

    • 不支持回滚操作,不能满足原子性。

    Redis 集群的利弊

    好处

    • 容量增加,处理能力增强。
    • 可按需扩容与缩容。

    问题

    1、存储数据时如何选择节点、查询数据时如何选择节点 ?
    2、新增节点时如何拉取数据、剔除节点时如何转移数据 ?

    解决方式

    为了解决数据与节点直接的映射关系,Redis 引入了槽。
    引入槽之后,节点上放置的是槽,槽当中存储的是数据。

    一个集群只能有 16384 个槽,编号为 0 - 16383。这些槽会分配给集群中的所有主节点,分配策略无要求。
    可以指定哪些编号的槽分配到哪一个主节点。集群会记录节点和槽的对应关系。

    如何计算 Key 在那个槽?
    对 Key 求哈希值,然后对 16384 取余,余数的值就是 Key 对应的槽的编号。
    即:CRC16 (Key) % 16384

    Redis 为什么需要管道技术?

    Redis 提供了一种管道技术,可以让客户端一次发送多条命令。
    期间不需要等待服务器端的响应,等所有的命令发送完成后,再依次响应。
    这样节省了时间,提升了效率。

    Redis 分布式锁是什么 ?

    • 先拿 setnx 来争抢锁,抢到之后,再用 expire 给锁加一个过期时间防止锁忘记了释放。
    • 如果在 setnx 之后,执行 expire 之前进程意外 crash 或重启维护, 那么就需要把 setnxexpire 合成一条指令来用。

    假如 Redis 里面有一亿个 key,其中 10 万个 key 是以某个固定的已知前缀开头的,如何将它们全部找出来?

    • 使用keys指令可以扫出指定模式的key列表。
    • 如果这个redis正在给线上的业务提供服务,那么使用key指令会导致线程阻塞。(redis是单线程的,执行key指令期间,线上服务会卡顿,直到指令执行完成,服务才会恢复)。在这种场景下,就可以使用scan指令,该指令可以无阻塞的提取出指定模式的key列表,但是会有一定重复的概率,可以在客户端做一次去重就好了, 但是整体花费的时间会比直接使用keys指令长。

    如何实现 Redis 异步队列 ?

    使用 list 结构作为队列,rpush 生产消息,lpop 消费消息。
    lpop 没有消息的时候,要适当 sleep 一会再重试。
    如果不用 sleep, 还有个指令 blpop, 在没有消息的时候, 他会阻塞住直到有消息。

    如果要生产一次消费多次,则需要使用 pub/sub 主题订阅者模式,可以实现 1:N 的消息队列。
    在消费者下线的情况下,生产的消息会丢失。

    在这种情况下,就得使用更专业的消息队列,例如 RabbitMQ。

    如何实现 Redis 延时队列 ?

    使用 SortedSet,拿时间戳作为 Score, 消息内容作为 key 调用 zadd 来生产消息,
    消费者用 zrangebysocre 指令获取N秒之前的数据轮询进行处理。

    如果有大量的 key 需要设置统一时间过期,需要注意什么 ?

    如果有大量的 key 过期时间设置过于集中,到过期的那个时间点。
    redis 可能会出现短暂的卡顿现象。一般需要在时间生加上一个随机值, 使得过期时间分散一些。

    Redis 如何做持久化 ?

    bgsave 做镜像全量持久化, aof 做增量持久化。
    因为 bgsave 会耗费较长时间, 不够实时, 在停机的时候会导致大量丢失数据, 所以aof来配合使用。
    redis 实例重启时, 会使用 bgsave 持久化文件重新构建内存, 在使用 aof 重放近期的操作指令来实现完整恢复重启之前的状态。

    如果不要求性能, 在每条写指令是都 sync 一下磁盘, 就不会丢失数据。
    但是在高性能的要求下每次都 sync 是不现实的, 一般都使用定时 sync, 比如1s1次, 这个时候最大就会丢失1s的数据。

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

    Pipeline 有什么好处?

    可以将多次 IO 往返的时间缩减为一次, 前提是 pipeline 执行的指令质检没有因果相关性。
    使用 redis-benchmark 进行压测的时候可以发现影响 redisQPS 峰值的一个重要因素是 piepline 批次指令的数目。

    Redis 的同步机制是如何操作的?

    redis 可以使用主从同步, 从从同步。
    第一次同步时, 主节点做一次 bgsave, 并同时将后续修改操作记录到内存buffer。
    待完成后将 rdb 文件全量同步到复制节点, 复制节点接受完成后, 将rdb镜像加载到内存。
    加载完成后, 再通知主节点将修改期间的操作 记录同步到复制节点进行重放就完成了同步过程。

    Redis 集群的原理?

    redis sentinal 着眼于高可用, 在 master 宕机时会自动将 slave 提升为 master, 继续提供服务。

    redis cluster 着眼于扩展性, 在单个 redis 内存不足时, 使用 cluster 进行分片存储。

    缓存穿透

    现象

    查询不存在的数据,缓存中没有数据,数据库也没有数据。
    因此所有的请求都访问到了数据库,给数据库造成了压力。

    解决方法

    1、采用布隆过滤器,将所有可能存在的数据,哈希到一个很大的 bitmap 中,
    一个一定不存在的数据会被 bitmap 拦截调,从而避免了对数据库的查询压力。

    2、如果查询的数据为空,那么直接将空数据也缓存起来并设置较短的过期时间。
    这样下次访问的时候,就直接返回空值。

    缓存预热

    系统上线之后,将需要缓存的数据直接加载到内存。

    实现思路:

    1、直接写个缓存刷新命令,上线时手动操作。
    2、项目启动时自动加载缓存到内存。
    3、定时刷新缓存。
    

    Redis 的三种删除策略

    定时删除

    在设置键的过期时间的同时,创建一个定时任务。当键达到过期时间时,立即执行对键的删除操作。

    • 优点

    对内存友好,定时删除策略可以保证过期键会尽可能的快被删除,并且释放过期键所占用的内存。

    • 缺点

    对 CPU 时间片不友好,在过期键比较多的情况下。删除任务会占用很大一部分 CPU 时间片,在内存不紧张但是 CPU 时间紧张时.将 CPU 事件用在删除和当前任务无关的过期键上,会影响服务器的响应时间和吞吐量。

    惰性删除

    • 优点

    对 cpu 时间友好,在每次从键空间获取键时进行过期键检查并是否删除,删除目标也仅限当前处理的键,这个策略不会在其他无关的删除任务上花费任何 cpu 时间。

    • 缺点

    对内存不友好,过期键过期也可能不会被删除,导致所占的内存也不会释放。甚至可能会出现内存泄露的现象,当存在很多过期键,而这些过期键又没有被访问到,这会可能导致它们会一直保存在内存中,造成内存泄露。

    定期删除

    由于定时删除会占用太多的 CPU 时间片,影响服务器的响应时间和吞吐量。并且惰性删除浪费太多的内存,有内存泄漏的风险。因此定期删除策略是这两策略的折衷策略。

    • 优点

    定期删除策略每隔一段时间执行一次删除过期键操作,并通过限制删除操作执行的时长和频率来减少删除操作对 CPU 时间的影响。

    定时删除策略有效地减少了因为过期键带来的内存浪费。

    什么是缓存穿透?

    缓存穿透是指缓存和数据库中都没有数据的情况下,客户端不断发起请求,导致数据库压力过大。

    什么是缓存击穿?

    缓存击穿是指缓存过期之后,瞬时间并发客户端特别多查询同一条数据的情况下,导致数据库压力过大。

    什么是缓存雪崩?

    缓存雪崩是指缓存中大量的不同数据同时过期,此时查询大量的数据,导致数据库压力过大。

  • 相关阅读:
    html实现打印预览效果
    layui-table 对表格数据进行处理之后的排序问题
    layui-table与layui-rate评分转换成星级的使用
    使用apache的poi来实现数据导出到excel的功能——方式二
    java获取配置文件中的key=value值
    layDate——设置最大日期不能超过当前日期
    layDate——初步使用
    echarts使用——柱状图
    layui内部定义的function,外部调用时候,提示某函数未定义现象解决方案
    layui table异步调用数据的时候,数据展示不出来现象解决方案
  • 原文地址:https://www.cnblogs.com/yxhblogs/p/9063913.html
Copyright © 2011-2022 走看看