优化更新

This commit is contained in:
2026-09-13 21:53:16 +08:00
parent 8548fe9ea1
commit 3f8626fb10
84 changed files with 2058 additions and 2594 deletions
+2 -22
View File
@@ -181,7 +181,6 @@ def get_redis():
| **JWT 黑名单** | String | `jwt:blacklist:{token_hash}` | Token 剩余有效期 | 登出时将 Token 加入黑名单 |
| **登录失败锁** | String | `login:lock:{username}` | 600 秒 | 连续 5 次失败后锁定 |
| **登录失败计数** | String (Lua) | `login:fail:{username}` | 300 秒 | 原子递增 + 首次设置 TTL |
| **滑动窗口限流** | String (Lua) | `rate:{ip}:{window_index}` | 2 倍窗口时长 | 滑动窗口计数器 |
| **数据字典缓存** | String (JSON) | `dict:{dict_code}` | 300 秒 | 字典项 {value: label} 映射 |
| **权限列表缓存** | String (JSON) | `perm:user:{user_id}` | 变更时失效 | 用户权限字符串列表 |
| **在线用户** | String | `online:user:{user_id}` | Token 有效期 | 在线用户 Token 存储 |
@@ -207,27 +206,9 @@ def incr_with_expire(redis_client, key: str, seconds: int) -> int:
```
:::tip 为什么需要 Lua 脚本?
`incr` 和 `expire` 分开执行时,两步之间若进程崩溃,key 会以无 TTL 的状态永久残留,导致基于 Redis 的限流/登录锁定永久封禁。Lua 脚本保证原子性,消除此风险。
`incr` 和 `expire` 分开执行时,两步之间若进程崩溃,key 会以无 TTL 的状态永久残留。Lua 脚本保证原子性,消除此风险。
:::
#### 滑动窗口限流
```python
_SLIDING_WINDOW_LUA = """
local cur = redis.call('incr', KEYS[1])
if cur == 1 then
redis.call('expire', KEYS[1], ARGV[1])
end
local prev = tonumber(redis.call('get', KEYS[2]) or '0')
local elapsed = tonumber(ARGV[3]) - tonumber(ARGV[2]) * tonumber(ARGV[1])
local f = elapsed / tonumber(ARGV[1])
if f < 0 then f = 0 elseif f > 1 then f = 1 end
local effective = prev * (1 - f) + cur
return effective
"""
```
滑动窗口限流通过当前窗口与上一窗口的计数按时间比例加权,消除固定窗口边界处的 2x 突发问题。
## 缓存策略对比
@@ -236,7 +217,7 @@ return effective
| **Cache-Aside** | 先查缓存,未命中查 DB,写回缓存 | 读多写少 | 数据字典、权限列表 |
| **Write-Through** | 写操作同时更新缓存 | 数据一致性要求高 | 字典项变更时主动失效 |
| **Write-Behind** | 写操作只更新缓存,异步写 DB | 写入性能要求高 | 未使用 |
| **TTL 过期** | 缓存自动过期 | 允许短暂不一致 | 登录锁、限流计数 |
| **TTL 过期** | 缓存自动过期 | 允许短暂不一致 | 登录锁 |
| **主动失效** | 数据变更时主动清除缓存 | 数据一致性要求高 | 字典缓存、权限缓存 |
## 缓存失效策略
@@ -263,7 +244,6 @@ invalidate_perm_cache(user_id)
```
数据字典缓存:TTL 300 秒(5 分钟)
登录失败计数:TTL 300 秒(5 分钟)
滑动窗口限流:TTL 2 倍窗口时长
验证码:TTL 120 秒(2 分钟)
```