当前位置:   article > 正文

比特跳动公司的三面

比特跳动

上回说到程序员小扎在通过二面之后,最终来到了技术的最后一面。

最后一面当然是我们接下来要讲的这位技术总监,这位技术总监安静的看着程序员小扎的简历,然后说到:我看你的之前的工作做过支付相关的业务,那我问你如果收到了两次微信或者支付宝的回调通知该怎么办?
「小扎」:哦哦,这个我们一般会做幂等,支付回调一般会有订单ID这样的信息,我们只要判断同样的订单ID是否已经处理过,如果处理过了,就直接忽略就好了。
「总监」:那如果在支付过程中,商品库存减成功了,用户的订单更新失败了怎么办?
「小扎」:这个我们一般会用事务来保证数据的一致性。
「总监」:这么说你们用的是MySQL数据库了吧。
「小扎」:是的。
「总监」:那你们的MySQL用的主从模式吗?
「小扎」:是的,一主多从模式,主提供写,从提供读。
「总监」:这里我有个问题,如果下订单的过程中,需要先去查询订单情况,这时候如果读的是从库,因为延时问题,会不会读不到最新的数据,导致数据出现问题?
「小扎」:如果要考虑延时问题,那么一般在对数据实时性要求比较高的场景中,我们会直接读主库,避免因为从库延时问题而读到老数据。
「总监」:我看有的架构让其中的一个从节点默认延迟一个小时,你觉得这样的好处是什么呢?
「小扎」:这个我懂,如果某天不小心删除或者更新了什么数据,然后后悔了,这时候我们可以在一小时内通过这个延迟复制的从节点找到被误更新或者删除的数据。
「总监」:那主从模式是依赖什么日志来复制的?
「小扎」:binlog,正常情况下开启binlog后,变更的sql会发给从节点,每个从节点根据binlog的内容来执行同样的sql达到数据一致。
「总监」:你说binlog里记录的是变更的sql是吧,那如果我执行了这样的sql:

update user set money=money+0.1 where money=rand()

由于rand会生成一个随机数,那么主库和从库同样执行这条sql大概率是会更新不同的数据的,这样不就会导致主从不一致了?
「小扎」:是的,其实binlog不仅仅支持这种statement模式(sql变更记录),还支持row模式,在row模式下,不再记录变更的sql,而是记录具体“这条数据变更了什么”,这样的话通过row模式,即使像rand()这样的随机数也不会出现主从不一致的情况。
「总监」:row模式是屌,但是row模式好像不太完美,你知道row模式的缺点吗?
「小扎」:知道的,row模式比较耗费存储空间,但是我们可以通过配置mixed模式(混合模式),这样的话,MySQL会根据实际情况判断,比如对于不会引起主从不一致的sql,直接用statement模式,对于会引起主从不一致的sql则会采用row模式,这样既保证了数据的一致性也不会因为全部使用row模式而占用过多存储空间。
「总监」:好的,被你装到了,我们接着回到订单的问题吧,如果某一天老板做活动,打算放1千个ipad mini7,价格是平时的1折,但是据悉有10万人来抢,你如何让你的接口抗的住?
「小扎」:你说的是秒杀吧(还有mini7是什么鬼,还没上市吧,这一看就是冒牌货,还有打1折是什么意思,直接打骨折算了),正常来说,分为前端限流和后端限流,前端的话,比如用户在点了下单按钮之后,让按钮置灰,这样用户第二次就会点击不了,避免疯狂的点击造成过多的无用的请求,后端的话,这样大的请求直接走数据库肯定不行,可以把请求存到redis队列里,redis的性能还是非常强的。
「总监」:嗯,说的还是比较浅的,你说前端把按钮置灰,避免用户二次点击,那如果用户再次刷新页面呢?
「小扎」:刷新页面的话,可以请求服务端,前面对于每个请求不仅仅让其进入队列排队待处理,还可以设置一个hash,hash的时间复杂度是O(1),这样当用户刷新页面请求的时候,可以根据用户订单是否已经在redis的hash表中来告诉当前是否可以继续下单。
「总监」:那还有什么办法可以减少疯狂刷新页面造成的请求吗?
「小扎」:有,对于已经下单的用户,可以存一个标记到浏览器本地的localStorage中,这样下次刷新的时候可以先校验本地的localStorage是否已经有对应的标记,有的话,就不用去服务端请求了,说明当前已经下单正在排队中,对于没有下单还在恶意刷新的用户,前端可以做个拦截,比如就算疯狂刷新,也不是每次都去请求,而是每隔1s请求一次。
「总监」:嗯~,你说服务端用hash来判断用户是否已下单,比如userid=100的用户如果下了单就存hash[100]=1,hash表的速度应该没问题,但是还有其他的更加节省空间的方法吗?
「小扎」:可以用bitmap来存,每个user_id占用一个比特位,非常节省内存。
「总监」:前面你说到每个成功下单的请求进入队列,这有问题吧,一共只有1000个商品,如果有10000个排序的用户,那岂不是9000个用户都抢不到。
「小扎」:(真的是,以前只在一个小公司接过支付,一天一共也就10来单,非要考我秒杀,要不是前公司黄了,我被公司秒杀了,会被你今天问秒杀~),这确实,不过由于是活动,商品数量有限,我们可以提前把总的商品数量set到redis里,这样每来一个请求,对应的总数就减一,当总数等于0的时候,直接告诉用户没有库存了,都不用进入排序的队列,这样在客户端拿到服务端没有库存的信息后,再次设置下localStorage,这样不管你有没有下过单都直接返回,不用去请求服务端,这样甚至可以拦截大量的无用请求。
「总监」:你这看起来还不错,但是好像没法保证数据的一致性呀,比如设置bitmap成功、减库存失败、进订单队列失败或者设置bitmap成功、减库存成功、进订单队列失败。
「小扎」:(你是真的

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/算法编织者/article/detail/62393
推荐阅读
相关标签