当前位置: 首页 > 科技观察

Redis的模糊查询在生产环境出现严重的性能问题

时间:2023-03-12 20:48:25 科技观察

Redis的模糊查询在生产环境中存在严重的性能问题查询量很多,而且数据量不是很频繁,所以项目中使用Redis来分担MySQL的大部分压力。在项目中,我其实是使用了Redis提供的客户端连接工具包jedis,只是在项目中引入了jedis.Jar。publicstaticSetsearchLike(Stringlike_key){//线上环境模糊查询带来严重的性能问题,避免使用if(!Config.IS_BUG){returnull;}Jedisjedis=RedisApi.getJedis();booleanis_ok=true;try{if(jedis==null){returnnull){returnnull;}returnjedis.keys(like_key);}catch(Exceptione){//TODO:handleexceptionis_ok=false;returnnull;}finally{close(jedis,is_ok);}}每当用户登录成功后,会生成一个cookie,分别存在于客户端和Redis数据库中。cookie的key由cookie值+用户ID组成:cookie字符串+“_”+用户ID。Forexample,theusercookieis"d9fb0ea5955fcf0a2183c5076",andtheuserIDis19092,thenthekeystoredinRedisisd9fb0ea5955fcf0a2183c5076_19092,andthefinalkey-vlaueis:{"d9fb0ea5955fcf0a2183c5076_19092":d9fb0ea5955fcf0a2183c5076}Andwhenusersloginsuccessfullyfora时间长了,这样的记录会不断积累,这样的记录会随着时间的推移而积累。key,既浪费redis空间又增加了redis查询的负担,于是想到用redis模糊查询来清除无用的cookiekey。Redis客户端jedis操作是通过jedis.keys(keys)来完成的,keys可以使用通配符来匹配Redis中的keys。通配符说明:*:0到任意数量的字符eg:searchLike("test*")?:1个字符比如需要清除某个用户所有无用的cookiekey,可以写成“*_19092”。Stringkey_like="*_19092";Setkeys=RedisApi.searchLike(key_like);这样就可以把这个用户的所有key都查出来,可以使用jedis提供的批量删除key的方法来达到目的。Stringkey_like="*_19092";Setkeys=RedisApi.searchLike(key_like);从需求到逻辑再到编码,一气呵成。简单测试没问题后会发布到网上,因为网站的访问量不是很高,所以跑了几天也没有什么异常。直到今天早上,拥有数十万粉丝的公众号发推文。推文的内容直接链接到网站,所以即时访问量非常高。跑了大概十几分钟,操作员突然发疯了过来,说网站访问速度很慢,甚至出现错误码。我慌了,赶紧上去查看日志。但是五一也不例外,都是下图所示的错误:从Redis池中获取少量连接,马上到redis服务器上查看,发现CPU已经达到100%以上。为了让Redis的CPU达到100%,我想出了几种可能:连接太多,存储连接的时间太长,存储的值太大,CPU和内存都占用访问,慢查询,以及其他操作的等待时间到redis被阻塞,一个操作阻塞Redis,导致CPU飙升。由于项目上线时间比较长,在检查Redis服务器性能的过程中可能基本排除了前三个,所以大概率是第四个。突然想起前几天做的功能,有一个模糊查询,应该不是这个问题吧?去官网输入“Redis模糊查询性能”,出现了很多redis模糊查询性能急剧下降的情况,建议在生产环境中使用redis的模糊查询禁用,于是直接把模糊查询业务注释掉,重新上线,跑了半天,也没有再出现这个问题,所以可以断定模糊查询是鬼。【备选方案】有问题一定要解决。既然模糊查询不行,就得想其他办法达到目的。想想Redis有一个Set的存储结构,那么可以把用户所有的cookiekey放在一个用户特定的Set中,每次用户登录成功,就清除之前Set中的cookiekey,然后***键放入,这样也可以达到同样的目的。StringsetKey="prefix_customer_cookie_list_10920";Stringtoken="ss2ssssss";//删除所有用户cookiekeySetlist=RedisApi.getSet(setKey);if(list!=null&&list.size()>0){//删除用户所有cookiekeysRedisApi.removeFromSet(setKey,list.toArray(newString[0]));}//添加***cookiekey到SetRedisApi.addSet(setKey,token);