如何在Redis中存储搜索缓存数据 最大化提升线上书店搜索性能
直接用原始JSON作为Redis key的合理性分析
直接用原始JSON作为Redis key完全不合理,核心问题有两个:
- 逻辑等价的搜索条件会生成不同的key,比如你举的例子里重复了两次price大于500的规则、两个筛选条件顺序调换、JSON多了换行空格,本质搜索逻辑完全一致,但原始JSON作为key就会被判定为不同缓存,不仅命中率极低,还会重复存储大量相同结果,内存浪费非常严重。
- 原始JSON长度不固定,长搜索条件的key本身就会占用额外内存,也会拖慢Redis的key查询效率。
理想的Redis缓存设计方案
1. 搜索条件归一化,解决key重复问题
- 先清洗请求的搜索参数:先去重完全相同的筛选规则,再把所有筛选条件按字段名的字典序排序,同字段的按操作符排序,彻底避免参数顺序、重复参数导致的key差异。
- 把清洗后的JSON压缩成无空格的紧凑字符串,再用MD5或者SHA1哈希生成固定长度的字符串,加上统一前缀比如
book_search:作为最终的Redis key,不管原搜索条件多长,key都是固定32位(MD5长度),内存占用极低,也不会出现逻辑相同但key不同的问题。
2. 做缓存准入和淘汰策略,避免无效内存占用
不是所有搜索结果都值得缓存,要做过滤:
- 先给每个归一化后的搜索条件做请求计数,只有24小时内请求次数超过2次的条件才缓存结果,那些只有极少数人搜的长尾条件直接查数据库即可,不会对数据库造成压力,也避免了大量低命中缓存占用内存。
- 给所有缓存设置合理的过期时间:热门搜索的结果过期时间设1~2小时,普通搜索结果设30分钟,冷数据到期自动清理。
- 开启Redis的LRU或者LFU淘汰策略,内存达到预设阈值时自动淘汰最久未使用或者最少访问的缓存,优先保证热门请求能命中缓存。
3. 分层存储缓存内容,最大化数据复用率
如果直接把书籍全量信息存在搜索结果的value里,不同搜索条件返回相同书籍时会重复存储,浪费大量内存,可以拆成两层缓存:
- 第一层是搜索结果缓存:value只存符合条件的书籍ID列表,比如
[1,23,56,78],这个列表的体积非常小,就算存大量搜索条件也占不了多少内存。 - 第二层是书籍信息缓存:每个单本书用
book_info:{book_id}作为key,存书籍的全量信息,过期时间可以设24小时,所有搜索请求拿到ID列表后,再批量去第二层缓存查书籍的具体信息,同一本书的信息只会存一次,内存占用能降90%以上。
可选优化
如果你的模糊搜索、多条件筛选的请求占比很高,可以先把书籍的索引同步到Elasticsearch做专门的搜索层,Redis只缓存ES的查询结果,比直接查MySQL的性能高几个量级,也能降低数据库的压力。书籍信息更新时不需要全量清所有相关搜索缓存,等缓存自然过期就行,避免频繁的缓存删除操作影响性能。
内容的提问来源于stack exchange,提问作者nayak0765
相关产品推荐
相关产品推荐

