业务场景描述:java
当用户登陆后会缓存一个新的token,该token有效期为180天,假设有个用户在多台设备上反复登陆,那么当该用户更新密码时候,会删除历史全部未过时的token,数量可能不少,这时候逐个删除的话会耗时好几秒的时间。
未修改以前的代码贴上:redis
JwtToken jwtToken = new JwtToken(); jwtToken.setUserId(userId); //获取数据库中当前用户全部的token记录 List<JwtToken> list = jwtTokenService.findList(jwtToken); for (JwtToken o : list) { //删除redis中缓存的token JedisUtils.del(RedisConstant.TOKEN_KEY + o.getToken()); JedisUtils.del(o.getToken()); } //删除数据库中当前用户全部的token记录 jwtTokenService.deleteWithUserId(userId);
经测试若是用户token多大上千个,操做则须要五六秒的时间。
尝试解决方法以下,开启jedis通道pipelined,关于pipelined的描述以下:数据库
redis是一个cs模式的tcp server,使用和http相似的请求响应协议。一个client能够经过一个socket链接发起多个请求命令。每一个请求命令发出后client一般会阻塞并等待redis服务处理,redis处理完后请求命令后会将结果经过响应报文返回给client。因为通讯会有网络延迟,假如从client和server之间的包传输时间须要0.125秒。假设四个命令8个报文至少会须要1秒才能完成。这样即便redis每秒能处理100个命令,而咱们的client也只能一秒钟发出四个命令。这显示没有充分利用 redis的处理能力。除了能够利用mget,mset 之类的单条命令处理多个key的命令外咱们还能够利用pipeline的方式从client打包多条命令一块儿发出,不须要等待单条命令的响应返回,而redis服务端会处理完多条命令后会将多条命令的处理结果打包到一块儿返回给客户端。缓存
这里再贴上修改后的代码:网络
@Override public void deleteAllToken(String userId) { JwtToken jwtToken = new JwtToken(); jwtToken.setUserId(userId); List<JwtToken> list = jwtTokenService.findList(jwtToken); Jedis jedis= JedisUtils.getResource(); Pipeline pipeline= jedis.pipelined(); for (JwtToken o : list) { //JedisUtils.del(RedisConstant.TOKEN_KEY + o.getToken()); //JedisUtils.del(o.getToken()); pipeline.del(RedisConstant.TOKEN_KEY + o.getToken()); pipeline.del(o.getToken()); } pipeline.sync(); jwtTokenService.deleteWithUserId(userId); }
经测试发现,性能显著提高,本来要五六秒的操做如今只须要一秒就操做完了。socket