業務場景描述: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