Redis 的键管理

2023-12-19

一、Redis 数据库管理

Redis 是一个键值对(key-value pair)的数据库服务器,其数据保存在 src/server.h/redisDb 中(网上很多帖子说在 redis.h 文件中,但是 redis 6.x版本目录中都没有这个文件。redisDb 结构应该在 server.h文件中)

typedef redisServer {
    ....
    
    // Redis数据库
    redisDb *db;
    
    ....
}

Redis 默认会创建 16 个数据库,每个数据库是独立互不影响。其默认的目标数据库是 0 号数据库,可以通过 select 命令来切换目标数据库。在 redisClient 结构中记录客户端当前的目标数据库:

typedef struct redisClient {

    // 套接字描述符
    int fd;

    // 当前正在使用的数据库
    redisDb *db;

    // 当前正在使用的数据库的 id (号码)
    int dictid;

    // 客户端的名字
    robj *name;             /* As set by CLIENT SETNAME */

} redisClient;

下面是客户端和服务器状态之间的关系实例,客户端的目标数据库目前为 1 号数据库:

通过修改 redisClient.db 的指针来指向不同数据库,这也就是 select 命令的实现原理。但是,到目前为止,Redis 仍然没有可以返回客户端目标数据库的命令。虽然在 redis-cli 客户端中输入时会显示:

redis> SELECT 1
Ok
redis[1]> 

但是在其他语言客户端没有显示目标数据库的号端,所以在频繁切换数据库后,会导致忘记目前使用的是哪一个数据库,也容易产生误操作。因此要 谨慎处理多数据库程序 ,必须要执行时,可以先显示切换指定数据库,然后再执行别的命令。

二、Redis 数据库键

2.1 数据库键空间

Redis 服务器中的每一个数据库是由一个 server.h/redisDb 结构来表示的,其具体结构如下:

typedef struct redisDb {
    //数据库键空间
    dict *dict;                 /* The keyspace for this DB */
    //键的过期时间,字典的值为过期事件 UNIX 时间戳
    dict *expires;              /* Timeout of keys with a timeout set */
    //正处于阻塞状态的键
    dict *blocking_keys;        /* Keys with clients waiting for data (BLPOP)*/
    //可以解除阻塞的键
    dict *ready_keys;           /* Blocked keys that received a PUSH */
    //正在被 WATCH 命令监视的键
    dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS */
    //数据库号端
    int id;                     /* Database ID */
    //数据库键的平均 TTL,统计信息
    long long avg_ttl;          /* Average TTL, just for stats */
    //
    unsigned long expires_cursor; /* Cursor of the active expire cycle. */
    list *defrag_later;         /* List of key names to attempt to defrag one by one, gradually. */
} redisDb;

键空间和用户所见的数据库是直接对应:

  • 键空间的 key 就是数据库的 key, 每个 key 都是一个字符串对象
  • 键空间的 value 是数据库的 value, 每个 value 可以是字符串对象、列表对象和集合对象等等任意一种 Redis 对象

举个实例,若在空白数据库中执行一下命令:插入字符串对象、列表对象和哈希对象

# 插入一个字符串对象
redis> SET message "hello world"
OK
# 插入包含三个元素的列表对象
redis> RPUSH alphabet "a" "b" "c"
(integer)3
# 插入包含三个元素的哈希表对象
redis> HSET book name "Redis in Action"
(integer) 1
redis> HSET book author "Josiah L. Carlson"
(integer) 1
redis> HSET book publisher "Manning"
(integer) 1

所以说 redis 对数据的增删改查是通过操作 dict 来操作 Redis 中的数据

2.2 数据库键的过期

我们可以通过两种方式设置键的生命周期:

  • 通过 EXPIRE 或者 PEXPIRE 命令来 为数据库中的某个键设置生存时间 (TTL,Time To Live)。在经过 TTL 个生存时间后,服务器会自动删除生存时间为0 的键。比如:

    redis> set key value
    OK
    # 设置键的 TTL 为 5
    redis> EXPIRE key 5
    (integer)1
    
  • 此外,客户端也可以通过 EXPIREAT 或者PEXPIREAT 命令,为数据库中的某个键设置过期时间(expire time)。过期时间是一个 UNIX 时间戳,当过期时间来临时,服务器就会自动从数据库中删除这个键。比如

    redis> SET key value
    OK
    redis> EXPIREAT key 1377257300
    (integer) 1
    # 当前系统时间
    redis> TIME
    1)"1377257296"
    # 过一段时间后,再查询key 
    redis> GET key // 1377257300
    (nil)
    
2.2.1 过期时间

redisDb 中的 dict *dict dict *expires 字典 分别保存了数据库中的键和键的过期时间,分别叫做 键空间 过期字典

  • 过期字典的键是一个指向键空间中的某个键对象
  • 过期字典的值是一个 long long 类型的整数,这个整数保存了键所指向的数据库键的过期时间

2.3 过期键的删除策略

对于已经过期的数据是如何删除这些过期键的呢?主要有两种方式:惰性删除和定期删除:

1.惰性删除

是指 Redis 服务器不主动删除过期的键值,而是通过访问键值时,检查当前的键值是否过期

  • 如果过期则执行删除并返回 null
  • 没有过期则正常访问值信息给客户端

惰性删除的源码在 src/db.c/expireIfNeeded 方法中

int expireIfNeeded(redisDb *db, robj *key) {

    // 判断键是否过期

    if (!keyIsExpired(db,key)) return 0;

    if (server.masterhost != NULL) return 1;

    /* 删除过期键 */

    // 增加过期键个数

    server.stat_expiredkeys++;

    // 传播键过期的消息

    propagateExpire(db,key,server.lazyfree_lazy_expire);

    notifyKeyspaceEvent(NOTIFY_EXPIRED,

        "expired",key,db->id);

    // server.lazyfree_lazy_expire 为 1 表示异步删除,否则则为同步删除

    return server.lazyfree_lazy_expire ? dbAsyncDelete(db,key) :

                                         dbSyncDelete(db,key);

}

// 判断键是否过期

int keyIsExpired(redisDb *db, robj *key) {

    mstime_t when = getExpire(db,key);

    if (when < 0) return 0; 

    if (server.loading) return 0;

    mstime_t now = server.lua_caller ? server.lua_time_start : mstime();

    return now > when;

}

// 获取键的过期时间

long long getExpire(redisDb *db, robj *key) {

    dictEntry *de;

    if (dictSize(db->expires) == 0 ||

       (de = dictFind(db->expires,key->ptr)) == NULL) return -1;

    serverAssertWithInfo(NULL,key,dictFind(db->dict,key->ptr) != NULL);

    return dictGetSignedIntegerVal(de);

}
2.定期删除

与惰性删除不同,定期删除是指 Redis 服务器会每隔一段时间就会检查一下数据库,看看是否有过期键可以清除,默认情况下,Redis 定期检查的频率是每秒扫描 10 次,这个值在 redis.conf 中的 “hz” , 默认是 10 ,可以进行修改。

定期删除的扫描并不是遍历所有的键值对,这样的话比较费时且太消耗系统资源。Redis 服务器采用的是随机抽取形式,每次从过期字典中,取出 20 个键进行过期检测,过期字典中存储的是所有设置了过期时间的键值对。如果这批随机检查的数据中有 25% 的比例过期,那么会再抽取 20 个随机键值进行检测和删除,并且会循环执行这个流程,直到抽取的这批数据中过期键值小于 25%,此次检测才算完成。

定期删除的源码在 expire.c/activeExpireCycle 方法中:

void activeExpireCycle(int type) {

    static unsigned int current_db = 0; /* 上次定期删除遍历到的数据库ID */

    static int timelimit_exit = 0;      

    static long long last_fast_cycle = 0; /* 上次执行定期删除的时间点 */

    int j, iteration = 0;

    int dbs_per_call = CRON_DBS_PER_CALL; // 需要遍历数据库的数量

    long long start = ustime(), timelimit, elapsed;

    if (clientsArePaused()) return;

    if (type == ACTIVE_EXPIRE_CYCLE_FAST) {

        if (!timelimit_exit) return;

        // ACTIVE_EXPIRE_CYCLE_FAST_DURATION 快速定期删除的执行时长

        if (start < last_fast_cycle + ACTIVE_EXPIRE_CYCLE_FAST_DURATION*2) return;

        last_fast_cycle = start;

    }

    if (dbs_per_call > server.dbnum || timelimit_exit)

        dbs_per_call = server.dbnum;

    // 慢速定期删除的执行时长

    timelimit = 1000000*ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC/server.hz/100;

    timelimit_exit = 0;

    if (timelimit <= 0) timelimit = 1;

    if (type == ACTIVE_EXPIRE_CYCLE_FAST)

        timelimit = ACTIVE_EXPIRE_CYCLE_FAST_DURATION; /* 删除操作花费的时间 */

    long total_sampled = 0;

    long total_expired = 0;

    for (j = 0; j < dbs_per_call && timelimit_exit == 0; j++) {

        int expired;

        redisDb *db = server.db+(current_db % server.dbnum);

        current_db++;

        do {

            // .......

            expired = 0;

            ttl_sum = 0;

            ttl_samples = 0;

            // 每个数据库中检查的键的数量

            if (num > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP)

                num = ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP;

            // 从数据库中随机选取 num 个键进行检查

            while (num--) {

                dictEntry *de;

                long long ttl;

                if ((de = dictGetRandomKey(db->expires)) == NULL) break;

                ttl = dictGetSignedInteger

                // 过期检查,并对过期键进行删除

                if (activeExpireCycleTryExpire(db,de,now)) expired++;

                if (ttl > 0) {

                    ttl_sum += ttl;

                    ttl_samples++;

                }

                total_sampled++;

            }

            total_expired += expired;

            if (ttl_samples) {

                long long avg_ttl = ttl_sum/ttl_samples;

                if (db->avg_ttl == 0) db->avg_ttl = avg_ttl;

                db->avg_ttl = (db->avg_ttl/50)*49 + (avg_ttl/50);

            }

            if ((iteration & 0xf) == 0) { /* check once every 16 iterations. */

                elapsed = ustime()-start;

                if (elapsed > timelimit) {

                    timelimit_exit = 1;

                    server.stat_expired_time_cap_reached_count++;

                    break;

                }

            }

            /* 判断过期键删除数量是否超过 25% */

        } while (expired > ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP/4);

    }

    // .......

}

以上就是Redis 的删除策略。下面来看一个面试题:

面试题:你知道 Redis 内存淘汰策略和键的删除策略的区别吗?

Redis 内存淘汰策略

我们可以通过 config get maxmemory-policy 命令来查看当前 Redis 的内存淘汰策略:

127.0.0.1:6379> config get maxmemory-policy

1) "maxmemory-policy"

2) "noeviction"

当前服务器设置的是 noeviction 类型的,对于 redis 6.x版本,主要有以下几种内存淘汰策略

  • noeviction:不淘汰任何数据,当内存不足时,执行缓存新增操作会报错,它是 Redis 默认内存淘汰策略。
  • allkeys-lru:淘汰整个键值中最久未使用的键值。
  • allkeys-random:随机淘汰任意键值。
  • volatile-lru:淘汰所有设置了过期时间的键值中最久未使用的键值。
  • volatile-random:随机淘汰设置了过期时间的任意键值。
  • volatile-ttl:优先淘汰更早过期的键值。
  • volatile-lfu: 淘汰所有设置了过期时间的键值中最少使用的键值。
  • alkeys-lfu: 淘汰整个键值中最少使用的键值

也就是 alkeys 开头的表示从所有键值中淘汰相关数据,而 volatile 表示从设置了过期键的键值中淘汰数据。

Redis 内存淘汰算法

内存淘汰算法主要分为 LRU 和 LFU 淘汰算法

LRU(Least Recently Used) 淘汰算法

是一种常用的页面置换算法,LRU 是基于链表结构实现,链表中的元素按照操作顺序从前往后排列。最新操作的键会被移动到表头,当需要进行内存淘汰时,只需要删除链表尾部的元素。

Redis 使用的是一种近似 LRU 算法,目的是为了更好的节约内存,给现有的数据结构添加一个额外的字段,用于记录此键值的最后一次访问时间。 Redis 内存淘汰时,会使用随机采样的方式来淘汰数据,随机取5个值,然后淘汰最久没有使用的数据。

LFU(Least Frequently Used)淘汰算法

根据总访问次数来淘汰数据,核心思想是 如果数据过去被访问多次,那么将来被访问的频率也更高

参考资料

《Redis 设计与实现》
https://kaiwu.lagou.com/course/courseInfo.htm?courseId=59#/detail/pc?id=1779

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Redis 的键管理 的相关文章

  • Redis Docker compose无法处理RDB格式版本10

    我无法在 docker compose 文件中启动 redis 容器 我知道docker compose文件没问题 因为我的同事可以成功启动项目 我读到有一个删除 dump rdb 文件的解决方案 但我找不到它 我使用Windows机器 任
  • Lua中按字符分割字符串

    我有像这样的字符串 ABC DEF 我需要将它们分开 字符并将两个部分分别分配给一个变量 在 Ruby 中 我会这样做 a b ABC DEF split 显然Lua没有这么简单的方法 经过一番挖掘后 我找不到一种简短的方法来实现我所追求的
  • 2 个具有共享 Redis 依赖的 Helm Chart

    目前 我有 2 个 Helm Charts Chart A 和 Chart B Chart A 和 Chart B 对 Redis 实例具有相同的依赖关系 如Chart yaml file dependencies name redis v
  • 有没有办法用Lettuce自动发现Redis集群中新的集群节点IP

    我有一个Redis集群 3主3从 运行在一个库伯内斯簇 该集群通过Kubernetes 服务 Kube 服务 我将我的应用程序服务器连接到 Redis 集群 使用Kube 服务作为 URI 通过 Redis 的 Lettuce java 客
  • Spring Data JPA Redis:无法编写基于自定义方法的查询

    我已经使用 Redis 配置了 Spring Data JPA 并使用RedisRepositorieswith 提供了类似的方法find findAll 所有这些方法似乎都工作得很好 但我无法编写我的自定义方法 RedisEntity f
  • Amazon Elasticache Redis 集群 - 无法获取端点

    我需要获取 Amazon Elasticache 中 Redis 集群的终端节点 以下代码适用于 Memcached 集群 但不适用于 Redis import com amazonaws auth AWSCredentials impor
  • 如何将“.csv”数据文件导入Redis数据库

    如何将 csv 数据文件导入 Redis 数据库 csv 文件中包含 id 时间 纬度 经度 列 您能否向我建议导入 CSV 文件并能够执行空间查询的最佳方法 这是一个非常广泛的问题 因为我们不知道您想要什么数据结构 您期望什么查询等等 为
  • 如何配置Lettuce Redis集群异步连接池

    我正在配置我的生菜重新分配池 当我按照官方文档配置时 连接池无法正常初始化 无法获取连接 官方文档指出 RedisClusterClient clusterClient RedisClusterClient create RedisURI
  • 超出 Redis 连接/缓冲区大小限制

    在对我们的应用程序服务器进行压力测试时 我们从 Redis 中得到以下异常 ServiceStack Redis RedisException 无法连接到 redis host 6379 处的 redis 实例 gt System Net
  • 使用环境变量在 redis.conf 中设置动态路径

    我有一个环境变量MY HOME其中有一个目录的路径 home abc 现在 我有一个redis conf文件 我需要像这样设置这个路径 redis conf pidfile MY HOME local var pids redis pid
  • 为什么单个 Redis 实例不是线程安全的?

    https github com xetorthio jedis wiki Getting started https github com xetorthio jedis wiki Getting started 在多线程环境中使用Jed
  • 没有适用于机器人的 Laravel 会话

    我在大型 Laravel 项目和 Redis 存储方面遇到问题 我们将会话存储在 Redis 中 我们已经有 28GB 的 RAM 然而 它的运行速度仍然相对较快 达到了极限 因为我们有来自搜索引擎机器人的大量点击 每天超过 250 000
  • 集合成员的 TTL

    Redis 是否可以不为特定键而是为集合的成员设置 TTL 生存时间 我正在使用 Redis 文档提出的标签结构 数据是简单的键值对 标签是包含与每个标签对应的键的集合 例如 gt SETEX id id 1 100 Lorem ipsum
  • 使用 Redis 中的键

    我是 Redis 和键值数据库的新手 你能告诉我如何在redis中正确实现这种关系方法吗 我有一个关系表 其中两个键对应一个值 master id slave id 价值 Example 主站 ID 从属ID 价值 1 1 值1 2 1 值
  • 在redis中存储多个嵌套对象

    我想在redis中存储多个复杂的json数据 但不知道如何 这是我的 json 结构 users user01 username ally email email protected cdn cgi l email protection u
  • 如何通过ARM模板输出返回Redis的primaryKey?

    我正在尝试借助下面列出的 ARM 模板来部署 Redis 然后返回其主密钥 Azure 门户中 Redis 的 访问密钥 gt 主 下可用的秘密字符串 但是 我从管道 AzureResourceManagerTemplateDeployme
  • redis能完全取代mysql吗?

    简单的问题 我是否可以使用 redis 而不是 mysql 来处理各种 Web 应用程序 社交网络 地理位置服务等 IT 领域没有什么是不可能的 但有些事情可能会变得极其复杂 将键值存储用于全文搜索之类的事情可能会非常痛苦 另外 据我所知
  • 具有匹配模式的 ioredis 密钥

    我想用键匹配模式 LOGIN 搜索 Redis 数据库 我在我的应用程序中使用 ioredis 昨天我搜索了整个网络 我得到了一些执行这项工作的选项 如下所示 KEYS 扫描流 Issue import Redis from ioredis
  • 如何暂停或恢复 celery 任务?

    我的项目中有一项要求 客户可以暂停或恢复正在挂起的流程 而不是流程流程 我在用网络套接字显示芹菜任务结果 但在暂停 恢复时我不明白如何设计代码 我想到的唯一方法就是revoke暂停请求中的任务 同时保留数据撤销的过程在缓存中 并稍后在res
  • 如何在Redis中存储聚合目录树搜索结果

    我有一个很大的产品目录树 目前包含约 36000 个类别和约 100 万个产品 即叶子 它的结构如下 最大深度为 5 Cat1 Cat11 Cat111 Cat1111 Product1 Cat1112 Product1 Cat1113 P

随机推荐

  • BENTLY 125800-01 励磁系统电源模

    BENTLY 125800 01 励磁系统电源模 BENTLY 125800 01 励磁系统电源模产品详情 BENTLY 125800 01 励磁系统电源模块通常用于为电力发电机的励磁系统提供电源 这些模块在电力工业中非常重要 因为它们确保
  • java中使用断言的好处和坏处?断言语句如下所示:Assert.notNull(field, exceptionMsg);

    断言是一种在编程中用于检查和验证假设的机制 Java 中使用断言可以通过 assert 关键字来实现 给定的断言语句 Assert notNull field exceptionMsg 表示当 field 为 null 时 会抛出一个指定的
  • 解决 Hive 外部表分隔符问题的实用指南

    简介 在使用 Hive 外部表时 分隔符设置不当可能导致数据导入和查询过程中的问题 本文将详细介绍如何解决在 Hive 外部表中正确设置分隔符的步骤 问题描述 在使用Hive外部表时 可能会遇到分隔符问题 这主要是因为Hive在读取数据时
  • 继电器和接触器的区别是什么?作用是什么?

    目录 继电器的原理与作用 接触器的原理与作用 区别 用途和容量 触点结构和数量 触发方式 耐久性和可靠性 继电器的原理与作用 继电器的原理是基于电磁感应现象的一种电器元件 继电器由线圈 铁芯和触点组成 当线圈通电时 通过产生的磁场使铁芯磁化
  • 硬件产品经理:硬件产品敏捷开发

    目录 简介 敏捷 CSDN学院 作者简介 简介 之所以敏捷产品开发流程会越来越普遍 主要得益于这个方法可以让企业使用更少的资源去开发出令客户满意的新产品 敏捷开发强调的最重要的一点就是 快 也就是要求通过快速迭代来获取频繁的客户反馈 这就特
  • 中高级网络安全职位的薪资水平持续上升!

    近两年网络安全科技人才供给逐渐充裕 供求紧张程度得到一定缓 解 2022 年 2023 年 很多高科技企业裁员和降薪 网络安全科技人才就业在一定程度上受到了大环境的影响 也使签约薪酬有所下降 市场价回落至 2018 年水平 但值得一提的是
  • HONEYWELL 05701-A-0326 工业机器人控制器

    HONEYWELL 05701 A 0326 工业机器人控制器 HONEYWELL 05701 A 0326 工业机器人控制器产品详情 HONEYWELL 05701 A 0326 工业机器人控制器在各种制造和生产领域中发挥关键作用 用于控
  • MVVM控件焦点问题

    在wpf中 有时点击空白处控件失去焦点事件无法触发 要解决这个问题 可以在主窗体mainwindow中重写MouseDown事件 MainWindowView xaml cm Message Attach Event MouseDown A
  • 红队基础建设与介绍

    目录 1 ATT CK相关背景 2 渗透测试与红队 2 1 渗透测试 2 2 红队 3 红队基础建设 3 1 设定行动 3 1 1 团队协作 3 1 2 制定计划 3 1 3 确认目标 3 2 功能隔离 3 2 1 网络钓鱼MSTP 3 2
  • ros2+xacro文件示例代码备份

    重要提示 在xacro文件虽然是xml文件 但是如果在xacro文件中随意插入自定义标签 虽然check urdf不会报错 但是最后rviz2解析的时候会出现错误 例如 如果在上述xml文件中加入以下代码将出现显示异常
  • 安装登录minio后,页面一直转圈

    报错 WARNING MINIO ACCESS KEY and MINIO SECRET KEY are deprecated Please use MINIO ROOT USER and MINIO ROOT PASSWORD 处理方案
  • Starting the Docker Engine...一直转圈

    出现的问题 原因排查 看了网上的很多篇文章 每个原因都排查了 没有发现问题 遇到这样的情况应先看自己是否安装成功 打开运行 在空框中输入 powershell 并点击确定 docker version 显示版本证明安装成功 Hyper V
  • 基于振弦采集仪的工程监测技术探索

    基于振弦采集仪的工程监测技术探索 随着工程建设的日益发展 对工程监测的需求也越来越迫切 工程监测是保障工程质量和安全的重要手段 而基于振弦采集仪的工程监测技术 由于其高精度 高灵敏度和实时性等特点 正逐渐成为工程监测领域的重要技术 振弦采集
  • ubuntu推送本地仓库到coding

    本教程提供在ubuntu系统下推送本地仓库到coding的指令 用于查阅 一 主要步骤有 0 初始化仓库 git init 1 添加远程仓库 git remote add origin https coding git 修改自己仓库链接 命
  • 题解 | #输出某一年的各个月份的天数#

    三方寄过去了 告诉我停止24届招聘 全部毁约 牛的 he芯 毁约应届生 34316 广西北部湾银行2022年校园招聘 广西北部湾银行股份有限公司2022届校园招聘 看终端大把大把15级的 这个14级是不是终端bg的白菜了 程序员面试六战六捷
  • 市域治理现代化建设方案(智慧网格解决方案):PPT全文33页,附下载

    关键词 市域治理现代化 智慧网格解决方案 市域治理主要内容 市域社会治理重点内容 市域社会治理现代化 一 市域治理现代化背景 1 城市化进程加速 随着城市化进程的快速推进 城市人口不断增加 城市规模不断扩大 城市治理面临着更加复杂的挑战 2
  • CNP日志采集组件使用说明

    移动云CNP上线了日志采集组件 整体功能类似ELK 可以实现集群容器日志的数据采集 汇聚 统一检索等功能 使用也很简单 首先安装组件 然后配置采集规则 目前支持标准输出和日志文件两种采集方案 标准输出很好理解 只需要你把日式输出到控制台 这
  • json转换工具属性排序

    json 对象属性的输出顺序测试 fastJson 有序 jackson gson无序 需代码中人工按约定来编码 接口数据签名规则 fastJson会根据对象的字段的首字母来排序 而jackson gson是根据对象的类中定义的属性的代码中
  • 工业5G路由器助力AGV工厂建设,确保自动流水线高效运转

    随着制造业自动化 智能化转型升级的需求 山东省济南市一家汽车零部件生产企业计划建设全自动生产流水线 并使用AGV替代部分人工运输 以降本提效 但是对无线通信要求极高的AGV系统在复杂的工厂建筑内很难获得稳定的信号覆盖 AGV之间 与控制中心
  • Redis 的键管理

    一 Redis 数据库管理 Redis 是一个键值对 key value pair 的数据库服务器 其数据保存在 src server h redisDb 中 网上很多帖子说在 redis h 文件中 但是 redis 6 x版本目录中都没