文章标签 » 秒杀

一些面试题目

之前逛论坛时,看到了一些经典的面试题,下边讨论的时候,也提供了一些不错的回答,现在把其中一个整理一下,不然老留着链接放浏览器里占位置,存文档里看的机会也会很少。

问题:
1、MySQL 里的记录有这么两个字段:
课程 id,课程余额
同时间大量学生抢同一门课,如何设计这个功能?
2、线上 Redis 内存满了,应该如何处理?这个问题,暂且认为是问线上Redis满了之后的处理方案。当然给了处理方案之后,后续的故障处理流程和优化方案也应该提供一下。
3、你认为解决高并发问题的本质是什么?

首先说第三个问题,根据下边网友讨论提示,这个面试官可能看过《高并发的哲学原理》才会问,链接: https://pphc.lvwenhan.com/
另外,有一个说法感觉说的也非常好:解决高并发的本质就是在业务上避免高并发的场景的产生,看看早年的双十一和现在的双十一。

OK,接下来贴一下一个网友(admol)的答案,如下:

第一问,实际上是在问你系统设计问题
而你只是直接回答了其中很小的一个点(做法),也不能说不对,只能说不完全对。

尝试从下面几个步骤回答下:
1. 多问
- 学校总的有多少学生需要抢课
- 学校大概总的有多少非常热门的课程
- 平均到每门热门课程大概有多少学生会同一时刻抢
- 给出一些人数,然后是否可以估算出 QPS
假设:需要抢课的学生 1000 人,
假设查询课程 QPS 粗略估算:1000QPS ,峰值*2 ,算 2000QPS

- 其他开放性问题,是否有其他要求
2.初步方案
分为两部来进行涉及:
1. 查询课程(查询并发最大)
设计一个高效的索引和缓存机制,以应对高并发查询需求。方案有:缓存、读写分离等
2. 提交抢课
设计一个分布式锁机制,确保同一时间只有一个学生可以成功抢课。方案有:Redis 、ZK 分布式锁、消息队列等

3.详细方案
- 开始抢课之前,提前将课程-课程余额缓存到 Redis 中
- 使用读写分离,分散查询课程和抢课程写结果时数据库的压力
- 使用 Redis 进行扣减余额
- 扣减成功,记录抢课结果(学生-课程)
4.总结
- 缓存、锁、读写分离、其他方案

问题2:线上 Redis 内存满了,应该如何处理?
思路:
1. 解决线上问题,快速恢复线上功能正常访问
- Redis 扩容
- 手动清理不必要的缓存数据,释放内存

线上功能恢复后再做
2. 找出为什么满问题
- 分析 Redis key ,是否是热点数据访问量暴增?
- 是否是 缓存 key 设计不合理
- Redis 配置参数不合理,导致内存使用效率低下
3. 避免为什么满问题
- 针对 2 进行优化,增加监控告警等措施

问题3.你认为解决高并发问题的本质是什么?
- 本质就是在大量的请求和有限的资源情况下,如何来保持系统的性能和可用性等。
- 手段很多:增加资源、减小开销、缓存、服务化、冗余、异步、队列、限流、熔断等

此网友还推荐看《系统设计面试:内幕指南》链接: https://learning-guide.gitbook.io/system-design-interview

以下是另外一个网友(dilu)的回答,这个点赞也比较多,回答也比较成体系,

小菜鸡一枚,尝试回答一下,以下答案没查阅资料也没参考楼上大佬们的答案。

1. 这个问题我觉得可以分开讨论一下,首先如果真的只是学校的抢课场景,从经验来说,那就算有并发也不会有很高的并发,在不保证高可用的情况下(如果真是学校抢课,没必要真的做什么高可用吧?)单台 redis 足够支撑需求了,最简单的实现肯定是 setnx ,但是可以从这里延伸一下,例如锁的时长要设置多久,锁过期了怎么办,要不要重试等等八股文,也可以用 lua 脚本,但是缺点是什么巴拉巴拉(掺杂八股文)
但是如果不是简单的学校抢课场景,而是电商的抢购商品这种场景(说时候电商秒杀的八股文和方案大家估计背的比我熟了吧?)既要保证高可用也要数据一致性的情况下,我觉得可以这样设计:

a) 根据以往秒杀时期的数据前提下,前端直接抛弃一部分流量,例如只有 20%的请求才能真正的请求,80%的请求在前端直接抛弃。
b) 秒杀请求进入队列,这样可以把对 redis db 等资源的峰值削平避免服务出现毛刺。由于是秒杀场景,失败了用户也会重试,所以完全可以不在意消息是否会丢失,这种情况下 mq 的性能绝对是能承载主流量的
c) 在消费的时候,再按照商品纬度加锁,这里可以用 redis 集群模式,也可以用 zk 等等组件,调你熟悉的讲,例如你熟悉 redis 的 redlock 那就讲 redlock ,熟悉 zk 脑裂你就讲脑裂

2. reidis 内存满了怎么办?我认为有也得分类讨论(前提是 redis 满了已经导致服务不可用了,如果配置了内存淘汰策略那就不用在乎满不满了)
a) 首先确认这个 redis 里面的数据是不是全是“缓存型数据”,如果是,可以挑一些 topn 的 key 先删一批,先让服务正常可用,然后迅速扩容,如果能动态扩容最好,如果不行先用 rdb 复制一台更高规格的 redis ,然后切换过去。
b) 如果 redis 后面不是传统 MySQL 或者 qps 不高的情况下,直接重启是最好的办法,当然这种情况不太常见,如果 qps 过高可能会直接拖垮 DB 。
c) 这件事的关键是要做好事后复盘、做好防护,避免下次再出问题,一个是要增加 redis 内存监控告警,超过 80%要告警,其次要配置一下 redis 的缓存淘汰策略,(这里也可以卖弄一下 LRU 之类的八股文)。

3. 我认为并发问题就是资源竞争的边界问题,解决并发的问题就是让资源竞争的请求从并行变成串行(加锁),让无序变有序,让混沌变秩序。这里可以卖弄一下读写锁,互斥锁,CAS ,原子操作之类的八股文。

其次,有一些关于面试的经验,想分享给 V 友们。

1. 面试跟谈恋爱是一样的,眼缘最重要,而不是闯关或者解密游戏,答对所有题,写出所有算法,不会决定你能否通过,能通过面试,一个是因为合适,一个是因为眼缘。而我认为后者的占比更大一些,所以建议可以适当处理一下个人形象,面试的时候别太颓废,别太随意。不管是面试还是生活中,看起来让人舒服的人,总能占更多的好处。

2. 面试的时候,问题不会,算法不会是很正常的一件事,计算机的知识没人能做到全都懂,你需要做的是把握面试节奏,让面试官去讨论你熟悉的东西,引导面试官的话题。例如楼主的题目,问你 redis 怎么实现分布式锁,如果你不熟悉 redlock 但是你熟悉 zk 那就说不好意思面试官,xxx 我不太熟,但是 zzz 我用的比较多,zzz 的原理是这样的 balabala 。要把节奏掌握在自己手中。

3. 面试官不一定能决定你是否通过,很多情况下还是 HR 话语权大一些

4. 面试前最好了解一下面试的公司和部门,他们有什么产品?主营什么业务,熟悉一下,对方问起来可以增加一些好感。

5. 面试必问,自我介绍、离职原因、语气薪资,这些问题一定要提前想好避免回答的时候大脑一片空白。

以上挑选了两个比较完整、认真的回答,保存下来,自己也多温习,毕竟基础不能丢啊。