• 记录--redis


    1. 说一下你在项目中的redis的应用场景

    redis 有五大常用数据类型:String、List、Hash、Set、Sorted Set

    分别有各自的应用场景,一般是作为数据缓存,分布式下提供分布式锁的解决方案

    2. redis是单线程还是多线程?

    redis 不管那个版本,工作线程只有一个;6.X版本之后提供了 IO 多线程,满足 redis 的串行原子,只不过 IO 多线程后,把输入/输出放到更多的线程里去并行,执行时间段,更快,充分利用 服务器的硬件资源

    3. redis存在线程安全的问题吗?为什么?

    redis 的工作线程只有一个 ,保证串行执行的原子性,因此 redis 内部是可以保证线程安全的,但是外界使用 api 来操作 redis 时是不能保证的,需要业务上自行保障

    4. 遇到过缓存穿透吗?详细描述一下。

    缓存穿透 -- redis 中没有,db 中也没有

    解决:

      缓存 null 值:对查询结果为 null 的数据进行缓存,长期使用的话需要定期清理,设置短时限失效,例如:30——60秒,最高 5 分钟

      白名单策略:提请预热各种分类的数据 id 对应的 bitmaps,id 作为 bitmaps 的 offset,相当于设置数据白名单,当加载正常数据时放行,加载异常数据时直接拦截;只用布隆过滤器,布隆过滤器的命中问题针对恶意访问造成服务器压力可以忽略

      实时监控:实时监控 redis 命中率与 null 数据的占比:非活动时间段波动--通常检查 3-5 倍,超过 5 倍纳入重点排查对象;活动时段检查 10-50 倍,超过 50 倍纳入重点排查对象;根据倍数不同,启动不同的排出程序,然后使用黑名单进行防控。

      key 加密:对 key 进行业务层传输加密服务,设定校验程序,发现不满足规则的 key ,直接驳回数据访问。

    5. 遇到过缓存击穿吗?详细描述一下。

    缓存击穿:热点 key 过期失效,redis 没有,db 中有,没有缓存

    解决:

      1)预先设定,根据实际业务情况,加大此类 key 的过期时长;

      2)监控访问流量,对自然流量激增的数据延长过期时间或设置永久性  key

      3)后台刷新数据:启动定时任务,在高峰来临之前,刷新数据有效期,确保不丢失

      4)二级缓存:设置不同的失效时间 ,保证不会同时被淘汰

      5)加锁:分布式锁,防止被击穿

    6. 如何避免缓存雪崩?

    缓存雪崩:大量的 key 过期失效,没有被缓存

    解决:

      1)构建多级缓存架构

      2)使用锁和队列:保证不会有大量的线程对数据库一次性进程读写,从而避免缓存失效时大量的请求落到存储库上

      3)设置过期标识更新缓存:记录缓存是否过期,设置提前量,如果过期通过后台程序更新实际 key 的缓存

      4)将缓存时间分散开,错峰失效

    解决 :核心就是避免 db 层面的无效或重复请求

    • 请求 redis ,没有数据
    • 大家抢锁,时间复杂度是只发生在 redis 获取不到的情况下
      • 抢到锁的请求到 db
      • 没抢到的返回或sleep
    • db 获取到,更新 redis(针对缓存穿透可以 set key null)
    • 若是 sleep 的,唤醒重复当前流程操作
    7. Redis是怎么删除过期key的?
    8. 缓存如何回收的?

    后台在轮询(serverCron)分段分批的删除那些过期的 key

    请求的时候判断是否已经过期

    • 定时删除:对每一个设置了过期时间的 key 都创建了一个定时器,只要到达过期时间就立即删除。该策略可以立即清除过期数据,对内存友好,但是占用过多的 cpu 资源处理过期数据,会影响 redis 的吞吐量和响应时间
    • 惰性删除:当访问一个 key 的时候判断是否过期,过期删除。该策略可以最大限度的节约 cpu 资源,但是对内存不友好。极端情况下,会存在大量过期的 key 不会被访问到,占用过多内存空间
    • 定期删除:每个一段时间扫描 redis 中过期字典中的 key,进行过期 key 删除,通过调整扫描周期和扫描限定耗时,可以使 cpu 和内存资源达到最优的平衡效果
    9. 缓存是如何淘汰的

    当 redis 的内存达到 maxmemory 的极限时,会通过某种算法来决定清除掉哪些数据,这就是 redis 的缓存淘汰策略

    redis 提供 8 中缓存淘汰的策略算法:

    • volatile_lru : 在设置了过期时间的 key 空间中,移除最近最不经常使用的 key,和最后一次访问 key 的事件有关
    • allkeys-lru : 在 key 空间中,移除最近最不经常使用的 key
    • volatile-lfu : 在设置了过期时间的 key 空间中,移除最近最少使用的 key,和使用次数有关,淘汰使用次数最少的
    • allkeys-lfu : 在 key 空间中,移除最近最少使用的 key
    • volatile-random : 在设置了过期时间的 key 空间中,进行随机移除
    • allkeys-random : 在 key 空间中,进行随机移除
    • volatile-ttl : 针对设置了过期时间的健值对,根据过期时间先后进行删除,越早过期的越先删除
    • noeviction : 一旦缓冲写满了,再有新的写请求过来时,redis 不再提供服务,直接返回错误

    lru : redisObject 中维护了一个 lru 属性,记录 key 的访问时间,当从 redis 中筛选出 N 个数据,比较 lru 属性,淘汰距离现在最久的

    10. Redis 是如何持久化的?

    redis 提供两种持久化方式 rdb 和 aof

    rdb: rdb 是 redis 默认的持久化方式;按照一定的时间将内存的数据以快照的形式保存到硬盘中,通过 配置文件 save 参数来定义快照的周期

    aof:将 redis 执行的每次写命令记录到单独的日志文件中,当重启 reis 会重新将持久化的日志中文件恢复数据。当两种方式同时开启时,数据恢复优先考虑 aof 恢复,配置 no、every second、always,只会丢失一秒的数据;

    11. Redis 集群实现原理
    redis cluster 是一种服务端 sharding 技术。cluster 并没有使用一致性 hash,而是采用 slot 槽的概念,一共分成 10384 ([0, 10383])个槽。将请求发送到任意节点,接受到请求的节点会讲查询请求发送到正确的节点上执行
    说明:
      通过 hash 的方式,将数据分片,每个节点均分存储一定哈希槽区间的数据,默认分配了 16384 个槽;
      每份数据分片会存储在多个互为主从的多节点上
      数据写入先写入主节点,再同步到从节点;
      同一分片多个节点间的数据不保持一致性;
      读取数据时,当客户端操作的 key 没有分配在该节点上时,redis 会返回转向指令,指向正确的节点;
      扩容时需要把旧节点的数据迁移一部分到新节点
    redis cluster 架构下,每个 redis 需要开发两个端口,如 6379,16379;16379 用来进行节点间通信,进行故障检查、配置更新、故障转移授权。使用二进制 gossip 协议,用于节点间进行高效的数据交换,占用更少的网络宽带和处理时间 
    12. Redis 与 MySQL 的双写一致性是如何保证的

    延时双删:先删除缓存,再更新数据库,在等待具体读业务逻辑数据的耗时+几百毫秒后,再次删除缓存

    删除缓存重试机制:若是第二次删除失败了,那么缓存数据和持久化还是不一致的,所以引入删除缓存重试机制,将删除失败的key放到消息队列中,将要删除的key拉去出来做重试删除的操作

    读取binlog异步删除缓存:可以将 binlog 日志采集发送到 mq 队列中,通过 ack 确认送达机制处理这条更新消息,删除缓存,保证数据缓存一致性

    为什么要删除缓存而不用更新呢  -- 线程 A 发起一个写操作,先更新了数据库 ,线程 B 发起一个写操作 ,在更新了数据库,由于网络原因,线程 B 先更新了缓存,而后线程 A 更新了缓存,导致缓存保存的还是 A 的数据。

    更新缓存相对于删除缓存:1)如果写入的缓存值,是经过复杂计算才得到的话,更新缓存频率高的话,就浪费性能了 ;2)在写数据库场景多,读数据场景少的情况下,数据很多时候还没被读取到,又被更新了,这也浪费性能

    13. redis 为什么快?

      1)绝大部分请求是存粹的内存操作,基于内存的操作响应非常快速;

      2)redis工作现场是单线程的,避免了不必要的上下文切换和竞争条件;

      3)redis 才用非阻塞 IO 多路复用 epoll 模型,减少了 IO 操作上的损耗时间

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

      使用 keys 命令可以扫出指定模式的 key 列表;但是 redis 是单线程的 keys 指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复,这个时候可以使用 scan 指令,scan 指令可以无阻塞的提取出指定模式的 key 列表,但是会有一定的重复概率,但是整体所花费的时间会比直接用 keys 指令长。

  • 相关阅读:
    ubuntu16.04系统安装
    SQL注入之Sqli-labs系列第二十六关(过滤空格、注释符、逻辑运算符注入)和第二十六A
    提权心法(2)提权基本流程
    布尔盲注
    提权心法(1)信息搜集很重要
    POST注入-双注入
    POST型注入-报错注入
    字符型注入
    Web中间件常见安全漏洞总结
    SSRF 从入门到批量找漏洞
  • 原文地址:https://www.cnblogs.com/zhuozhang/p/14884647.html
Copyright © 2020-2023  润新知