vault backup: 2026-05-25 23:50:33
This commit is contained in:
+83
-34
@@ -126,15 +126,56 @@ SLOWLOG RESET
|
||||
| `LRANGE 0 -1` (百万条 List) | 全列表拉取 | LRANGE 指定范围 |
|
||||
| 无索引的 DB 查询(在 Lua 中) | DB 层问题 | 加 DB 索引 |
|
||||
|
||||
```bash
|
||||
# SLOWLOG GET 输出字段说明
|
||||
1) (integer) 14 # 慢查询 ID(递增)
|
||||
2) (integer) 1716620400 # 发生时间(Unix 时间戳)
|
||||
3) (integer) 13456 # 耗时(微秒)
|
||||
4) 1) "KEYS" # 命令及参数
|
||||
2) "*"
|
||||
5) "127.0.0.1:53412" # 客户端地址
|
||||
6) "" # 客户端名称
|
||||
```
|
||||
|
||||
```go
|
||||
// go-redis 中的 SlowLog 接口
|
||||
entries := rdb.SlowLogGet(ctx, 10).Val()
|
||||
entries, err := rdb.SlowLogGet(ctx, 10).Result()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
for _, e := range entries {
|
||||
fmt.Printf("ID: %d, Time: %s, Cmd: %s, Duration: %v\n",
|
||||
e.ID, e.Time, e.Cmd, e.Duration)
|
||||
e.ID, e.Time.Format(time.RFC3339), e.Args, e.Duration)
|
||||
}
|
||||
```
|
||||
|
||||
### 延迟诊断工具
|
||||
|
||||
Redis 提供了内建的延迟诊断能力,定位"客户端感知慢"但服务端 CPU 并不繁忙的场景:
|
||||
|
||||
```bash
|
||||
# ──── 实时延迟采样(排查首选) ────
|
||||
redis-cli --latency # 持续输出 min/avg/max(ms)
|
||||
redis-cli --latency-history -i 5 # 每 5 秒输出一次统计
|
||||
|
||||
# ──── 延迟分布直方图 ────
|
||||
redis-cli --latency-dist # 交互式彩色直方图,快速定位延迟区间
|
||||
|
||||
# ──── 事件驱动延迟监控(需服务端配置) ────
|
||||
# 在 redis.conf 中配置延迟阈值(微秒)
|
||||
# latency-monitor-threshold 10
|
||||
|
||||
# 之后查看:
|
||||
LATENCY LATEST # 最近的延迟事件
|
||||
LATENCY HISTORY command # 某命令的延迟历史
|
||||
LATENCY RESET # 重置统计数据
|
||||
```
|
||||
|
||||
> [!TIP] 延迟排查三板斧
|
||||
> 1. `redis-cli --latency` — 先看基线是否正常(正常 P99 < 1ms)
|
||||
> 2. `LATENCY LATEST` — 看是否有异常事件(fork、大 Key 删除、AOF fsync)
|
||||
> 3. `INFO commandstats` — 按命令耗时排序,定位慢命令
|
||||
|
||||
## 三、大 Key 治理
|
||||
|
||||
### 什么是大 Key?
|
||||
@@ -202,52 +243,59 @@ UNLINK big_key # 异步删除(Redis 4.0+),立即返回
|
||||
|
||||
```go
|
||||
rdb := redis.NewClient(&redis.Options{
|
||||
Addr: "localhost:6379",
|
||||
Password: "",
|
||||
DB: 0,
|
||||
|
||||
// ──── 连接池参数 ────
|
||||
MaxIdle: 10, // 空闲连接上限
|
||||
MaxActive: 100, // 最大活跃连接数
|
||||
IdleTimeout: 5 * time.Minute, // 空闲超时关闭
|
||||
|
||||
Addr: "localhost:6379",
|
||||
Password: "",
|
||||
DB: 0,
|
||||
|
||||
// ──── 连接池参数(go-redis v9) ────
|
||||
PoolSize: 100, // 连接池最大连接数(= 旧 MaxActive)
|
||||
MinIdleConns: 10, // 最小空闲连接数,启动时预热
|
||||
ConnMaxIdleTime: 5 * time.Minute, // 空闲连接存活上限,超时关闭
|
||||
ConnMaxLifetime: 0, // 连接最大存活时长,0 = 不限制
|
||||
|
||||
// ──── 超时参数 ────
|
||||
DialTimeout: 5 * time.Second, // 建立 TCP 连接超时
|
||||
ReadTimeout: 3 * time.Second, // 读超时
|
||||
WriteTimeout: 3 * time.Second, // 写超时
|
||||
PoolTimeout: 1 * time.Second, // 获取连接的等待超时
|
||||
|
||||
// ──── 心跳保活 ────
|
||||
PingPeriod: 60 * time.Second, // PING/PONG 保活周期,防止连接被防火墙断开
|
||||
MaxRetries: 3,
|
||||
RetryDelay: 200 * time.Millisecond,
|
||||
DialTimeout: 5 * time.Second, // 建立 TCP 连接超时
|
||||
ReadTimeout: 3 * time.Second, // 读超时
|
||||
WriteTimeout: 3 * time.Second, // 写超时
|
||||
PoolTimeout: 1 * time.Second, // 获取连接的等待超时
|
||||
|
||||
// ──── 重试策略 ────
|
||||
MaxRetries: 3,
|
||||
MinRetryBackoff: 200 * time.Millisecond,
|
||||
MaxRetryBackoff: 1 * time.Second,
|
||||
})
|
||||
```
|
||||
|
||||
> [!NOTE] go-redis v8 → v9 参数变化
|
||||
> - `MaxIdle` / `MaxActive` → 合并为 `PoolSize`,`MinIdleConns` 控制预热
|
||||
> - `IdleTimeout` → `ConnMaxIdleTime`
|
||||
> - `PingPeriod` 无对应字段,go-redis 内部通过健康检查自动保活
|
||||
> - `RetryDelay` → `MinRetryBackoff` + `MaxRetryBackoff`(指数退避)
|
||||
|
||||
### 连接池选型决策树
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A["预估 QPS"] -->|"< 500"| S["MaxActive: 20<br/>MaxIdle: 5"]
|
||||
A -->|"500 ~ 5000"| M["MaxActive: 50<br/>MaxIdle: 20"]
|
||||
A -->|"> 5000"| L["MaxActive: 100~200<br/>MaxIdle: 30~50"]
|
||||
|
||||
A["预估 QPS"] -->|"< 500"| S["PoolSize: 20, MinIdleConns: 5"]
|
||||
A -->|"500 ~ 5000"| M["PoolSize: 50, MinIdleConns: 20"]
|
||||
A -->|"> 5000"| L["PoolSize: 100~200, MinIdleConns: 30~50"]
|
||||
|
||||
B{"有无 Pipeline?"}
|
||||
B -->|"是"| C["↑ 增加 30% 连接数"]
|
||||
B -->|"是"| C["增加 30% 连接数"]
|
||||
B -->|"否"| D["保持上述配置"]
|
||||
|
||||
|
||||
style L fill:#fdd,stroke:#900
|
||||
```
|
||||
|
||||
> [!TIP] MaxActive 计算公式
|
||||
> [!TIP] PoolSize 计算公式
|
||||
> ```
|
||||
> MaxActive = N × (1 + CPU等待时间/CPU计算时间)
|
||||
> PoolSize = N × (1 + CPU等待时间/CPU计算时间)
|
||||
> ```
|
||||
> 其中 N 为 Goroutine 数量。对于大多数 Web 应用,**50~100** 已经足够——如果频繁出现 PoolTimeout,优先考虑排查慢查询或大 Key 问题。
|
||||
|
||||
> [!WARNING] 连接池常见问题
|
||||
> - **MaxActive 太小**:`context deadline exceeded`(PoolTimeout)频繁出现
|
||||
> - **MaxActive 太大**:创建过多 TCP 连接,文件描述符耗尽
|
||||
> - **PoolSize 太小**:`context deadline exceeded`(PoolTimeout)频繁出现
|
||||
> - **PoolSize 太大**:创建过多 TCP 连接,文件描述符耗尽
|
||||
> - **ReadTimeout 太短**:大数据量操作(如 HGETALL 大 hash)被误杀
|
||||
> - **不设 DialTimeout**:Redis 宕机时请求永远挂起
|
||||
|
||||
@@ -268,8 +316,9 @@ maxmemory-policy allkeys-lru
|
||||
| 策略 | 作用范围 | 淘汰算法 | 适用场景 |
|
||||
|------|---------|---------|---------|
|
||||
| **allkeys-lru** | 所有 key | LRU(近似) | 通用缓存 ✅ 最常用 |
|
||||
| allkeys-lfu | 所有 key | LFU(频次统计) | Redis 6.0+,热点数据语义更强的场景 |
|
||||
| allkeys-lfu | 所有 key | LFU(频次统计) | Redis 4.0+,热点数据语义更强的场景 |
|
||||
| volatile-lru | 仅设 TTL 的 key | LRU(近似) | 混合存储:永不过期的配置 + 可淘汰的缓存 |
|
||||
| volatile-lfu | 仅设 TTL 的 key | LFU(频次统计) | 混合存储 + 频次敏感淘汰 |
|
||||
| volatile-ttl | 仅设 TTL 的 key | TTL 最短优先 | 让数据自然死亡的场景 |
|
||||
| noeviction | — | — | 数据不可丢失,超限返回错误(如配置中心) |
|
||||
|
||||
@@ -336,7 +385,7 @@ Crontab:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["⚠️ 数据异常或丢失"] --> B{"可用最近的备份?"}
|
||||
A["数据异常或丢失"] --> B{"可用最近的备份?"}
|
||||
B -->|"是"| C["停止写入,防止覆盖"]
|
||||
C --> D["恢复 RDB/AOF 备份"]
|
||||
D --> E["检查数据完整性"]
|
||||
@@ -377,8 +426,8 @@ flowchart TD
|
||||
|
||||
```bash
|
||||
# ACL 示例(Redis 6.0+)
|
||||
ACL SETUSER readonly on ">readOnlyPass123" ~cached:* get mget scan
|
||||
ACL SETUSER writer on ">writePass123" ~*:set* ~*:add* ~*:incr* set add incr
|
||||
ACL SETUSER readonly on >readOnlyPass123 ~cached:* &* +get +mget +scan +ping
|
||||
ACL SETUSER writer on >writePass123 ~* &* +set +add +incr +del +ping
|
||||
ACL LIST # 查看所有用户
|
||||
ACL WHOAMI # 当前用户
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user