用戶登錄Token緩存Redis實踐:提升SpringBoot應用性能

前言

在現代Web應用中,用戶認證和授權是至關重要的功能。

傳統的基于數據庫的Token存儲方式雖然簡單易用,但在高并發場景下容易成為性能瓶頸。

本文將介紹如何將SpringBoot項目中的用戶Token從數據庫存儲遷移到Redis緩存,顯著提升系統性能。

一、原有架構分析

在原始的代碼實現中,Token信息存儲在數據庫中:

// 數據庫查詢Token信息
SysUserTokenEntity tokenEntity = baseDao.getByToken(accessToken);

這種方式存在幾個問題:

  1. 性能瓶頸:每次Token驗證都需要查詢數據庫
  2. 數據庫壓力:高頻的Token驗證請求給數據庫帶來巨大壓力
  3. 擴展性差:難以應對高并發場景

二、Redis緩存設計方案

2.1 緩存鍵設計

我們采用兩種鍵結構來存儲Token信息:

// Token詳細信息緩存鍵
private final static String TOKEN_KEY_PREFIX = "sys:token:";// 用戶與Token映射關系緩存鍵  
private final static String USER_TOKEN_KEY_PREFIX = "sys:user:token:";

這種設計允許我們:

  • 通過Token快速獲取用戶信息
  • 通過用戶ID快速找到對應的Token
  • 支持雙向查詢需求

2.2 緩存數據結構

// Token緩存結構
sys:token:abc123 -> {"userId": 1,"token": "abc123","expireDate": "2023-12-31 23:59:59","updateDate": "2023-12-31 11:59:59"
}// 用戶Token映射
sys:user:token:1 -> "abc123"

三、核心代碼實現

3.1 Token創建與緩存

@Override
public Result createToken(Long userId) {// 生成或更新TokenString token = generateOrUpdateToken(userId);// 緩存到RediscacheTokenToRedis(userId, token, expireTime);return new Result().ok(buildTokenResponse(token));
}private void cacheTokenToRedis(Long userId, String token, Date expireTime) {String tokenKey = TOKEN_KEY_PREFIX + token;String userTokenKey = USER_TOKEN_KEY_PREFIX + userId;// 計算剩余過期時間long expireSeconds = (expireTime.getTime() - System.currentTimeMillis()) / 1000;// 存儲Token詳細信息redisUtils.set(tokenKey, buildTokenEntity(userId, token, expireTime), expireSeconds, TimeUnit.SECONDS);// 存儲用戶-Token映射redisUtils.set(userTokenKey, token, expireSeconds, TimeUnit.SECONDS);
}

3.2 Token驗證優化

@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {String accessToken = (String) token.getPrincipal();// 從Redis獲取Token信息(優先緩存)SysUserTokenEntity tokenEntity = sysUserTokenService.getByToken(accessToken);if (tokenEntity == null || tokenEntity.isExpired()) {throw new IncorrectCredentialsException("Token無效或已過期");}// 獲取用戶信息并認證return buildAuthenticationInfo(tokenEntity);
}

3.3 緩存查詢策略

public SysUserTokenEntity getByToken(String token) {String key = TOKEN_KEY_PREFIX + token;// 1. 優先從Redis查詢SysUserTokenEntity tokenEntity = (SysUserTokenEntity) redisUtils.get(key);if (tokenEntity != null) {if (tokenEntity.isExpired()) {// 自動清理過期TokencleanExpiredToken(token, tokenEntity.getUserId());return null;}return tokenEntity;}// 2. Redis未命中,查詢數據庫tokenEntity = getFromDatabase(token);if (tokenEntity != null && !tokenEntity.isExpired()) {// 3. 回寫到RediscacheTokenToRedis(tokenEntity.getUserId(), token, tokenEntity.getExpireDate());}return tokenEntity;
}

四、性能對比測試

4.1 測試環境

  • 服務器配置:4核8G
  • Redis:單節點
  • 數據庫:MySQL 8.0
  • 并發用戶:1000

4.2 測試結果

場景

平均響應時間

QPS

數據庫CPU使用率

數據庫存儲

128ms

78

85%

Redis緩存

23ms

435

15%

性能提升

82%

458%

82%

五、最佳實踐建議

5.1 緩存過期策略

// 設置略短于實際過期時間的緩存過期
long redisExpire = EXPIRE - 60; // 提前60秒過期
redisUtils.set(key, value, redisExpire, TimeUnit.SECONDS);

這樣設計可以避免緩存中存在已過期的Token。

5.2 緩存雪崩防護

// 添加隨機過期時間偏移量
long randomOffset = new Random().nextInt(30);
long actualExpire = EXPIRE - randomOffset;

5.3 監控與告警

建議監控以下指標:

  • Redis內存使用情況
  • Token緩存命中率
  • Token驗證響應時間
  • 緩存穿透頻率

六、故障處理與恢復

6.1 緩存穿透處理

// 使用布隆過濾器或空值緩存防止緩存穿透
if (tokenEntity == null) {// 緩存空值,避免頻繁查詢數據庫redisUtils.set(tokenKey, NULL_OBJECT, 60, TimeUnit.SECONDS);
}

6.2 緩存重建機制

// 異步重建緩存
@Async
public void asyncRebuildTokenCache(Long userId, String token) {// 異步重新加載Token到緩存
}

七、總結

通過將用戶Token從數據庫遷移到Redis緩存,我們實現了:

  1. 性能大幅提升:響應時間降低82%,QPS提升458%
  2. 數據庫壓力減輕:數據庫CPU使用率從85%降至15%
  3. 系統擴展性增強:支持更高的并發用戶數
  4. 用戶體驗改善:登錄和Token驗證更加迅速

這種架構改造不僅提升了系統性能,還為后續的微服務化和分布式部署奠定了基礎。在實際項目中,建議根據具體業務需求調整緩存策略和過期時間,以達到最佳的性能效果。

后續優化方向

  1. 集群部署:Redis集群提高可用性和性能
  2. 多級緩存:結合本地緩存減少Redis訪問
  3. Token刷新機制:實現無感Token刷新
  4. 安全增強:添加Token黑名單機制

通過持續的優化和迭代,可以構建出更加高效、安全的用戶認證系統。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/96470.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/96470.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/96470.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

深度解析Structured Outputs:讓AI輸出嚴格遵循JSON Schema的結構化響應

深度解析Structured Outputs:讓AI輸出嚴格遵循JSON Schema的結構化響應 引言 在現代應用開發中,JSON 是最流行的數據交換格式之一。為了提升 API 接口的健壯性和數據一致性,結構化輸出(Structured Outputs)成為了大模…

關于 微服務中服務注冊與發現 的詳細說明,涵蓋主流框架/解決方案的對比、核心功能、配置示例及總結表格

以下是關于 微服務中服務注冊與發現 的詳細說明,涵蓋主流框架/解決方案的對比、核心功能、配置示例及總結表格:1. 服務注冊與發現的核心概念 服務注冊與發現是微服務架構的基礎能力,主要解決以下問題: 服務注冊:服務實…

08高級語言邏輯結構到匯編語言之邏輯結構轉換 continue break 完結匯編按邏輯結構

目錄 📚 1. continue 語句的原理與實現 🛠 1.1 continue 語句的基本概念 ?? 1.2 底層原理 📖 1.3 案例分析:跳過偶數,累加奇數 🚀 2. break 語句的原理與實現 🛠 2.1 break 語句的基本概…

AI出題人給出的Java后端面經(二十二)(日更)

鏈接雙端鏈表 前一篇:AI出題人給出的Java后端面經(二十一)(日更) 后一篇:null 目錄 🔵 一、Java基礎(集合/流式/OOP) 答案: 題目1:集合遍歷性…

AI賦能體育訓練突破:AI動作捕捉矯正精準、戰術分析系統提效率,運動員破瓶頸新路徑

傳統體育訓練長期受限于 “動作矯正依賴教練主觀判斷”“戰術分析滯后于賽場變化”“運動員體能分配憑經驗摸索” 的難題,而 AI 技術的深度介入,正讓體育訓練從 “經驗驅動” 轉向 “數據驅動”,既能實時捕捉動作偏差,又能動態優化…

【python實用小腳本-194】Python PNR一鍵查票:輸入號碼秒出座位狀態——再也不用刷12306

Python PNR一鍵查票:輸入號碼秒出座位狀態——再也不用刷12306 PNR查詢, 實時座位, 離線腳本, 零廣告, 瑞士軍刀 故事開場:一把瑞士軍刀救了趕火車的你 周五傍晚,你拎著行李沖向站臺,手機信號一格,12306 死活刷不出座位…

【python】python進階——推導式

目錄 一、推導式介紹 二、推導式的用法 2.1 列表推導式 2.2 字典推導式 2.3 集合推導式 2.4 生成器表達式 三、推導式的嵌套和復雜用法 3.1 嵌套推導式 3.2 多重條件推導式 四、推導式對比傳統循環 4.1 性能比較 4.2 可讀性比較 五、常見應用場景 5.1 數據清…

數字安全隱形基石:隨機數、熵源與DRBG核心解析與技術關聯

前言:數字安全的 “隱形基石” 在數字化浪潮席卷全球的今天,從金融交易的密鑰生成到區塊鏈的共識機制,從量子通信的加密協議到智能汽車的身份認證,隨機數如同空氣般滲透在信息系統的每一個安全節點。然而,看似簡單的 …

TDengine IDMP 最佳實踐

最佳實踐 IDMP 提供了一強大的數據建模能力,讓數據標準化、情景化,從而可以更好地利用 AI 技術,從數據中挖掘出業務價值,但數據建模本身是一個很難用 AI 完成的事情。 為最大程度減少建模的成本,TDengine 推薦在數據…

8.20網絡編程——sqlite3數據庫

文章目錄一、思維導圖二、學生管理系統1、myhead.h2、代碼三、牛客網刷題一、思維導圖 二、學生管理系統 1、myhead.h #ifndef __MYHEAD_H__ #define __MYHEAD_H__#include <string.h> #include <stdio.h> #include <stdlib.h> #include <errno.h>#d…

電腦不能訪問服務器磁盤,連不上服務器。解決辦法:在窗口中輸入 regedit 確定即可打開注冊表,。。。。0改為1,確認;

打開注冊表&#xff1a; 按鍵盤上的 WinR 鍵&#xff0c;打開運行窗口&#xff0c;在窗口中輸入 regedit 確定即可打開注冊表。&#xff08;或者直接在左下角搜索框中搜索“注冊表”&#xff09; 依次打開以下目錄 計算機\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Service…

EP4CE40F23I7N Altera FPGA Cyclone IV E

EP4CE40F23I7N 阿爾特拉 Altera Cyclone IV E 系列的一顆中等密度、低功耗 FPGA&#xff0c;通信接口與工業控制等應用。該器件采用成熟的工藝制程&#xff0c;器件規模約為 39k 左右的邏輯單元&#xff08;Logic Elements&#xff09;&#xff0c;由若干邏輯陣列塊&#xff08…

【typenum】 21 類型級別計算最大公約數(Gcd)

一、源碼 代碼實現了一個在類型級別計算最大公約數&#xff08;GCD&#xff09;的系統 定義&#xff08;type_operators.rs&#xff09; /// A **type operator** that computes the [greatest common divisor][gcd] of Self and Rhs. /// /// [gcd]: https://en.wikipedia.org…

如何為 Visual Studio 2019 安裝 WDK

我用nmake編譯代碼提示錯誤&#xff1a;fatal error U1052: 未找到文件“\makefile.def”&#xff0c;經過排查發現是代碼依賴WDK&#xff0c;所以研究了一下WDK的安裝步驟&#xff0c;下面是具體步驟&#xff1a; 請遵循以下步驟來為你的 VS2019 搭建完整的驅動開發環境&…

使用 Apache Flink CDC 3.0 實現 MySQL 到 Elasticsearch 的數據同步

下面我將創建一個完整的 Spring Boot 項目&#xff0c;使用 Flink CDC 3.0 基于 MySQL 的 binlog 實現數據同步到 Elasticsearch。 項目概述 這個項目將&#xff1a; 使用 Flink CDC 連接 MySQL 并讀取 binlog處理數據變化&#xff08;插入、更新、刪除&#xff09;將數據同步到…

Web網站的運行原理2

請求Web網站的文件-HTTP 可以使用HTTP協議在Web瀏覽器和Web服務器應用程序之間傳輸Web網頁的文件。 在進行HTTP傳輸之前&#xff0c;需要先在Web瀏覽器和Web服務器應用程序之間建立TCP連接。 使用HTTP請求可以要求Web瀏覽器向Web服務器應用程序傳輸文件。 傳輸Web網站的文件-HT…

論文閱讀:Do As I Can, Not As I Say: Grounding Language in Robotic Affordances

地址&#xff1a;Do As I Can, Not As I Say: Grounding Language in Robotic Affordances 摘要 大型語言模型&#xff08;LLM&#xff09;能夠編碼豐富的世界語義知識&#xff0c;這類知識對于機器人執行自然語言表達的高層級、時間擴展指令具有重要價值。然而&#xff0c;語…

Django管理后臺結合剪映實現課件視頻生成應用

在教學內容的數字化制作中&#xff0c;如何將課件與音頻快速轉換為視頻是一項高頻需求。借助管理后臺和剪輯工具&#xff0c;可以實現課件內容的下載、轉換和草稿生成&#xff0c;大幅減少重復操作。 【AI教育教學考試系統】課件在線剪映視頻草稿生成應用這里實現的課件PPT部分…

AI升級社區便民服務:AI辦事小程序高效辦證+應急系統秒響應,告別跑腿愁住得更安心

朋友&#xff0c;你有沒有在社區辦過事&#xff1f;想給孩子辦入學證明&#xff0c;得先跑居委會開證明&#xff0c;再去街道辦事處蓋章&#xff0c;來回幾趟不說&#xff0c;要是材料沒帶全&#xff0c;還得重新跑&#xff1b;家里水管爆了&#xff0c;半夜聯系物業&#xff0…

el-table-draggable拖拽實現表格內容排序

1、圖片2、安裝包import ElTableDraggable from "el-table-draggable";3、代碼&#xff08;html&#xff09;<el-table-draggable:data"soloTableData"input"dragInputHandlerSolo"><el-table:data"soloTableData"row-key&qu…