起因--->最近接手的项目,有个需求需要通过 redis 做数据缓存,需要缓存当天和昨天的共二十几万条左右的数据。
问题--->起初项目刚开始跑的时候没问题,过了一段时间后发现前端拿不到 redis 的数据了,排查程序日志发现全部请求超时了;遂排查 redis 是否有问题;发现 redis 占用 cpu 百分之百。通过 slowlog 排查发现所有占用 redis 的命令都是 keys 123* 做的数据查询。
尝试解决--->替换 keys 命令匹配,使用 scan 进行扫描;并通过程序 log 观察匹配占用时间;发现 cup 占用率下来了,但是 scan 命令扫描比 keys 命令的扫描时间还要长。
请问各位大佬该怎么解决这个问题。
1
Jooooooooo 2022-03-28 23:36:34 +08:00
分成多个 key 然后并行去查这些 key.
|
2
crysislinux 2022-03-28 23:38:54 +08:00 via Android
改变实现逻辑去掉 keys 调用。谁在 production 用 keys 谁挨打。楼上说的并行没用
|
3
cweijan 2022-03-28 23:43:04 +08:00
你总不会一下子获取 20 万条数据吧, 拿一部分数据就行了
|
4
ch2 2022-03-28 23:52:41 +08:00
戒掉"我要用 keys 做模糊查询"这个想法
用更复杂的机制间接实现你的想法 |
5
zakokun 2022-03-28 23:59:15 +08:00
1. 绝对禁止使用 keys
2. 写入 key 的时候记录下 key 名,然后在获取的时候,通过记录的 key 名,使用 MGET key1 key2 key3... 获取 |
7
rockyliang 2022-03-29 00:07:45 +08:00
1 )并发量不高的话改为用 MySQL 存储,只要建立好索引,像 123*这种模式的匹配,十几二十万的数据量完全撑得住
2 )上 ElasticSearch |
8
GeruzoniAnsasu 2022-03-29 01:37:07 +08:00 1
|
9
night98 2022-03-29 01:42:37 +08:00
1.为啥会有这种需求?
2. 能不能在数据生成的时候基于需求扔到对应 list 里去,比如 123* 的 string 放到 123 的 list 里面 3. 换其他服务处理,比如 es ,数据量不大直接 mysql |
10
CEBBCAT 2022-03-29 01:47:55 +08:00
|
11
zhs227 2022-03-29 08:24:22 +08:00
产生环境使用 keys 会导致灾难性后果。
|
12
james2013 2022-03-29 09:10:58 +08:00
1.使用 mysql 建 1 张新表,这个表只保存当天和昨天的数据
2.将查询结果根据查询条件进行短时间缓存 |
13
zmal 2022-03-29 09:17:06 +08:00
怎么敢在生产环境用 keys ,要丢饭碗的啊
|
14
zmal 2022-03-29 09:20:46 +08:00
redis 内部是一个伪单线程实现,一个 keys 会阻塞后面所有的查询,导致全部超时。
|
15
raptor 2022-03-29 09:53:23 +08:00
模糊查询请使用 ES 集群,redis 不是这样用的
|
16
sadfQED2 2022-03-29 11:45:36 +08:00 via Android
生产环境直接禁用 keys 命令,谁服务挂了就喷谁
|
17
earneet 2022-03-29 12:21:41 +08:00
对 key 维护一个字典树,需要模糊的时候先从字典树里找到具体的 key ,再去查
|
18
DarkFaith 2022-03-29 15:45:52 +08:00
keys 的实现可以粗略的理解为遍历全部键,找到所有匹配的键然后全部返回。
scan 的实现可以粗略的理解为分批次遍历,遍历完一部分后立即返回,然后开始下一次遍历。 遍历是 O(n)的,也就是随着键的增多,消耗的时间是线性增加的。 这个时候需要更高效的查询方法。 需要分析存储的键是否可以 Hash ,如果可以 hash ,则可以使用 hash map 来存储数据。如果键是需要范围查询的,比如 top_n ,比如时间等等,可以采用 zset 来存储。 |
19
erquiasz0825 2022-07-07 00:59:36 +08:00
scan 难道不耗费 cpu 吗,可能就 100% 了
|