
1) 【一句话结论】在360手机卫士推送服务中,通过采用消息队列(Kafka)解耦请求与处理、异步任务队列(Redis+Go Worker)降低延迟、资源隔离(进程级CPU亲和性+线程池)保障稳定性,成功解决了百万级用户下的推送延迟(平均<100ms)和资源瓶颈(CPU利用率<70%),支撑高并发场景。
2) 【原理/概念讲解】老师会解释高并发推送的核心挑战是“请求洪峰”导致服务器阻塞,需通过“解耦+异步+资源隔离”解决:
3) 【对比与适用场景】
| 特性 | 同步处理模式 | 异步处理模式 |
|---|---|---|
| 定义 | 请求发送后,客户端等待服务器返回结果 | 请求发送后,客户端立即返回,服务器后续处理 |
| 延迟 | 较高(需等待推送完成) | 较低(客户端快速返回) |
| 适用场景 | 请求量小、对延迟敏感低(如查询类) | 请求量大、对延迟敏感高(如推送、通知) |
| 注意点 | 需要服务器处理能力足够,否则易阻塞 | 需要消息队列和消费者保障可靠性 |
4) 【示例】
// 推送服务核心流程(伪代码)
func PushNotification(userID, msg string) error {
// 1. 将推送请求放入消息队列(Kafka)
err := kafkaProducer.SendMessage(fmt.Sprintf("user_%d", userID), msg)
if err != nil {
return fmt.Errorf("failed to send to kafka: %v", err)
}
// 2. 返回成功(异步处理,客户端无需等待)
return nil
}
// 消费者处理逻辑(Go Worker)
func KafkaConsumer() {
consumer := kafkaConsumer.NewConsumer()
for msg := range consumer.Messages() {
userID, content := parseMessage(msg)
// 异步推送(通过Go Worker池并行处理)
go sendPushAsync(userID, content)
}
}
// 异步推送函数
func sendPushAsync(userID, content string) {
err := pushService.SendPush(userID, content)
if err != nil {
log.Errorf("push failed for user %s: %v", userID, err)
}
}
5) 【面试口播版答案】
面试官您好,我参与过360手机卫士的推送服务项目,核心是解决百万级用户的高并发推送问题。首先,我们采用消息队列(Kafka)作为请求缓冲,把突发请求暂存,避免服务器直接处理导致阻塞。然后,推送逻辑分为两步:第一步快速将请求投递到消息队列,客户端立即返回成功;第二步由消费者异步处理,通过Go Worker池并行推送,这样延迟控制在100ms以内。另外,为了解决资源瓶颈,我们给不同优先级的推送分配独立进程,比如紧急通知用高优先级进程,每个进程固定占用2个CPU核心,这样CPU利用率稳定在70%以下,不会因为资源争抢导致延迟飙升。通过这些设计,我们成功支撑了百万级用户的推送需求,平均延迟低于100ms,资源利用率合理。
6) 【追问清单】
7) 【常见坑/雷区】