perf(auth): JWT 权限缓存 RwLock 替换为 DashMap
USER_SCOPE_CACHE 从 LazyLock<RwLock<HashMap>> 改为 LazyLock<DashMap>, 消除读写锁竞争,提升高并发场景下的认证中间件吞吐量。 过期条目淘汰逻辑改用 DashMap::retain,无需手动获取 write lock。
This commit is contained in:
@@ -26,3 +26,4 @@ cbc.workspace = true
|
|||||||
hex.workspace = true
|
hex.workspace = true
|
||||||
base64 = "0.22"
|
base64 = "0.22"
|
||||||
redis.workspace = true
|
redis.workspace = true
|
||||||
|
dashmap.workspace = true
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use axum::body::Body;
|
|||||||
use axum::http::Request;
|
use axum::http::Request;
|
||||||
use axum::middleware::Next;
|
use axum::middleware::Next;
|
||||||
use axum::response::Response;
|
use axum::response::Response;
|
||||||
|
use dashmap::DashMap;
|
||||||
use erp_core::error::AppError;
|
use erp_core::error::AppError;
|
||||||
use erp_core::request_info::REQUEST_INFO;
|
use erp_core::request_info::REQUEST_INFO;
|
||||||
use erp_core::request_info::RequestInfo;
|
use erp_core::request_info::RequestInfo;
|
||||||
@@ -12,11 +13,11 @@ use crate::service::token_service::TokenService;
|
|||||||
type DeptIds = Vec<uuid::Uuid>;
|
type DeptIds = Vec<uuid::Uuid>;
|
||||||
type DataScopes = std::collections::HashMap<String, DataScope>;
|
type DataScopes = std::collections::HashMap<String, DataScope>;
|
||||||
type ScopeCacheEntry = (DeptIds, DataScopes, std::time::Instant);
|
type ScopeCacheEntry = (DeptIds, DataScopes, std::time::Instant);
|
||||||
type ScopeCacheMap = std::collections::HashMap<uuid::Uuid, ScopeCacheEntry>;
|
|
||||||
|
|
||||||
/// 用户权限数据缓存(user_id -> (department_ids, data_scopes, cached_at))
|
/// 用户权限数据缓存(user_id -> (department_ids, data_scopes, cached_at))
|
||||||
static USER_SCOPE_CACHE: std::sync::LazyLock<std::sync::RwLock<ScopeCacheMap>> =
|
/// DashMap 分片并发,读写无锁竞争
|
||||||
std::sync::LazyLock::new(|| std::sync::RwLock::new(std::collections::HashMap::new()));
|
static USER_SCOPE_CACHE: std::sync::LazyLock<DashMap<uuid::Uuid, ScopeCacheEntry>> =
|
||||||
|
std::sync::LazyLock::new(DashMap::new);
|
||||||
|
|
||||||
const SCOPE_CACHE_TTL: std::time::Duration = std::time::Duration::from_secs(60);
|
const SCOPE_CACHE_TTL: std::time::Duration = std::time::Duration::from_secs(60);
|
||||||
|
|
||||||
@@ -76,16 +77,17 @@ pub async fn jwt_auth_middleware_fn(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 查询用户所属部门 ID 列表 + 权限数据范围(带 60 秒缓存)
|
// 查询用户所属部门 ID 列表 + 权限数据范围(带 60 秒缓存)
|
||||||
let cached = {
|
let cached = USER_SCOPE_CACHE.get(&claims.sub).and_then(|entry| {
|
||||||
let cache = USER_SCOPE_CACHE.read().unwrap();
|
let (_, _, at) = entry.value();
|
||||||
cache.get(&claims.sub).and_then(|(depts, scopes, at)| {
|
if at.elapsed() < SCOPE_CACHE_TTL {
|
||||||
if at.elapsed() < SCOPE_CACHE_TTL {
|
let (depts, scopes, _) = entry.value();
|
||||||
Some((depts.clone(), scopes.clone()))
|
Some((depts.clone(), scopes.clone()))
|
||||||
} else {
|
} else {
|
||||||
None
|
drop(entry);
|
||||||
}
|
USER_SCOPE_CACHE.remove(&claims.sub);
|
||||||
})
|
None
|
||||||
};
|
}
|
||||||
|
});
|
||||||
let (department_ids, permission_data_scopes) = match cached {
|
let (department_ids, permission_data_scopes) = match cached {
|
||||||
Some(hit) => hit,
|
Some(hit) => hit,
|
||||||
None => fetch_and_cache_scopes(claims.sub, claims.tid, &db).await,
|
None => fetch_and_cache_scopes(claims.sub, claims.tid, &db).await,
|
||||||
@@ -207,15 +209,14 @@ async fn fetch_and_cache_scopes(
|
|||||||
Some(conn) => fetch_permission_data_scopes(user_id, tenant_id, conn).await,
|
Some(conn) => fetch_permission_data_scopes(user_id, tenant_id, conn).await,
|
||||||
None => std::collections::HashMap::new(),
|
None => std::collections::HashMap::new(),
|
||||||
};
|
};
|
||||||
let mut cache = USER_SCOPE_CACHE.write().unwrap();
|
USER_SCOPE_CACHE.insert(
|
||||||
cache.insert(
|
|
||||||
user_id,
|
user_id,
|
||||||
(depts.clone(), scopes.clone(), std::time::Instant::now()),
|
(depts.clone(), scopes.clone(), std::time::Instant::now()),
|
||||||
);
|
);
|
||||||
// 惰性淘汰过期条目,防止 HashMap 无限增长
|
// 惰性淘汰过期条目,防止 DashMap 无限增长
|
||||||
if cache.len() > 500 {
|
if USER_SCOPE_CACHE.len() > 500 {
|
||||||
let now = std::time::Instant::now();
|
let now = std::time::Instant::now();
|
||||||
cache.retain(|_, (_, _, at)| now.duration_since(*at) < SCOPE_CACHE_TTL);
|
USER_SCOPE_CACHE.retain(|_, (_, _, at)| now.duration_since(*at) < SCOPE_CACHE_TTL);
|
||||||
}
|
}
|
||||||
(depts, scopes)
|
(depts, scopes)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user