美团面试题

转自:https://cloud.tencent.com/developer/article/1348115

一面

hashmap与concurrenthashmap的区别

垃圾回收算法以及垃圾回收器

CMS的回收步骤

G1和CMS的区别

CMS哪个阶段是并发的哪个阶段是串行的?

G1内部是如何分区的(region)

HashMap如何解决Hash冲突

my sql 索引类别

什么是覆盖索引

扫描二维码关注公众号,回复: 5853255 查看本文章

b+树和b树的区别

为什么选用自增量作为主键索引

my sql如何优化查询

my sql如何在RR隔离级别下避免幻读问题:间隙锁

my sql范式和反范式的区别以及彼此的优缺点

AOF如何缩减自身文件大小

AOF缩减自身文件大小的时候,数据库来了新的操作怎么办?

多线程了解么?

死锁条件以及破坏死锁条件的方法

volatile做什么用的,如何实现可见性的

volatile和atomic的区别

atomic底层是如何实现的

二面

表锁 行锁 乐观锁 悲观锁的特点和区别

并发工具包有哪些,具体怎么用

Lock和Synchronized的区别

分布式下redis如何保证线程安全

Kafka讲一讲

Docker平时怎么使用的

几种线程池区别

Kafka如何解决数据堆积

kafka消息的存储机制

如何用kafka保证消息的有序性

kafka如何保证并发情况下消息只被消费一次

三面

redis用的哪个版本

如何搭建redis集群

redis如何主从同步

redis分布式锁注意事项

redis持久化的方式以及区别

redis持久化方式及区别

my sql数据量多大的时候需要分表

my sql常用的存储引擎及区别

死锁的条件及应对措施

zookeeper的作用:分布式锁、注册服务中心

zookeeper如何实现分布式锁、其他分布式锁怎么实现

分布式事务的解决方案

单点登录怎么实现

秒杀系统怎么来实现

HR面

1.自我介绍啊

2.为啥想来美团,对美团了解多少

3.心中的互联网公司排序

4.工作中遇见暂时无法解决的问题,你怎么来应对

5.自己的优点和缺点

6.未来的职业规划是什么

互联网特别是电商平台,阿里双11秒杀、还有12306春运抢票、以及平时各种节假日抢购活动等,都是典型的高并发场景。

这类场景最大的特征就是活动周期短,瞬间流量大(高并发),大量的人短期涌入服务器抢购,但是数量有限,最终只有少数人能成功下单。

这里,就来讲一讲对应该场景下需要考虑的技术实现。

先从基本的概念的建立,再讲对应的实现部分。

第一:高并发

技术要做的事,一方面优化程序,让程序性能最优,单次请求时间能从50ms优化到25ms,那就可以在一秒钟内成功响应翻倍的请求了。

另一方面就是增加服务器,用更大的集群来处理用户请求,设计好一个可靠且灵活扩充的分布式方案就更加重要了。

第二:时间短

火热的秒杀活动,真的是一秒钟以内就会把商品抢购一空,而大部分用户的感受是,提交订单的过程却要等待好几秒、甚至十几秒,更糟糕的当然是请求报错。

那么一个好的秒杀体验,当然希望尽可能减少用户等待时间,准确的提示用户当前是否还有商品库存。而这些,也是需要有优秀的程序设计来保证的。

第三:系统容量预估

系统设计的时候,都需要有一个容量预估,那就是要提前计算好,我们设计的系统,要承载多大的数量级。

假如线上前端服务器规格是8核16G内存的服务器,而提交订单的处理程序耗时100ms,那么可以简单计算一下:

每秒可以处理的订单请求数=1000ms/100ms*8=80qps

上面这个结果,对于秒杀系统来说,肯定是非常不理想的。

如果能将处理程序耗时优化后,降低到10ms,那么就可以达到800qps。

如果我们可以把程序继续优化,能快速区分开有库存和无库存处理,那么无库存时处理就有可能做到1ms甚至更低的耗时。这样无库存时就能有更好的性能,上万的qps也是可以达到的。

上面的预估,都是针对单机,那么简单的增加前端服务器,是不是就能有更好的并发处理量呢?

肯定没这么简单,因为数据库、缓存系统甚至机房网络带宽都会成为瓶颈。

于是就要有一个更好的分布式方案。

第四:好的分布式方案

一个好的分布式方案,首先当然是稳定可靠,不要出乱子,然后就是方便扩充,最好的效果当然是增加一台服务器,并发处理量可以1:1线性增长。

比如:单机qps是1k,那么10台服务器可以做到1w,100台可以做到10w每秒。

要做到这样的线性增长效果,就要杜绝出现瓶颈,否则还是会代价太大。

拒绝假的分布式尤其重要,比如:前端服务器是可以独立存在的,但是都依赖集中的一个数据库或者缓存系统,那最后,一定是集中的那个数据库或者缓存系统受不了,同样无法做到一个好的分布式。

第五:关注系统的瓶颈

大家先有几个基本的共识,系统的处理速度

程序内数据读写 > redis > mysql > 磁盘

单机网络请求 > 局域网内请求 > 跨机房请求

我们优化程序的时候,尽量用最快的方式,尽量用最简短的逻辑。

用redis替代mysql来保存订单处理中依赖的数据,用程序中的提交的数据代替从redis中二次获取数据,比如:商品库存信息,用户订单信息。

逻辑处理中,把速度快且提前中断的逻辑放在最前面,比如:验证登录,验证问答。

我们做分布式方案的时候,尽量把资源调用放在最近的地方。

前端服务器依赖的数据尽量就在局域网内,如果能在单机都有读的redis服务当然更好,程序维护数据响应会复杂些。

不要出现跨机房网络请求,不要出现跨机房网络请求,不要出现跨机房网络请求,重要的事情说三遍。

第六:什么语言更适合这类系统

当然,像是用golang, ngx_lua可能在高并发和性能方面会更有优势。

如果使用java、php当然也是可以的,作为一个系统,语言只是工具,更好的设计和优化,才能达到最终想要的效果。

有了上面的基本概念,我们接下来再来看看,具体运行时,会出现什么状况。

下面是一些具体的实现问题:

问题1:库存超卖

只有10个库存,但是一秒钟有1k个订单,怎么能不超卖呢?

核心思想就是保证库存递减是原子性操作,10--返回9,9--返回8,8--返回7。

而不能是读取出来库存10,10-1=9再更新回去。因为这个读取和更新是并发执行的,很可能就会有1k个订单都成功了,而库存实际只有10。

那么,怎么保证原子性操作呢?

1 数据库:

update product set left_num=left_num-1 where left_num>0;

这里用到的是left_num=left_num-1,如果left_num>0才能执行成功,数据库查询、更新的时候有用到锁,是可以保证更新操作的原子性的。

数据库性能较差,不建议使用。

2 分布式锁

用redis来做一个分布式锁,reids->setnx('lock', 1) 设置一个锁,程序执行完成再del这个锁。

锁定的过程,不利于并发执行,大家都在等待锁解开,不建议使用。

3 消息队列

将订单请求全部放入消息队列,然后另外一个后台程序一个个处理队列中的订单请求。

并发不受影响,但是用户等待的时间较长,进入队列的订单也会很多,体验上并不好,也不建议使用。

4 redis递减

通过 redis->incrby('product', -1) 得到递减之后的库存数。

问题2:集群怎么来规划

前端服务器因为没有相互间关联,集群的数量不受影响。

redis的性能可以达到每秒几万次响应,所以一个集群的规模,也就是redis服务可以承载的数量。

比如:一台前端服务器是1~2k的qps(有库存时),那么10台+1台redis就可以是一个独立的集群,可以支撑1~2w每秒订单量。

10个上述的集群就可以做到一秒钟处理10w~20w的有效订单。

如果秒杀活动的库存量在1w以内,预计参与的人数在百万左右,那么有一个集群也就可以搞定。

如果秒杀参与的人数超过千万,那么就要用到不止一个集群了。

问题3:多个集群的数据怎么保持一致性

不要做多集群的数据同步,而是用散列,每个集群的数据是独立存在的。

假设,有10个商品,每个商品有1w库存,规划用10个集群,那么每个集群有10个商品,每个商品是1k库存。

每个集群只需要负责把自己的库存卖掉即可,至于说,会不会有用户知道有10个集群,然后每个集群都去抢。

这种情况就不要用程序来处理了,利用运营规则,活动结束后汇总订单的时候再去处理就好了。

如果担心散列的不合理,比如:某个集群用户访问量特别少,那么可以引入一个中控服务,来监控各个集群的库存,然后再做平衡。

问题4:机器人抢购怎么办:

没什么太好的办法,类似DDOS攻击,只能是让自身更强大才是王道。

运营策略上,可以严格控制用户注册,必须登录,提交订单的时候引入图像验证码,问答,交互式验证等。

猜你喜欢

转载自blog.csdn.net/ruanhao1203/article/details/88924474