• Redis


    Redis(Remote dictionary service 远程字典服务)

    特性

    • 快  -- 内存型数据库 key-value
    • 持久化  -- 过期、淘汰策略
    • 高可用 集群 
    • 单线程命令执行
    • IO多路复用

    Redis内部数据的存储结构-redis Object

    1、结构体定义:

    1. typedef struct redisObject {
    2. unsigned type;
    3. unsigned encoding;
    4. unsigned lru;
    5. int refcount;
    6. void *ptr;
    7. } robj;

    2、字段说明

            type: 数据类型

            encoding: 内部编码

            lru: 如果是LRU 设置的是全局的lru_clock的值 即是最近访问时间

                  如果是LFU,低8位设置的是使用次数(频率),高16位设置的是访问时间

            refcount: 引用数,如果为0说明现在这个value没人引用,可以回收


    Redis五大数据类型

    1、String

        内部编码(转换不可逆)

    1.  int -- 8字节长整型 redis.conf文件中可配
    2. raw -- 44字节以上
    3. embstr -- 44字节以下 只读

    2、hash(可以存储对象类型数据)

    key和value中间有一个field(小key)但是field不能设置过期时间   

     内部编码

    1.  ziplist
      1. 类似于双向链表,不同的是ziplist指向的是指针并不是具体的数据。典型的时间换空间
      2. 所以只能用在数据比较小的地方
      3. 64字节 数量<512
    2. hashtable
      1. 数组+链表的结构
      2. 可以扩容 有两个数组ht[0]和ht[1]
        1. 先为ht[1]分配空间 = ht[0].used*2
        2. ht[1]=ht[0]
        3. ht[0]删除
        4. ht[1]改为ht[0],创建新的ht[1]

    3、list(有序可以重复)

     内部编码

    1.  quicklist(双向链表+ziplist组成)

    4、set(无序集合)

    内部编码

    1.  intset 存储的都是整数类型的数据
    2. hashtable

    5、zset(有序集合)

    内部编码

    1. ziplist
    2. skiplist(跳表)
      1. 有一个level属性,给数据随机分层

    过期策略

    1、定时过期 -- redis没有用

            redis自己去定时判断key是否过期,对内存友好但是对cpu不友好,影响缓存的响应时间和吞吐量

    2、惰性过期

            当key被动访问的时候,才会去判断是否过期。对cpu友好但是对内存不友好

    3、定期过期(redis采用了这种策略)

            每个一段时间去请求判断是否有过期的key,key 的过期时间室友单独存放的

            具体的操作:( 触发--serverCron  执行频率--hz 10[每1秒执行10次] )

    1. 从所有设置了过期时间的key中取20个
    2. 删除这20个key里面已经过期的数据
    3. 删除后,计算过期键的比例,如果超过25%(有1/4以上过期)重复操作1 2 

    淘汰策略

    1、LRU(least recently used 最近未使用)

            通过最近被使用的时间,来判断最久没有被使用的可以然后进行淘汰

            算法:-- 计算key没有被使用的时间

    1. 首先系统里有一个server.lruclock字段,它serverCron每次执行完后被更新,所以它是一个延迟100ms的系统时间
    2. 计算没有被使用的时间,比较server.lruclock和redisObject.lru

            if(server.lruclock>=redisObject.lru)  server.lruclock-redisObject.lru

            else server.lruclock+(LRU_CLOCK_MAX-redisObject.lru)

            redisObject.lru在每次创建或访问时,都会把server.lruclock赋值

            LRU_CLOCK_MAX 是lru的最大值 24位

             server.lruclock如果超过最大值,就会重新开始计算,所以存在else的情况

            问题:仅根据最后的使用时间淘汰不合理

    此时,淘汰第一个并不合理

    2、LFU(least frequently used)最不常用

    根据次数和访问时间进行判断

    redis.conf中的相关配置:

    lfu-log-factory  10     次数的增长频率因子

    lfu-decay-time  10     每分钟没有访问次数减少10


    持久化机制

            为什么要持久化?

            redis是内存数据库,宕机数据会丢失。

    1、RDB

            将当前内存中的数据快照写入磁盘,恢复时将文件直接读到内存

            redis.conf配置

    1. dbfilename   dump.rdb   快照文件名称
    2. dir    ./    文件生成位置--默认在启动目录下

            自动触发

                    save 900 1           900s内至少有一个key被修改

                    save 300 10         300s内至少有10个key被修改

                    save 60 10000     60m内至少有10000个key被修改

            手动触发

                    shutdown

                    flushall

                    save指令 生成RDB文件会阻塞Redis服务器,不能处理其他命令

                    bgsave 主进程通过fork一个子进程去处理,主进程不用进行任何磁盘I/O操作

            命令

                    stop-writes-on-bgsave-error: yes

    • 当启用RDB且最后一次数据保存失败,Redis是否停止接收数据。让用户意识到数据没有正确持久化到硬盘上,如果Redis重启,又可以重新接收数据了。

            优点

                    比AOF快,保存的是某个时间点的数据集

            缺点       

    • 无法做到实时备份,数据可能会丢失,因为是每隔一段时间做的。保存的是二进制的数据,无法直接查看文件内容。

    2、AOF

            配置

    • appendonly on 是否开启(默认不开启)
    • appendfilename   "appendfile.aof"   文件名
    • appendfsync  everysec   AOF持久化策略(默认everysec)
    1. no(表示不执行fsync,由操作系统保证数据同步到磁盘。速度快但是不太安全)
    2. always(表示每次写入都执行fsync,以保证数据同步到磁盘。效率低)
    3. everysec(表示每秒执行一次fsync,可能会导致丢失1s数据,但是兼顾效率和安全性)

            问题:AOF是命令追加,所以会导致文件很大

            解决:重写AOF

            配置

    1. auto-aof-rewrite-percentage  100(当目前文件大小超过上次重写的aof文件的百分之多少进行重写,默认100)
    2. auto-aof-rewrite-min-size  64(设置允许重写的最小AOF文件的大小,默认64M)

                    避免达到了约定百分比但文件大小仍然很小的情况(避免不需要的重写)

            重写机制

    • 当需要重写时,Redis会fork一个子进程去处理,首先读取内存中的数据,重新写到一个临时的文件中。
    • 在子进程执行AOF重写时,主进程也要做一些事情
    1. 处理客户端发过来的命令请求
    2. 将写命令追加到现有的AOF文件中
    3. 将写命令追加到AOF重写缓存中
    • 当子进程重写完后,会发一个信号给主进程,主进程收到后悔调用信号处理函数(会Block主进程)执行以下工作:
    1. 将AOF重写缓存区中的数据全部写入新的AOF文件中
    2. 对新的AOF文件进行改名,新旧替换

            RDB和AOF可以同时开启,在数据恢复时用AOF

  • 相关阅读:
    羽夏壳世界—— PE 结构(上)
    聊聊 13 种锁的实现方式
    Android 监听网络状态变化
    基于动态规划法的水力发电优化调度(Python代码实现)
    一种跳板机的实现思路
    POJ2031空间站题解
    m基于MATLAB的通信系统仿真,包括信号源,载波信号,放大器,带宽滤波器,接收端包括放大器,带宽滤波器,载波解调,低通滤波器等
    CentOS7安装配置Kafka3.2.0(含SpringBoot连接测试)
    斜率优化dp
    Android 12(S) 图像显示系统 - HWC HAL 初始化与调用流程
  • 原文地址:https://blog.csdn.net/m0_37998944/article/details/125956363