Files
junhong_cmp_fiber/docs/polling-system/performance-tuning.md
huang 3a2e3f2571
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m8s
浅浅升级一下
2026-05-06 14:41:14 +08:00

175 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 轮询系统性能调优指南
## 千万卡规模优化方案
### 1. 调度器优化
当前配置存在瓶颈:每次只取 1000 张卡,每 10 秒调度一次,每分钟最多处理 6000 张卡。
**优化方案**
```go
// 修改 scheduler.go 中的 processTimedQueue
cardIDs, err := s.redis.ZRangeByScore(ctx, queueKey, &redis.ZRangeBy{
Min: "-inf",
Max: formatInt64(now),
Count: 10000, // 从 1000 提高到 10000
}).Result()
```
调整调度间隔:
```go
func DefaultSchedulerConfig() *SchedulerConfig {
return &SchedulerConfig{
ScheduleInterval: 5 * time.Second, // 从 10 秒改为 5 秒
// ...
}
}
```
优化后:每分钟可处理 12 万张卡
### 2. 并发控制优化
修改 `scripts/init_polling_config.sql`
```sql
-- 千万卡规模的并发配置
INSERT INTO tb_polling_concurrency_config (task_type, max_concurrency, description) VALUES
('realname', 500, '实名检查并发数'),
('carddata', 1000, '流量检查并发数'),
('package', 500, '套餐检查并发数'),
('stop_start', 100, '停复机操作并发数');
```
### 3. Worker 多实例部署
多实例扩容时,必须拆分 Worker 角色,禁止直接复制多个完整 Worker 进程。推荐保留 `1 leader + N consumer`
```yaml
# docker-compose.yml 示例
services:
worker-leader:
image: junhong-cmp-worker
environment:
- JUNHONG_WORKER_ROLE=leader
- JUNHONG_WORKER_INSTANCE_NAME=worker-leader-1
worker-consumer-1:
image: junhong-cmp-worker
environment:
- JUNHONG_WORKER_ROLE=consumer
- JUNHONG_WORKER_INSTANCE_NAME=worker-consumer-1
worker-consumer-2:
image: junhong-cmp-worker
environment:
- JUNHONG_WORKER_ROLE=consumer
- JUNHONG_WORKER_INSTANCE_NAME=worker-consumer-2
```
说明:
- `leader` 负责轮询初始化、轮询调度、Asynq 定时任务调度等单例职责
- `consumer` 只负责 Asynq 队列消费,适合横向扩容
- 单实例部署默认使用 `all`,行为等价于历史版本
- 不要直接启动多个 `all` 或多个 `leader`,否则会重复扫库、重复调度、重复入队
- 需要提升吞吐时,优先增加 `consumer` 数量,而不是复制完整 Worker
- 本期仅完成角色拆分,不包含 Redis Leader 锁、自动选主、任务唯一性去重,这些作为第二期增强处理
### 4. 检查间隔优化
根据业务需求调整检查间隔,减少不必要的检查:
| 卡状态 | 当前间隔 | 建议间隔 | 说明 |
|--------|---------|---------|------|
| 未实名 | 60 秒 | 300 秒 | 实名状态不会频繁变化 |
| 已实名 | 3600 秒 | 86400 秒 | 已实名只需每天检查一次 |
| 已激活流量 | 1800 秒 | 3600 秒 | 每小时检查一次足够 |
这样可以大幅减少检查次数:
- 原方案1000 万次/小时
- 优化后:约 100 万次/小时
### 5. 初始化优化
使用 Pipeline 批量写入 Redis
```go
// 优化 initCardPolling使用 Pipeline
func (s *Scheduler) initCardsBatch(ctx context.Context, cards []*model.IotCard) error {
pipe := s.redis.Pipeline()
for _, card := range cards {
config := s.MatchConfig(card)
if config == nil {
continue
}
// 批量 ZADD
nextTime := s.calculateNextCheckTime(card, config)
pipe.ZAdd(ctx, queueKey, redis.Z{Score: float64(nextTime), Member: card.ID})
// 批量 HSET
pipe.HSet(ctx, cacheKey, cardData)
}
_, err := pipe.Exec(ctx)
return err
}
```
优化效果:减少 Redis 往返次数,初始化时间从 150 秒降至 30-50 秒
### 6. 数据库索引优化
确保以下索引存在:
```sql
-- 用于渐进式初始化的游标分页
CREATE INDEX IF NOT EXISTS idx_iot_card_id_asc ON tb_iot_card(id ASC) WHERE deleted_at IS NULL;
-- 用于条件筛选
CREATE INDEX IF NOT EXISTS idx_iot_card_polling
ON tb_iot_card(enable_polling, real_name_status, activation_status, card_category);
```
### 7. Redis 配置优化
```conf
# redis.conf
maxmemory 8gb
maxmemory-policy allkeys-lru
# 连接池优化
tcp-keepalive 300
timeout 0
```
### 8. 监控告警阈值
千万卡规模的告警阈值建议:
```sql
INSERT INTO tb_polling_alert_rule (rule_name, metric_type, task_type, threshold, comparison, alert_level) VALUES
('队列积压告警', 'queue_size', 'polling:realname', 100000, 'gt', 'critical'),
('失败率告警', 'failure_rate', 'polling:realname', 10, 'gt', 'warning'),
('延迟告警', 'avg_wait_time', 'polling:carddata', 3600, 'gt', 'warning');
```
---
## 容量规划
| 规模 | Worker 数 | Redis 内存 | 并发总数 | 预估 QPS |
|------|----------|-----------|---------|---------|
| 100 万卡 | 2 | 512MB | 200 | 1000 |
| 500 万卡 | 4 | 2GB | 500 | 3000 |
| 1000 万卡 | 8 | 4GB | 1000 | 5000 |
| 2000 万卡 | 16 | 8GB | 2000 | 10000 |
## 压测建议
1. 使用 `wrk``vegeta` 对 API 进行压测
2. 使用脚本批量创建测试卡验证初始化性能
3. 监控 Redis 内存和 CPU 使用率
4. 监控数据库连接池和查询延迟
```bash
# API 压测示例
wrk -t12 -c400 -d30s http://localhost:3000/api/admin/polling-stats
```