V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yoloMiss
V2EX  ›  Redis

请大佬指点一下, redis 模糊匹配 key 查询缓慢问题

  •  
  •   yoloMiss · 2022-03-28 23:27:45 +08:00 · 3014 次点击
    这是一个创建于 731 天前的主题,其中的信息可能已经有所发展或是发生改变。

    起因--->最近接手的项目,有个需求需要通过 redis 做数据缓存,需要缓存当天和昨天的共二十几万条左右的数据。

    问题--->起初项目刚开始跑的时候没问题,过了一段时间后发现前端拿不到 redis 的数据了,排查程序日志发现全部请求超时了;遂排查 redis 是否有问题;发现 redis 占用 cpu 百分之百。通过 slowlog 排查发现所有占用 redis 的命令都是 keys 123* 做的数据查询。

    尝试解决--->替换 keys 命令匹配,使用 scan 进行扫描;并通过程序 log 观察匹配占用时间;发现 cup 占用率下来了,但是 scan 命令扫描比 keys 命令的扫描时间还要长。

    请问各位大佬该怎么解决这个问题。

    19 条回复    2022-07-07 00:59:36 +08:00
    Jooooooooo
        1
    Jooooooooo  
       2022-03-28 23:36:34 +08:00
    分成多个 key 然后并行去查这些 key.
    crysislinux
        2
    crysislinux  
       2022-03-28 23:38:54 +08:00 via Android
    改变实现逻辑去掉 keys 调用。谁在 production 用 keys 谁挨打。楼上说的并行没用
    cweijan
        3
    cweijan  
       2022-03-28 23:43:04 +08:00
    你总不会一下子获取 20 万条数据吧, 拿一部分数据就行了
    ch2
        4
    ch2  
       2022-03-28 23:52:41 +08:00
    戒掉"我要用 keys 做模糊查询"这个想法
    用更复杂的机制间接实现你的想法
    zakokun
        5
    zakokun  
       2022-03-28 23:59:15 +08:00
    1. 绝对禁止使用 keys
    2. 写入 key 的时候记录下 key 名,然后在获取的时候,通过记录的 key 名,使用 MGET key1 key2 key3... 获取
    zakokun
        6
    zakokun  
       2022-03-29 00:07:39 +08:00
    @zakokun 当然这里 MGET 分批去获取,比如一次 1000 个 key 。或者使用 redis 的 pipline
    rockyliang
        7
    rockyliang  
       2022-03-29 00:07:45 +08:00
    1 )并发量不高的话改为用 MySQL 存储,只要建立好索引,像 123*这种模式的匹配,十几二十万的数据量完全撑得住
    2 )上 ElasticSearch
    GeruzoniAnsasu
        8
    GeruzoniAnsasu  
       2022-03-29 01:37:07 +08:00   ❤️ 1
    随手一搜: https://www.cnblogs.com/yinkw/p/redis_keys.html

    在 kv db 里全文扫描是否搞错了什么? 这样还不如 sqlite :memory: 呢
    night98
        9
    night98  
       2022-03-29 01:42:37 +08:00
    1.为啥会有这种需求?
    2. 能不能在数据生成的时候基于需求扔到对应 list 里去,比如 123* 的 string 放到 123 的 list 里面
    3. 换其他服务处理,比如 es ,数据量不大直接 mysql
    CEBBCAT
        10
    CEBBCAT  
       2022-03-29 01:47:55 +08:00
    zhs227
        11
    zhs227  
       2022-03-29 08:24:22 +08:00
    产生环境使用 keys 会导致灾难性后果。
    james2013
        12
    james2013  
       2022-03-29 09:10:58 +08:00
    1.使用 mysql 建 1 张新表,这个表只保存当天和昨天的数据
    2.将查询结果根据查询条件进行短时间缓存
    zmal
        13
    zmal  
       2022-03-29 09:17:06 +08:00
    怎么敢在生产环境用 keys ,要丢饭碗的啊
    zmal
        14
    zmal  
       2022-03-29 09:20:46 +08:00
    redis 内部是一个伪单线程实现,一个 keys 会阻塞后面所有的查询,导致全部超时。
    raptor
        15
    raptor  
       2022-03-29 09:53:23 +08:00
    模糊查询请使用 ES 集群,redis 不是这样用的
    sadfQED2
        16
    sadfQED2  
       2022-03-29 11:45:36 +08:00 via Android
    生产环境直接禁用 keys 命令,谁服务挂了就喷谁
    earneet
        17
    earneet  
       2022-03-29 12:21:41 +08:00
    对 key 维护一个字典树,需要模糊的时候先从字典树里找到具体的 key ,再去查
    DarkFaith
        18
    DarkFaith  
       2022-03-29 15:45:52 +08:00
    keys 的实现可以粗略的理解为遍历全部键,找到所有匹配的键然后全部返回。
    scan 的实现可以粗略的理解为分批次遍历,遍历完一部分后立即返回,然后开始下一次遍历。

    遍历是 O(n)的,也就是随着键的增多,消耗的时间是线性增加的。

    这个时候需要更高效的查询方法。

    需要分析存储的键是否可以 Hash ,如果可以 hash ,则可以使用 hash map 来存储数据。如果键是需要范围查询的,比如 top_n ,比如时间等等,可以采用 zset 来存储。
    erquiasz0825
        19
    erquiasz0825  
       2022-07-07 00:59:36 +08:00
    scan 难道不耗费 cpu 吗,可能就 100% 了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1128 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 74ms · UTC 18:47 · PVG 02:47 · LAX 11:47 · JFK 14:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.