
1) 【一句话结论】采用分层架构,通过Redis缓存、ES全文检索、分库分表数据库,结合布隆过滤器防缓存穿透、消息队列异步更新ES、Nginx负载均衡、熔断限流,有效应对开学季流量峰值。
2) 【原理/概念讲解】老师讲解时,先明确核心需求——快速响应、高并发读写。逐一解释各组件:
3) 【对比与适用场景】
| 组件 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| Elasticsearch | 分布式搜索引擎 | 支持全文检索、复杂查询、高并发读写、自动分词 | 课程标题/描述的模糊搜索、多条件组合查询 | 索引维护成本高,不适合事务性操作 |
| 关系型数据库 | 结构化数据存储 | 强一致性、事务支持、ACID | 课程基本信息(ID、价格、讲师ID)的增删改查 | 查询复杂时性能下降 |
| Redis | 内存数据库 | 高速读写、缓存、消息队列 | 热门搜索结果、布隆过滤器 | 缓存穿透/雪崩风险,需设置过期时间 |
| 布隆过滤器 | 哈希集合 | 空间高效、可能误判 | 防缓存穿透,检查ID是否存在 | 存在误判率(如1%),需优化位数组长度 |
| 消息队列(如Kafka) | 异步通信 | 解耦、高吞吐 | ES索引异步更新 | 需确保消息不丢失,处理延迟 |
4) 【示例】用户搜索“Java基础”,系统处理流程:
伪代码(简化):
func searchCourses(keyword string) ([]Course, error) {
// 1. 检查Redis缓存
cached, err := redisClient.Get("search:" + keyword).Result()
if err == nil {
return parseJSON(cached), nil
}
// 2. 检查布隆过滤器
isExist, err := redisClient.PBool("bloom:course:" + keyword, true)
if err != nil || !isExist {
// 不存在,调用ES
esResult, err := esClient.Search(keyword, "title", "description")
if err != nil {
return nil, err
}
// 存入Redis和布隆过滤器
redisClient.Set("search:" + keyword, esResult, 5*time.Minute)
redisClient.PSetBit("bloom:course:" + keyword, 0, 1) // 假设课程ID为0
return esResult, nil
}
return parseJSON(cached), nil
}
5) 【面试口播版答案】(约90秒)
“面试官您好,针对高并发课程搜索系统,我的设计思路是分层架构,核心组件包括Redis缓存、Elasticsearch(ES)和分库分表的数据库。首先,Redis作为缓存层,存储热门搜索词的查询结果,比如“Python入门”这类高频请求,直接从Redis返回,避免ES和数据库压力。然后,ES负责全文检索,通过倒排索引技术快速匹配课程标题、描述等文本字段,支持模糊搜索和多条件组合。数据库方面,我们按课程类型分库,按课程ID范围分表,比如编程类课程放在编程库,数学类在数学库,每个库再分表,避免单表数据过大。流量峰值处理上,开学季时,我们会增加ES的分片数量(比如从5个增加到10个),扩展Redis集群节点,同时用API网关做限流(令牌桶算法,每秒1000请求),防止流量瞬间冲击。针对缓存穿透问题,我们引入布隆过滤器,在Redis中存储热门课程ID的布隆过滤器,检查请求的ID是否在布隆过滤器中,若不在再查询ES,减少无效请求。ES索引更新通过消息队列(如Kafka)接收课程变更事件,定时批量更新索引,或者调整refresh间隔(如1分钟),平衡实时性和性能。负载均衡使用Nginx四层负载均衡,配置轮询策略,将请求分发到多个API网关实例,再由API网关分发到后端服务。熔断器使用Hystrix,配置熔断阈值(3秒内10次失败),确保系统在异常时快速降级。这样整体架构既能保证搜索速度,又能应对开学季的流量峰值。”
6) 【追问清单】
7) 【常见坑/雷区】