zoukankan      html  css  js  c++  java
  • Redis知识点

    1. 应用场景

    缓存:根据键值过期时间设置

    请求频率限制:比如短信验证码120秒内只能发送一次,则将标志性的key-value键值对设置过期时间为120秒,用户请求的时候判断一下【SET key value EX 120 NX

    排行榜:利用zset数据类型

    计数器:利用 INCR KEY 命令,key不存在初始化为0,存在则自增1

    用户爱好:利用set集合,其特有的命令方法能够计算用户共同爱好

    消息队列:利用list数据类型的lpush和brpop

    分布式锁:利用 SET key value [EX seconds] [PX milliseconds] [NX|XX] 

    2.速度快的原因

    • 纯内存访问
    • 数据结构简单
    • 底层I/O用多路复用模型实现,利用epoll去监听多个流的IO事件:空闲的时候,线程是阻塞的;如果有一个或者多个事件到达,线程被唤醒,开始轮询并处理那些发生了事件的流。
    • 单线程避免了线程切换和竞争,也不用考虑加锁的问题

    3. 数据类型

    • 字符串(String):内部编码【8个字节长整型:int】【小于等于39个字节的字符串:embstr】【大于39个字节的字符串:raw】
    • 哈希(Hash):内部编码【元素个数小于512个并且每个值都小于64字节:ziplist-压缩列表】【否则是hashtable-哈希表】
    • 列表(List):内部编码【元素个数小于512个并且每个值都小于64字节:ziplist-压缩列表】【否则是linkedlist-链表】
    • 集合(Set):内部编码【元素都是整数并且个数小于512个:intset-整数集合】【否则是hashtable-哈希表】
    • 有序集合(ZSet):内部编码【元素个数小于128个并且每个值都小于64字节:ziplist-压缩列表】【否则是skiplist-跳跃表】

    4. 持久化-RDB

    触发:save或者bgsave命令。不同的是save会阻塞服务器,直到持久化完成;bgsave会fock子进程,子进程负责完成持久化的任务,这种只在fock的时候会阻塞很短一部分时间。

    RDB持久化流程:

    • 执行bgsave命令,如果已存在相关的子进程,则直接返回。
    • 父进程执行fock操作创建子进程。fock完成后不再阻塞父进程。
    • 子进程创建RDB文件,根据父进程的内存生成临时快照文件,完成后对原有文件进行原子替换。
    • 最后给父进程发送完成信号,父进程更新统计信息。

    Redis默认采用LZF算法对生成的RDB文件做压缩处理,压缩后的文件远远小于内存大小。

    5. 持久化-AOF

    工作流程:

    • 命令写入:所有的写入命令都会追加到AOF缓冲区(处于性能的考量,不追加到硬盘)
    • 文件同步:缓冲区根据对应的策略向硬盘做同步操作(策略:always,everysec,no,默认everysec)
    • 文件重写:AOF文件越来越大,所以定期对AOF文件进行重写,达到压缩的目的(无效命令比如del、set,文件只保留最终数据的写入命令;多条命令合并成一条)
    • 重启加载:Redis服务器重启后,会根据AOF文件进行数据恢复

    AOF重写流程:

    首先主进程会fock一个子进程。Redis会维护一个AOF重写缓冲区,该缓冲区会在子进程创建新的AOF文件期间,记录服务器执行的所有写命令。当子进程完成创建新AOF文件之后,服务器会将重写缓冲区中的所有内容追加到新的AOF文件的末尾。最后,服务器用新的AOF文件替换旧的AOF文件,以此来完成AOF文件重写操作。

    如果同时配置了RDB和AOF,则Redis会优先加载AOF

    6. 数据分区

    分布式环境下要解决把数据映射到多个节点的问题。

    A:节点取余分区

    【对key取hash】%【节点数量】,来决定数据打到哪一个节点上。

    B:一致性哈希分区

    为系统中每个节点分配一个token,范围为2的32次幂,这些token构成一个hash环。读写数据的时候,根据key取hash,然后顺时针找到第一个大于等于该hash值的token所对应的节点。

    一致性哈希存在的问题:

    • 加减节点会导致一部分数据无法命中,需要手动处理或者忽略,所以一致性哈希常用语缓存场景。
    • 节点比较少的情况,节点发生变化将影响很大一部分数据命中,所以不适合节点少的情况。

    C:虚拟槽分区

    Redis Cluser采用虚拟槽分区,所有的键根据哈希函数映射到0~16383整数槽内,计算公式:slot=CRC16(key)&16383。每一个节点负责维护一部分槽以及槽所映射的键值数据

    优点:解耦数据和节点之间的关系,简化了节点扩容和收缩难度。

    7. 集群功能限制

    不支持批量操作比如:mget,mset

    不支持多数据库空间,即只有一个db0

    8. 缓存穿透

    原因:请求不存在的数据,而导致每次请求都要跳过缓存直接去存储层拿数据,失去了缓存保护后端存储的意义。

    解决:

    • 方法一:存储层不命中,依然缓存空对象,之后再访问这个数据就会从缓存中获取。可是:如果是恶意攻击,意味着这部分无意义的数据会占用内存,可以通过设置过期时间来缓解。
    • 方法二:利用布隆过滤器把存在的key缓存起来,作为访问的第一层,之后才是缓存和数据库,如果布隆过滤器认为请求的key不存在,则不会访问数据库,进而保护了存储层。
    • 比较:存储空对象适用于:数据频繁变化实时性高的场景。布隆过滤器适用于:数据相对固定实时性低的场景。

    9. 缓存击穿

    原因:比如有个热点key承载了大量请求,在key失效的一瞬间,大量请求跳过缓存直接去请求了数据库

    解决:

    • 方法一:一般是因为做促销活动导致key成为这种热点,对于这类key要么设置过期时间长一些以至于熬过高峰期,要么直接设置成永不过期。
    • 方法二:加互斥锁,即如果缓存不存在,则加锁去读取数据库并更新缓存,保证失效的时候只有一个线程能去访问数据库。

    10. 缓存雪崩

    原因:

    • 在同一时间点,承载大量请求的缓存集中失效,大量请求会到达存储层,进而造成存储层压力过大而宕机。
    • 缓存层由于异常不能提供服务后,大量请求会到达存储层,进而造成存储层压力过大而宕机。

    解决:

    • 保证缓存服务高可用
    • 将key的过期时间设置随机,这样避免同一时间大量失效

    11. 淘汰策略(6种)

    这6种策略的前提都是:当内存不足以容纳新写入数据时

    noeviction:新写入操作会报错(默认策略)

    范围:在主键空间中

    allkeys-lru:移除最近最少使用的key

    allkeys-random:随机移除某个key

    范围:在设置了过期时间的键空间中

    volatile-lru:移除最近最少使用的key

    volatile-random:随机移除某个key

    volatile-ttl:有更早过期时间的key优先移除

  • 相关阅读:
    java常用类
    java throw和catch同时使用
    HTML5 input 类型: email及url
    Android中集成支付宝
    HTML5 预加载
    SQLite数据库
    Android开发中如何加载API源码帮助开发
    Java中的static
    HTML5 Web Storage 特性
    gdal1.10编译经验
  • 原文地址:https://www.cnblogs.com/LUA123/p/12877791.html
Copyright © 2011-2022 走看看