redis常见问题

1.应用场景

1. 开销大的复杂计算:以 MySQL 为例子,一些复杂的操作或者计算(例如大量联表操作、一些分组计算),如果不加缓存,不但无法满足高并发量,同时也会给MySQL 带来巨大的负担。
2. String 类型:计数器,缓存用户对象,分布式锁, session 共享
3. List 类型:不频繁更新排行榜,消息队列
4. Hash 类型:购物车,缓存对象 , 活动数据
5. Zset :实时排行榜,抢票加速包 , 延迟消息队列
6. Set 类型:分库分表之后减少复杂查询,黑白名单,筛选功能 , 抽奖等

2.redis主从的实现原理

1. 配置文件中配置主从的ip,端口
2. 主从之间建立socket的连接
3. 发送ping命令
4. 权限验证
5. 同步数据 =》 全量复制 / 增量复制
6. 命令持续复制

3.全量复制 / 增量复制

  • 全量复制:
》用于初次复制或其它无法进行部分复制的情况,将主节点中的所有数据都发送给从节点,是一个非常重型的操作,当数据量较大时,会对主从节点和网络造成很大的开销
1. psync同步命令 理由: 从节点没有复制的偏移量 
2. 判断或解析当前属于全量复制 =》 发送进程id以及偏移量 从那边实际是没有偏移量的 所以判断是全量的复制
3. info master信息 =》 slave在得到之后,slave需要保存他们
4. 主发送RDB文件作为数据发送给从,从解析完成之后,会做数据的清理,以及日志的记录
5. 返回一个从的信息回去,主会进行一次记录
  • 部分复制:
1. 主从之间发生网络断开,有一个时间限制(超时的时间)主从出现异常
2. 主节点根据偏移量将数据发送给从节点,从节点在保存数据

4.redis数据怎么同步保持一致性

  • 双写策略:双写策略主要是指,在程序完成写操作之后,然后在事务提交成功之后,再往缓存中写入数据;这里会存在一个问题就是数据可能会因为某一些原因在mysql中没有写入成功;然后Redis又插入成功需要回滚;需要值得注意缓存的写入不适合在事务中进行写入,会影响事务的执行速度的;
  • 异步更新策略:在对换出数据一致性要求不是那么高,数据量也不是很大的时候则可以考虑定期全量同步缓存;另一种方案就是采用队列技术,通过对mysqlbinlog日志的监听,利用canel工具读取binlog日志信息同步到队列中,再通过worker进程去同步(参考地址: https://blog.csdn.net/qq_39962403/article/details/109454726)

5.redis使用的时候需要注意什么

1. redis数据更新的问题 =》 双写 / 订阅binlog日志异步更新
2. redis中不存在太过大的value(1w7行的数据不合适)
3. 冷热数据分离 =》 redis当中仅缓存热点的数据
4. 缓存数据的过期时间 =》 如果是当下的热点的数据不考虑 ,做一个监听程序
5. 连接数 => 请求多,负载大,可以适当考虑考虑多台redis 或者连接池
6. keys flush,select 很影响性能
7. 实际在项目中不太建议使用redis做消息队列,因为从业务以及项目整体的角度来说是不适合的
8. 批量操作一定要基于范围操作 =》 管道 事务

6.redis对热key的解决方案

1. 多级缓存,浏览器端、在 nginx 应用程序中可以结合 lua 构建缓存、在服务本身自己也再构建缓存、及分布式缓存
2. 增加热点数据发现系统,在请求查询回源到服务之后 nginx 应用将查询请求上报到热点发现系统中,热点发现系统对请求数据统计并将热点信息数据推送设置到对应节点的缓存上(nginx 本地缓存)
3. 做好主从 / 集群,增强系统的高可用
4. 分布式缓存数据更新可同 canal binlog 日志的监听,并异步更新缓存信息数据
5. 减少大 value 的存在,维度化缓存;将整体的数据拆分为各个小维度的数据存储并更新特别是请求频繁的数据
6. 做好降级开关,如果因为缓存导致应用可用性下降,可以考虑部分用户降级(比如返回服务的缓存)然后慢慢减少降级,后台通过worker 预热缓存

7.redis缓存的雪崩、穿透、击穿问题

  • 缓存穿透
指查询一个一定不存在的数据,如果从存储层查不到数据则不写入缓存,这将 导致这个不存在的数据每次请求都要到DB 去查询,可能导致 DB 挂掉。
解决方案 :
1. 查询返回的数据为空,仍把这个空结果进行缓存,但过期时间会比较短 ;
2. 布隆过滤器 : 将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对 DB 的查询。
  • 缓存击穿
对于设置了过期时间的 key ,缓存在某个时间点过期的时候,恰好这时间点对 这个 Key 有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB 加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把 DB 压垮。
解决方案 :
1. 使用互斥锁 : 当缓存失效时,不立即去 load db ,先使用如 Redis setnx 去设置一个互斥锁,当操作成功返回时再进行load db 的操作并回设缓存,否则重试 get 缓存的方法。
2. 永远不过期 : 物理不过期,但逻辑过期 ( 后台异步线程去刷新)
  • 缓存雪崩
设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部 转发到 DB DB 瞬时压力过重雪崩。与缓存击穿的区别: 雪崩是很多 key ,击穿是某一个 key 缓存。
解决方案 :
将缓存失效时间分散开,比如可以在原有的失效时间基础上增加一个随机值, 比如 1-5 分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效 的事件。

8.redis为什么要用skiplist及skiplist的实现

这个问题的关键因素在于排序;数据的排序,可以进行跨度的计算;
我们可以了解一下关于 Redis 如何实现对排名的计算;
zset 的底层中会存在一个关键的指针 forwrad 在这个指针上都正价了 span 属性代表跨度的意思,标识从当前层的当前节点沿着forward 指针调到下一个节点中间会跳过多少个节点, Redis 插入和删除的时候会小心的更新这个元素的大小,而当我们要计算一个元素的排名的时候只需要将“ 搜索路径 经过的所有节点的跨度 span 值进行叠加就可以算出元素的最终排行
为什么采用跳远表,主要的关键因素在于可以很好的帮助 Redis 实现节点元素的排名计算

实现:Redis 的跳跃表由 zskiplistNode skiplist 两个结构定义 , 其中 zskiplistNode 结构用于表示跳跃表节点 , zskiplist 结构则用于保存跳跃表节点的相关信息, 比如节点的数量 ,以及指向表头节点和表尾节点的指针等等。跳跃表在 Redis 中使用不是特别广泛,只用在了两个地方。一是实现有序集合键,二是集群节点中用作内部数据结构在跳跃表中每增加一个新的节点,都需要调用一个随机算法给它分配一个合理的层数,直观上的期望目标是50% 的概率分配到level1,25% 的概率被分配到 level2,12.5% 概率分配到 level3 ,以此类推 2^-63 的概率被分配到最顶层,每次一层的晋升率是50%

9.Redis对数据的处理

淘汰策略
Redis 的内存淘汰策略是指在 Redis 的用于缓存的内存不足时,怎么处理需要新写入且需要申请额外空间的数据。
  • 当内存不足以容纳新写入数据时,新写入操作会报错。
  • allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。(这个是最常用的)
  • allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key
  • 当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key
  • volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key
  • volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。
过期数据
当主节点存储大量设置超时的数据时, redis 内部需要维护过期数据删除策略,删除策略主要有两种:惰性删除和定时删除
  • 惰性删除:主节点每次处理读取命令时,都会检查键是否超时,如果超时则执行del命令删除键对象,之后del命令也会异步发送给从节点。因为保持复制的一致性,从节点自身永远不会主动删除超时数据。
  • 定时删除:Redis主节点在内部定时任务会循环采样一定数据量的键,当发现采样的键过期时执行del命令,之后再同步给从节点

10.redis的哨兵的监控机制?

哨兵监控也是有集群的,会有多个哨兵进行监控,当判断发生故障的哨兵达到一定数量的时候才进行修复。一个健壮的部署至少需要三个哨兵实例。
1. 每个 Sentinel 以每秒钟一次的频率向它所知的 Master Slave 以及其他 Sentinel 实例发送一个 PING 命令
2. 如果一个实例( instance )距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel 标记为主观下线。
3. 如果一个 Master 被标记为主观下线,则正在监视这个 Master 的所有 Sentinel 要以每秒一次的频率确认 Master 的确进入了主观下线状态。
4. 当有足够数量的 Sentinel (大于等于配置文件指定的值)在指定的时间范围内确认 Master 的确进入了主观下线状态, 则Master 会被标记为客观下线
5. 在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有 Master Slave INFO 命令
6. Master Sentinel 标记为客观下线时, Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10 秒一次改为每秒一次
7. 若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会被移除。若 Master 重新向Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除

11.redis clusterhash slot算法

redis cluster有固定的16384hash slot,对每个key计算CRC16值,然后对16384取模,可以获取key对应的hash slot

redis cluster中每个master都会持有部分slot,比如有3master,那么可能每个master持有5000多个hash slot

hash slot node 的增加和移除很简单,增加一个 master ,就将其他 master hash slot 移动部分过去,减少一个master,就将它的 hash slot 移动到其他 master 上去
移动 hash slot 的成本是非常低的
客户端的 api ,可以对指定的数据,让他们走同一个 hash slot ,通过 hash tag 来实现
127.0.0.1:7000>CLUSTER ADDSLOTS 0 1 2 3 4 ... 5000 可以将槽 0-5000 指派给节点 7000 负责。
每个节点都会记录哪些槽指派给了自己,哪些槽指派给了其他节点。
客户端向节点发送键命令,节点要计算这个键属于哪个槽。
如果是自己负责这个槽,那么直接执行命令,如果不是,向客户端返回一个 MOVED 错误,指引客户端转向正确的节点。

12.redis cluster master的写入

redis cluster 写入数据的时候,其实是你可以将请求发送到任意一个 master 上去执行
但是,每个 master 都会计算这个 key 对应的 CRC16 值,然后对 16384 hash slot 取模,找到 key 对应的 hash slot ,找到hash slot 对应的 master, 如果对应的 master 就在自己本地的话, set mykey1 v1 mykey1 这个 key 对应的 hashslot 就在自己本地,那么自己就处理掉了
但是如果计算出来的 hash slot 在其他 master 上,那么就会给客户端返回一个 moved error ,告诉你,你得到哪个master上去执行这条写入的命令
什么叫做多 master 的写入,就是每条数据只能存在于一个 master 上,不同的 master 负责存储不同的数据,分布式的数据存储
100w 条数据, 5 master ,每个 master 就负责存储 20w 条数据,
分布式数据存储:默认情况下,redis cluster 的核心的理念,主要是用 slave 做高可用的,每个 master 挂一两个 slave ,主要是做数据的热备,还有master 故障时的主备切换,实现高可用的
redis cluster 默认是不支持 slave 节点读或者写的,跟我们手动基于 replication 搭建的主从架构不一样的

  • 11
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值