redis系列题目总结

作者: 机智的老刘明同志 | 来源:发表于2020-06-20 18:06 被阅读0次

    1. 关系型与非关系型数据库对比?

            关系型数据库是依据关系模型(一对一、一对多、多对多)来创建的数据库。     优点:支持复杂查询,事务回滚
            非关系型模型:列模型,键值对模型(memcache,redis),文档类模型(mongodb)。     优点:不需要解析性能高,耦合低可扩展性好。

    2. redis优点:

            1.数据存在内存中速度快。类似HashMap,查找和操作的时间复杂度都是O(1)。
            2.支持丰富数据类型,string,linked-list(lpop是线程不安全的,可使用blpop),set,zset(sorted sets),hash,bitMap(位图,本质字符串但可以对位进行操作),GEO(地理位置),hyperloglogs(基数统计,基数数量大时耗费的空间很小)
            3.支持事务(不会回滚),操作都是原子性
            4.丰富的特性,缓存,过期时间等。

    3. redis淘汰策略:  

            maxmemory <bytes>  最大物理内存,超出则启用redis淘汰策略
            maxmemory-policy noeviction 淘汰策略

                volatile-lru:从已设置过期的数据集中挑选最近最少使用的淘汰
                volatile-ttr:从已设置过期的数据集中挑选将要过期的数据淘汰
                volatile-random:从已设置过期的数据集中任意挑选数据淘汰
                allkeys-lru:从数据集中挑选最近最少使用的数据淘汰
                allkeys-random:从数据集中任意挑选数据淘汰
                noenviction:禁止淘汰数据

    4. redis哈希槽:

            Redis 集群有16384个哈希槽(一个节点可能有一个或多个槽,因此最大节点个数:2^14 = 16384)
            通过公式:crc16(key) mod 16384 决定key放置在哪个槽上。

            优点:实现简单,容易增删节点,不用停掉redis服务。新增时只需要把其他节点的某些哈希槽挪到新节点即可。删除反之

    5. 缓存穿透(缓存和db中都没有):

            1. 布隆过滤器(对一个key进行多种hash算法,将结果存贮在一亿位上。对于新key只需要判断每种hash算法结果位上是否有值)
            2. 缓存空对象(有效期略短)

    6. 缓存击穿(热点数据失效后,大量访问)

            1. 热点数据永不失效
            2. 线程加锁

    7. 缓存雪崩

            1. 失效时间加个随机值
            2. 热点数据永不失效
            3. 热点数据均匀分布在不同的 Redis 库(高可用性Redis集群,防止宕机)

    8. 分布式锁

            setnx加锁,del删除锁,expire设置过期时间防止无法释放造成的死锁

    9. redis异步队列:

            定时任务。list 结构,rpush 生产消息,lpop 消费消息。当 lpop 没有消息的时候,要适当 sleep 再重试(空轮询拉高客户端的CPU)

    10. 持久化

            rdb:快照,保存在dump.rdb中(默认方式)
            aof:增量,保存redis命令到appendonly.aof中

    11. 缓存和数据库一致性解决方案:

            情况1:先删除缓存再写入数据库。写入时,其他进程进来读取了老数据写入了缓存。此时缓存中为脏数据。
            情况2:先写入数据库再删除缓存。如果写入成功后,删除缓存前服务器宕机了。此时缓存中也为脏数据。

            方案1:延时双删 + 有效期设置:a.先删除缓存,b.再写入数据库,c.休眠500毫秒,d.再删除缓存。
            方案2:异步更新缓存:mysql binlog增量订阅消费+消息队列+增量数据更新到redis(阿里的canal框架)

    12. 如何理解redis单线程非阻塞?

            单线程:避免了不必要的上下文切换和竞争条件。
            非阻塞IO:IO多路复用,Redis采用epoll做为I/O多路复用技术的实现,再加上Redis自身的事件处理模型将epoll中的连接,读写,关闭都转换为时间,不在I/O上浪费过多的时间。

    13.主从配置:

            从服务配置:slaveof    <masterip>    <masterport>

    14. 哨兵

            作用:1.监测主数据库和从数据库是否正常运行。2.当主数据库出现故障的时候,自动将一个从库转换为主库

            步骤:哨兵监控也是有集群的,会有多个哨兵进行监控,当判断发生故障的哨兵达到一定数量的时候才进行修复。一个健壮的部署至少需要三个哨兵实例。

            1.每个Sentinel  1s/次 向它所知的Master,Slave以及其他 Sentinel 实例发送一个 PING 命令
            2.如果实例距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 所指定的值, 则这个实例会被 Sentinel 标记为主观下线
            3.如果一个 Master 被标记为主观下线,则正在监视这个 Master 的所有 Sentinel 要以每秒一次的频率确认 Master 的确进入了主观下线状态
            4.当有足够数量的 Sentinel(≥配置文件指定值)在指定的时间范围内确认Master的确进入了主观下线状态, 则Master会被标记为客观下线
            5.在一般情况下, 每个 Sentinel 会以每 10 秒一次的频率向它已知的所有 Master,Slave 发送 INFO 命令(1.发现 slave 节点,2.确定主从)
            6.当Master被 Sentinel 标记为客观下线时,Sentinel 向下线的 Master 的所有 Slave 发送 INFO 命令的频率会从 10s/次 改为 1s/次
            7.若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会被移除。若 Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除。

    15. 性能与调优:

            1.Redis异步尽量不要用,因为Redis延迟本身很小,大概在100us-200us。另外Redis是单线程的,异步任务切换的耗时比网络耗时还要大
            2.在Linux上多实例部署,实例个数等于处理器个数,各实例最大内存直接为本机物理内存,避免单个实例内存撑爆
            3.把海量数据(10亿+)根据key哈希(Crc16/Crc32)存放在多个实例上(哈希槽),读写性能成倍增长。
            4.采用二进制序列化,而非常见的Json序列化。
            5.Redis的主要性能瓶颈是序列化、网络带宽和内存大小,滥用时处理器也会达到瓶颈。
            6.Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件。如果数据比较重要,在某个Slave上开启AOF备份数据,策略设置为每秒同步一次。
            7.主从复制不要用图状结构,使用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3...这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。

    16. redis zset跳跃表:

    17. Redis,MongoDB,Memcached 对比:

    18. redis LRU算法实现:

            LRU的经典实现:

                hashMap + 双向Linkedlist

            Redis的近似LRU实现:

                redis嫌弃LinkedList占用的空间太大。在redisObjct中存储了对象最后一次被命令程序访问的时间。

                当需要移除Key时,随机取N个(配置项maxmemory-samples,默认为5)Key的空闲时间与缓冲池(默认有16个key会按照空闲时间排好序)里的空闲时间最小的key作对比。如果大于则加入到缓冲池中。同时淘汰的时候会从pool中选择空闲时间最大的key淘汰掉。

    19. pipeline:

            每个命令的执行时间 = 客户端到服务器的时间+命令排队的时间+命令真正执行时间+结果从服务器到客户端的时间。第一个和第四个消耗的时间总和称为RTT

            不使用管道的时候,批量操作1000条数据所需要的时间是:1000次RTT时间+1000次命令执行时间

            使用pipeline操作一次传递命令时,所需要的时间是1次RTT时间+1000次命令执行时间:

    相关文章

      网友评论

        本文标题:redis系列题目总结

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