时间:18年5月14
地点:北京某回迁房内
人物:博主
情景:正在打扫房间卫生,接到阿里蚂蚁面试电话
目标岗位:java 开发
面试到的知识点:多线程并发,锁机制,系统设计,机器学习算法,排序算法,消息队列,数据库主从模式,分布式锁
面试结果:跪的没边
反思:凡是预则立,不预则废。立即准备,差的不是丁点。
问到的问题
- 1 设计一个秒杀系统需要注意的地方 数据库的同步机制
- 2 设计一个消息队列 生产者消费者模式,如何一个生产者和多个消费者保证每个消费者读到的是自己的消息,并且并发啥的也可以保证
- 3 kafka在消息队列中的应用,包括其原理
- 4 用java如何实现一个线程池,需要注意哪些地方 核心线程数等
- 5 java的锁机制,如何实现锁以及java分布式锁 (重点)
- 6 项目讲解
- 7 分布式数据库锁机制
后期answer整理
1 秒杀系统涉及的知识点:
A 高并发,cache ,锁机制
B 基于缓存架构redis,Memcached的先进先出队列
C 稍微大一点的秒杀,肯定是分布式的集群的,并发来自于多个节点的JVM,synchronized所有在JVM上加锁是不行了
D 数据库压力
E 秒杀超卖问题 ??
F 如何防止用户来刷,黑名单?IP限制
G 利用memcached的带原子性特性的操作做并发控制.
2 淘宝的秒杀设计:
1 前端:三板斧【扩容】【静态化】【限流】
A 扩容:
加机器,这是最简单的方法,通过增加前端池的整体承载量来抗峰值
B 静态化:
将活动页面上的所有可以静态的元素全部静态化,并尽量减少动态元素。通过CDN来抗峰值。
C 限流
一般都会采用IP级别的限流,即针对某一个IP,限制单位时间内发起请求数量。或者活动入口的时候增加游戏或者问题环节进行消峰操作。
D 有损服务
最后一招,在接近前端池承载能力的水位上限的时候,随机拒绝部分请求来保护活动整体的可用性。
2 后端
A 首先MySQL自身对于高并发的处理性能就会出现问题,一般来说,MySQL的处理性能会随着并发thread上升而上升,但是到了一定的并发度之后会出现明显的拐点,之后一路下降,最终甚至会比单thread的性能还要差。
II: 其次,超卖的根结在于减库存操作是一个事务操作,需要先select,然后insert,最后update -1。最后这个-1操作是不能出现负数的,但是当多用户在有库存的情况下并发操作,出现负数这是无法避免的。
III:最后,当减库存和高并发碰到一起的时候,由于操作的库存数目在同一行,就会出现争抢InnoDB行锁的问题,导致出现互相等待甚至死锁,从而大大降低MySQL的处理性能,最终导致前端页面出现超时异常。
3 秒杀场景:
1 校验库存
2 扣库存
3 创建订单
4 支付
4 乐观锁更新 + 分布式限流 + Redis 缓存
其实这是实时查询库存的 SQL,主要是为了在每次下单之前判断是否还有库存。由于我们的应用是分布式的,所以堆内缓存显然不合适,Redis 就非常适合。
A 每次查询库存时走 Redis。
B 扣库存时更新 Redis。
C 需要提前将库存信息写入 Redis(手动或者程序自动都可以)。
5 乐观锁更新 + 分布式限流 + Redis 缓存 + Kafka 异步
每当一个请求通过了限流到达了 Service 层通过了库存校验之后就将订单信息发给 Kafka ,这样一个请求就可以直接返回了。
消费程序再对数据进行入库落地。因为异步了,所以最终需要采取回调或者是其他提醒的方式提醒用户购买完成。