
1) 【一句话结论】
针对360安全卫士漏洞扫描服务,采用微服务架构,通过动态限流(基于QPS/CPU的令牌桶参数自调)、分层缓存(热点数据+结果缓存+随机过期防雪崩)、分库分表+读写分离的数据库优化,确保高峰时段高并发下的服务稳定性与性能。
2) 【原理/概念讲解】
系统架构分为四层:前端网关(请求路由与限流)、任务调度中心(生成任务并放入消息队列)、任务执行集群(多实例消费任务执行扫描)、结果存储层(Redis缓存+MySQL持久化)。
3) 【对比与适用场景】
| 策略/组件 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| 限流算法(令牌桶) | 维持固定大小桶,按时间生成令牌,请求消耗令牌 | 流量平滑,允许突发但总量有限,支持动态调整 | 高峰时段流量控制(漏洞扫描服务) | 需合理设置桶大小与填充速率,动态调整需结合监控指标 |
| 限流算法(漏桶) | 维持固定大小漏斗,按固定速率流出令牌,请求消耗令牌 | 严格限制突发流量,流量恒定 | 系统资源严格限制场景 | 可能导致请求积压,不适合突发流量 |
| 缓存(热点数据:漏洞库) | 高频访问数据存入Redis | 高速读取,减少数据库压力 | 漏洞特征库(用户频繁扫描的常见漏洞) | 需设置随机过期时间防雪崩,避免数据过时 |
| 缓存(结果数据) | 用户扫描结果存入Redis | 快速返回历史结果,减少重复计算 | 用户常用扫描结果(系统已扫描过的漏洞) | 需互斥锁防击穿,确保缓存一致性 |
| 数据库分库分表(哈希分库) | 按用户ID哈希分配至不同数据库 | 避免单库数据膨胀,提升写性能 | 高并发写场景(用户任务量大的漏洞扫描) | 分库规则需均匀分布,避免热点库 |
| 数据库分库分表(时间分表) | 按任务时间或任务ID分表 | 提升查询效率,避免单表数据过大 | 热点表(近期数据多时) | 分表键需合理选择,如按时间范围分表,结合负载均衡 |
| 数据库读写分离 | 主库写,从库读 | 分散读压力,提升读性能 | 高并发读场景(结果查询) | 需保证从库数据一致性(如延迟不超过秒级) |
4) 【示例】
伪代码(用户提交扫描请求与任务执行流程):
// 用户提交扫描请求
func submitScanRequest(ctx context.Context, userId string, deviceInfo string) error {
// 1. 限流检查(前端网关)
if !isAllowed(ctx, userId) {
return errors.New("request too frequent")
}
// 2. 生成任务ID
taskId := generateTaskId()
// 3. 放入消息队列(Kafka,持久化存储)
err := kafkaProducer.Send(ctx, "scan_tasks", map[string]interface{}{
"user_id": userId,
"task_id": taskId,
"device_info": deviceInfo,
})
return err
}
// 任务执行服务消费消息(动态限流调整示例)
func processScanTask(ctx context.Context, task map[string]interface{}) {
userId := task["user_id"].(string)
taskId := task["task_id"].(string)
deviceInfo := task["device_info"].(string)
// 1. 从Redis缓存漏洞库(热点数据)
vulnerabilities, err := getVulnerabilitiesFromCache()
if err != nil {
// 数据库 fallback
vulnerabilities, err = getVulnerabilitiesFromDB()
if err != nil {
return
}
// 雪崩预防:缓存后设置随机过期
setVulnerabilitiesToCache(vulnerabilities, randomExpireTime(3600, 300)) // 随机过期时间
}
// 2. 扫描设备
scanResult := scanDevice(deviceInfo, vulnerabilities)
// 3. 存储结果(互斥锁防击穿)
lock := getMutexLock(userId, taskId)
defer releaseMutex(lock)
setScanResultToCache(userId, taskId, scanResult)
saveScanResultToDB(userId, taskId, scanResult) // 持久化
}
// 动态限流调整函数(假设由监控服务触发)
func adjustRateLimiter(rateLimiter *TokenBucket, qps, cpuUsage float64) {
// 阈值规则:QPS > 1000 或 CPU > 80% 时调整
if qps > 1000 || cpuUsage > 80 {
rateLimiter.setRate(5) // 降低填充速率
} else {
rateLimiter.setRate(10) // 恢复正常速率
}
}
5) 【面试口播版答案】
面试官您好,针对360安全卫士的漏洞扫描服务,我会从系统架构、限流、缓存、数据库优化四个方面设计。首先,系统采用微服务架构,分为前端网关、任务调度中心、任务执行集群、结果存储层四层。前端网关负责请求限流,任务调度中心将请求转化为消息队列任务,任务执行集群消费并处理,结果存入Redis和MySQL。限流策略用令牌桶算法,控制高峰时段的请求速率,并通过Prometheus监控QPS和CPU,当QPS超过1000时,动态降低令牌桶填充速率(从10个/秒降至5个/秒),调整桶大小以适应流量波动。缓存方面,将漏洞特征库(热点数据)缓存到Redis,减少数据库查询;扫描结果也缓存,快速响应历史请求,同时设置随机过期时间(如3600秒±300秒随机),预防缓存雪崩;对缓存热点数据采用分布式锁防击穿。数据库优化采用读写分离,主库写,从库读;按用户ID哈希分库(如用户ID % 8取模),按任务时间分表,避免单表数据过大;对扫描结果的关键字段(用户ID、任务ID、时间)建索引,提升查询效率。这样设计能确保高峰时段高并发下的服务稳定性和性能。
6) 【追问清单】
7) 【常见坑/雷区】