为什么Redis中不建议使用KEYS?

2024-04-19

在Redis中,建议不要使用按键命令 https://redis.io/commands/KEYS。为什么会这样呢?是因为它的时间复杂度是 O(N) 吗?或者是别的什么原因。


我做了下面的实验来证明KEYS命令有多么危险。

当带有 KEYS 的一个命令运行时,其他 KEYS 命令正在等待运行时间。 KEYS 命令的一次运行有两个阶段,第一个阶段是从 Redis 获取信息,第二个阶段是将其发送到客户端。

$ time src/redis-cli keys "*" | wc -l
1450832
real    0m17.943s
user    0m8.341s


$ src/redis-cli
127.0.0.1:6379> slowlog get
1) 1) (integer) 0
   2) (integer) 1621437661
   3) (integer) 8321405
   4) 1) "keys"
      2) "*"

因此,它在 Redis 上运行了 8 秒,然后通过管道传输到“wc”命令。 Redis 在 8 秒内完成了该命令,但“wc”命令需要 17 秒的数据才能完成计算。因此内存缓冲区必须存在至少 17 秒。现在,让我们想象一下网络上的客户端,这些数据也必须发送到客户端。如果我们有 10 个键命令,这些命令将在 Redis 上逐个运行,当第一个命令完成并且下一个命令运行时,第一个命令的结果必须先存储在内存中,然后客户端才会使用它们。这一切都需要内存,所以我可以想象一种情况,第五个客户端正在运行 KEYS 命令,但我们仍然需要保留第一个客户端的数据,因为它们仍然没有通过网络传输。

我们来测试一下。

场景:我们有一个 200M 大小(1000M 物理内存)的 Redis DB,检查一次执行 KEYS 需要多少内存,以及通过网络执行时需要多长时间。然后模拟5个相同的KEYS命令运行,看看是否会杀死Redis。

$ src/redis-cli info memory
used_memory_human:214.17M
total_system_memory_human:926.08M

When run from the same node:
$ time src/redis-cli keys "*" | wc -l
1450832
real    0m17.702s
user    0m8.278s

$ free -m
              total        used        free      shared  buff/cache   available
Mem:            926         301         236          24         388         542
Mem:            926         336         200          24         388         507
Mem:            926         368         168          24         388         475
Mem:            926         445          91          24         388         398
Mem:            926         480          52          24         393         363
Mem:            926         491          35          24         399         352
-> looks like it consumed 190M for the KEYS command

-> 所以,Redis 忙于该命令 8s,但该命令消耗内存 17s。 -> 仅运行一个 KEYS 命令只会阻塞 Redis 8 秒,但不会导致 OOM

让我们(几乎)同时运行 2 个 KEYS 命令(无论如何都会一个接一个地运行)

$ time src/redis-cli keys "*" | wc -l &
$ time src/redis-cli keys "*" | wc -l &

$ free -m
              total        used        free      shared  buff/cache   available
Mem:            926         300         430          24         194         546
Mem:            926         370         361          24         194         477
Mem:            926         454         276          24         194         393
Mem:            926         589         141          24         194         258
Mem:            926         693          37          24         194         154
-> now we used 392M memory for 26s, while Redis is hung for 17s
-> but we still have a running Redis

让我们(几乎)同时运行 3 个 KEYS 命令(无论如何都会一个接一个地运行)

$ time src/redis-cli keys "*" | wc -l &
$ time src/redis-cli keys "*" | wc -l &
$ time src/redis-cli keys "*" | wc -l &

$ free -m
              total        used        free      shared  buff/cache   available
Mem:            926         299         474          23         152         549
Mem:            926         385         388          23         152         463
Mem:            926         512         261          23         152         336
Mem:            926         573         200          23         152         275
Mem:            926         711          61          23         152         136
Mem:            926         842          21          21          62          17
-> now we used 532M memory for 36s, while Redis is hung for 26s
-> but we still have a running Redis

Let's run 4 KEYS commands at the (almost) same time (that will run one after another anyway)
$ time src/redis-cli keys "*" | wc -l &
$ time src/redis-cli keys "*" | wc -l &
$ time src/redis-cli keys "*" | wc -l &
$ time src/redis-cli keys "*" | wc -l &
-> that kills Redis

Redis 日志中没有任何内容:

2251:C 19 May 16:03:05.355 * DB saved on disk
2251:C 19 May 16:03:05.379 * RDB: 2 MB of memory used by copy-on-write
1853:M 19 May 16:03:05.432 * Background saving terminated with success

在 /var/log/messages 中

May 19 16:08:01 consumer2 kernel: [454881.744017] redis-cli invoked oom-killer: gfp_mask=0x6200ca(GFP_HIGHUSER_MOVABLE), nodemask=(null), order=0, oom_score_adj=0
May 19 16:08:01 consumer2 kernel: [454881.744180] [<8023bdb8>] (oom_kill_process) from [<8023c6e8>] (out_of_memory+0x134/0x36c)

结论:

  • 我们可以杀死健康的 Redis 实例,消耗 200M RAM,其中操作系统上有 70% 的 RAM 可用,只需运行 4 个 KEYS 命令,一个接一个地发出并一个接一个地运行。只是因为即使 Redis 执行完毕,结果也必须被缓冲。
  • 无法使用 maxmemory 保护 Redis 免受这种行为的影响,因为内存使用不是 SET 命令的结果
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么Redis中不建议使用KEYS? 的相关文章

  • Java 将字节转换为二进制安全字符串

    我有一些以字节为单位的数据 我想将它们放入Redis中 但是Redis只接受二进制安全字符串 而我的数据有一些二进制非安全字节 那么如何将这些字节转换为二进制安全字符串以便将它们保存到 Redis 中呢 Base64 对我有用 但它使数据更
  • 如何使redis中的“HSET”子键“过期”?

    我需要使 Redis 哈希中所有超过 1 个月的密钥过期 这不可能 https github com antirez redis issues 167 issuecomment 2559040 为了保持 Redis 简单 https git
  • StackExchange.Redis的正确使用方法

    这个想法是使用更少的连接和更好的性能 连接会随时过期吗 对于另一个问题 redis GetDatabase 打开新连接 private static ConnectionMultiplexer redis private static ID
  • redis 2.8.7 Linux Sentinel环境配置问题,如何使其自启动,应该订阅什么?

    现在我们尝试使用 redis 2 8 7 作为缓存存储 来自使用 booksleeve 客户端的 NET Web 应用程序 目前看来这是一个非常有趣和令人兴奋的任务 redis 文档非常好 但由于缺乏真正的实践经验 我确实有几个关于如何正确
  • 使用redis进行树形数据结构

    我需要为基于树的键值开发一个缓存系统 与Windows注册表编辑器非常相似 其中缓存键是字符串 表示树中到值的路径 可以是原始类型 int string bool double 等 或子树本身 例如 key root x y z w val
  • 如何使用 Redis 自动删除与模式匹配的键

    在我的 Redis DB 中 我有很多prefix
  • 节点应用程序之间共享会话?

    我目前有两个独立的节点应用程序在两个不同的端口上运行 但共享相同的后端数据存储 我需要在两个应用程序之间共享用户会话 以便当用户通过一个应用程序登录时 他们的会话可用 并且他们似乎已登录到另一个应用程序 在本例中 它是一个面向公众的网站和一
  • 在 Spring 4 中干掉通用的 RedisTemplate

    我读到你可以拥有 Autowired从 Spring 4 开始泛型 这太棒了 我有一个摘要RedisService我想参加的课程 Autowired一个通用的 RestTemplate 如下所示 public abstract class
  • 如何使用redis发布/订阅

    目前我正在使用node js和redis来构建应用程序 我使用redis的原因是因为发布 订阅功能 该应用程序只是在用户进入用户或离开房间时通知经理 function publishMsg channel mssage redisClien
  • 超出 Redis 连接/缓冲区大小限制

    在对我们的应用程序服务器进行压力测试时 我们从 Redis 中得到以下异常 ServiceStack Redis RedisException 无法连接到 redis host 6379 处的 redis 实例 gt System Net
  • 将文件传递给活动作业/后台作业

    我通过标准文件输入接收请求参数中的文件 def create file params file upload Upload create file file filename img png end 但是 对于大型上传 我想在后台作业中执行
  • 没有适用于机器人的 Laravel 会话

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

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

    我正在使用 StackExchange Redis DB 插入键值对字典Batch如下 private static StackExchange Redis IDatabase database public void SetAll
  • 如何高效地将数十亿数据插入Redis?

    我有大约 20 亿个键值对 我想将它们有效地加载到 Redis 中 我目前正在使用 Python 并使用 Pipe 如redis py https redis py readthedocs io en latest redis Redis
  • Redis 客户端忽略其上设置的配置选项并尝试连接到默认 IP 127.0.01

    在AWS中 我使用ElastiCache Redis服务器并使用节点作为后端和 promise redis 包 这就是我尝试连接到我的 redis 服务器端点的方法 client redis createClient host my red
  • 如何在Redis中使用HSCAN命令?

    我想在我的作业中使用 Redis 的 HSCAN 命令 但我不知道它是如何工作的 Redis 的官方页面 http redis io commands hscan http redis io commands hscan 这个命令给了我空白
  • spring中如何使用jackson代替JdkSerializationRedisSerializer

    我在我的一个 Java 应用程序中使用 Redis 并且正在序列化要存储在 Redis 中的对象列表 但是 我注意到使用 RedisTemplate 会使用 JdkSerializationRedisSerializer 相反 我想使用 J
  • Spring-boot中将redis-cache反序列化为对象的问题

    我在 Client 类中使用 JsonNode 来处理 MySQL 8 数据库中 JSON 类型的字段 即使对于 API 请求 它也能很好地工作 但是当我使用 Redis 启用缓存 我确实需要它 时 我注意到 Redis 无法序列化 Jso
  • 有没有好的方法支持 Redis 排序集中的 pop 成员?

    有没有好的方法可以像 List 的 api LPOP 一样支持 Redis 排序集中的 pop 成员 我发现从 Redis 排序集中弹出消息是使用 ZRANGE ZREM 但是它不是线程安全性 并且当多个线程从不同主机同时访问它们时需要分布

随机推荐

  • 如何使用 Netty 发送对象?

    如何通过Netty从服务器端发送bean并在客户端接收该bean 当我发送简单的整数消息 inputstream 时 它工作成功 但我需要发送 bean 如果您在客户端和服务器端使用 Netty 那么您可以使用 Netty对象解码器 htt
  • 以编程方式关闭 WP7 应用程序? [复制]

    这个问题在这里已经有答案了 可能的重复 Windows Phone 7 关闭应用程序 https stackoverflow com questions 3659195 windows phone 7 close application 如
  • 表达忽略视图目录

    我已经设置了一个配置文件来存储我的 Express 应用程序的应用程序路径 cookie 秘密等设置 问题是它似乎忽略了我的视图路径目录设置 配置 js exports server port 3000 cookie secret path
  • 使用类的 __new__ 方法作为工厂:__init__ 被调用两次

    我在 python 中遇到了一个奇怪的错误 其中使用 new 将类的方法作为工厂会导致 init 实例化类的方法被调用两次 这个想法最初是为了使用 new 母类的方法根据传递的参数返回其子类之一的特定实例 而无需在类外部声明工厂函数 我知道
  • 需要类或命名空间;语法正确且正确

    在 dualstk h 中 ifndef 32 dualstk h define 32 dualstk h include
  • AWS 检查状态机/Step Functions 并发运行

    我在处理状态机 步骤函数 的并发运行时遇到很多问题 该状态机中确实有胶水作业任务 状态机由 Lambda 启动 并由 FIFO SQS 队列触发 lambda 获取消息 检查正在运行的状态机实例数量 如果该数量低于 GlueJob 并发运行
  • .htaccess 将一个文件夹中的所有文件重定向到另一个文件夹中的完全相同的文件

    我们只需将名为 音乐 的目录中的每个页面移动到名为 信息 的目录 这是唯一的更改 有很多指向音乐页面的链接 我们不想全部破坏 我不擅长重写条件 基本上 我想做的就是当用户输入 music index php 或 music life myp
  • 复合属性

    有没有办法在 C 中制作复合属性以在编译时提供等效的元数据 例如 改变 ClassInterface ClassInterfaceType AutoDual ProgId MyProgId MyMefExport MyProgId publ
  • 有没有办法使用 getUserMedia 减少延迟?

    在尝试减少视频延迟的同时WebRTC通信时 我测量了视频捕获和视频显示之间的延迟 为了防止测量 WebRTC 涉及的延迟 我只是使用getUserMedia和一个 HTMLvideo显示流 我通过每帧显示时间戳来做到这一点 使用reques
  • 编译器错误:对调用的引用不明确

    Case 1 static void call Integer i System out println hi i static void call int i System out println hello i public stati
  • 更改 ToolStripMenuItem 的大小

    我正在自定义绘制一个菜单项MenuStrip 我遇到的问题是菜单项坚持根据文本调整自身大小 这不是我想要的 没有文本 我可以设置AutoSize设置为 false 并显式指定大小 但包含的菜单 ToolStripDropDown 仍然根据文
  • $_POST、$_GET 和 $_REQUEST 为空

    SOLVED 我省略了输入字段中的名称属性 我有一个简单的 html php 表单 我提交了 POST 始终为空 如果我尝试 get 那么 GET 总是空的 REQUEST 和 php input 相同 我没有得到任何回报 有很多关于这个主
  • AVCaptureVideoPreviewLayer 和从相机位置预览

    我正在开发一个允许用户拍照的应用程序 我已经开始使用AVCam https developer apple com library ios samplecode AVCam Introduction Intro html苹果提供了 但我实际
  • ElasticSearch - 索引模板和索引模式有什么区别

    我在这里阅读了对我的问题的解释 https discuss elastic co t whats the differece Between index pattern and index template 54948 https disc
  • 如何通过 django admin 中的操作请求用户输入?

    在我的代码中 我正在编写一个分组操作 我想询问用户每个组需要多少人 然后用一个警报框进行响应 根据用户输入显示 您有 4 个组 的内容 我如何在 django admin 中执行此操作 如何创建某种弹出窗口来询问他们想要放入一个组中的人数
  • 默认移动构造函数/赋值和删除的复制构造函数/赋值

    根据标准 如果类 X 的定义没有显式声明移动构造函数 则当且仅当 X 没有用户声明的复制构造函数 X 没有用户声明的复制赋值运算符 X 没有用户声明的移动赋值运算符 并且 X 没有用户声明的析构函数 现在以下无法编译 include
  • Highstocks 图表宽度未正确呈现

    您好 我在使用 jquery 选项卡时遇到 highstocks 问题 这是构造函数的代码 Chart new Highcharts StockChart Chart new Highcharts StockChart chart rend
  • 在调试或正常运行时读取字符串时出现 NullReferenceException [关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 当尝试在调用时读取文件时DoSomething from Something 在里面TestProgram Load 方
  • WebSocket 库 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我想在 Linux 上使用 C 访问 WebSocket API 我见过不同的图书馆 比如libweb
  • 为什么Redis中不建议使用KEYS?

    在Redis中 建议不要使用按键命令 https redis io commands KEYS 为什么会这样呢 是因为它的时间复杂度是 O N 吗 或者是别的什么原因 我做了下面的实验来证明KEYS命令有多么危险 当带有 KEYS 的一个命