抖音电商面经(已offer)
时间点如下:6.10投递 -> 6.20一面 -> 7.1二面 -> 7.15三面 -> 8.1 hr面 -> 8.8口头 -> 8.17 offer,流程拉的很长,hr明确告知就业环境发生变化,需要横向比较。
一点思考
字节比较看重算法题,着重挑选有acm经验的人,这三轮面试都出了算法题。幸亏提前刷了一个月的算法题,且拿其他公司练手了几轮,最后都写出来了。按照以往,算法能做出来,通过的概率是非常高的,但是今年候选人太多了,写出来也不能稳过,而且薪资涨幅比以往低了很多,来来回回跟hr扯了很久。整体比较注重问题排查经验,讲究系统设计和架构经验,深挖分布式理论,常见系统设计题有:
分布式id、短链、feed流、微博、微信红包、日志监控、直播弹幕等,重点考察需求分析、存储设计,服务交互,注重高性能、高可用、可扩展。
系统设计题:https://www.cnblogs.com/crazymakercircle/p/14367907.html,https://www.modb.pro/db/135068
javaguide: https://javaguide.cn/
今年找工作十分不易,市场候选人很多,希望这篇面经能帮到大家~
抖音电商一面(6.20 15:00)
- 设计一个微博feed流系统
- 大v发消息时可能会扩散,单独搞个信道,只写一次。
- 粉丝来拉取时从该发信箱拉取,每个关注的明星都去拉一遍明星的信道,可能就关注了10个明星,然后做一下排序。再展示出来。那分页呢?
- 粉丝拉取明星消息如何优化?
- 粉丝关注的明星,有个关联关系,按照粉丝分表就行。也可以做缓存。双向建表。。
- 长轮询,避免空拉,也可以websocket用推送。
- 批量聚合一些再推送,而不是来一条推一条
- 推模式:推到用户的收信箱
- 拉模式:从发送方的发信箱拉取。
- 加缓存避免热key问题,毕竟读多写少,对第一页加下缓存,避免缓存全量。尤其对于大v的发信箱的拉取,需要做好多级缓存,避免热点问题。
- 客户端根据消息id做去重,分页查询
- 双向分库分表,牺牲空间换时间。user-ses/ses-user。如果不分库分表,建立双向索引即可。
- 如果使用写扩散,可以对在线的用户立即写,离线的用户,写入到kafka里,异步去写就可以了。但是会有很多废弃的账号,存储会有很大的冗余。删除也不好删。更新也不好更新。
https://developer.aliyun.com/article/706808
普通用户去拉大v的发信箱,则需要并发拉很多个,例如很多条关注者的微博,需要进行动态排序。
普通用户给普通用户发消息,直接投递到对应的收信箱即可。
随着业务的增长,推模式资源浪费会越发严重。原因在于两点:第一存在着大量的僵尸账号,以及大比例的非活跃用户几天或者半个月才登陆一次;第二信息过载,信息太多,重复信息太多,垃圾信息太多,用户感觉有用的信息少,消息的阅读比例低。这种情况下推模式相当一部分在做无用功,白白浪费系统资源。
单向关系(关注)和双向关系(朋友圈)。
https://www.jianshu.com/p/f8f0930f9d68
https://juejin.cn/post/7025208419875291166mget一次性获取多个key的数据,减少多次网络调用。但是前提是在同一个分片上。可以增加redis分片节点,分配slot,避免某个节点请求量太大。
这里还可以通过用户行为去维护一个活跃粉丝列表,对于该列表中的粉丝,同样进行一个写扩散的行为,保证即时触达。
维护三张表,t_feed内容表(user_id分表),t_like粉丝关注表(user_id分表),t_inbox收信表(user_id/feed_id),大v发消息时,写入t_outbox即可。粉丝读消息时,除了查询自己的t_inbox(推),还要查询下粉丝关联关系,过滤出大v,从每个大v的t_feed拉取消息feed_id(拉),然后进行倒序排序,返回给粉丝查看,这里可能要分页。每条消息详情可以根据feed_id进行缓存。mget
如果有多维度查询需求,需要建立搜索的索引。例如监听binlog。
如何优化粉丝读取压力?拉取关联关系时,增加缓存user_id -> likeId list,然后根据likeId缓存对应的最近的100条消息内容。第二个需要增加本地缓存,避免热查询。之后聚合排序取前n条,可以对第一页做缓存。
如何标记粉丝是否读取该大v消息,增加一个feedId_userId关联表。
算法题:打家劫舍II
NoSQL比RDB(关系型数据库)的好处是,
- 框架层就考虑了自动扩容、在线扩容、节点分片,例如hbase、es、redis-cluster,有的还考虑了自动均衡节点数据;而MySQL未考虑可扩展性,扩容时,需要自己去设计实现。
抖音电商二面(7.1 11:00)
- 算法:分糖果2
- 服务发现怎么实现?zk怎么保证数据一致性
- 为什么要过半数投票
- 从选主的角度来看,最多只可能有一个从节点收到的票数大于 N/2 + 1,防止脑裂(多主)
- 从数据同步确认的角度看,quorum机制,收到过半确认,即可以提交,表示当前有过半节点是最新的,如果读取过半节点,一定有一个数据是最新的。
zk选主投票的原则有哪些?
选主的原则就是选择数据日志比较新的那个(zxid),同时轮次是最新的(term/epoch)。选主也是过半投票选举,需要看票是否允许改投。
mysql 回滚怎么实现,有用到redolog么
redis string怎么实现的,针对大key如何节省空间?
- sdshdr{len:当前使用的长度, free:当前剩余的长度, buf,最后还是以\0结束,总容量为len + free + 1},
- 递增长度的,如果len < 1mb,则扩容后,free = len,如果超过了,则会保留free=1MB。这里是不是free不够len,才会扩容,如果超过了len,则不用动。
- 缩短长度时,不会把free释放掉,当然也可以手动释放
https://blog.csdn.net/pugongying_95/article/details/99718749
kafka和rocketmq有什么区别,怎么用?
rocketmq有同步和异步发送,两种,同步的话,实时性强些。一个大队列,可以新建很多个topic,kafka至多构建64个topic,不然会出现随机IO的情况,性能下降。支持延迟消息、事务消息等。
https://blog.nowcoder.net/n/65c0e36c0d3743df9270b6e0ed8e8429系统设计题:设计一个抢券系统,一个主播发放一万张券,大量人来抢券,如何设计。
- 发券时,存db,然后预初始化当前券的库存数量到redis,也就是一个key。
- 单个请求如果该用户已经请求过了,直接拒绝掉。且只能请求一次。拿到券后,存一个分配的key到redis中。
- 先单机计数限流,限流请求量为1w个,超过了直接返回失败。
- 然后在redis初始化一个1w的计数器,拿到计数的请求通过,没有拿到的直接拒绝。
- 可以把拿到请求写到kafka里,异步操作数据库消费,扣库存,有一定延迟。数据库扣库存时,一定要加上条件,where 剩余库存>0
- 实时的情况,就要操作数据库,要分库分表,将写请求打散,1w的库存,均摊到100个db里,拿到1-100编号的,操作第一个db,拿到101-200的操作第二个db,扣库存,依次类推,如果没有库存了,直接返回失败。这种方式没法显示剩余库存比较麻烦。
- 超卖和少卖问题
- 用的是redis,跟秒杀有点类似了,将大量无效流量拦截在上游,接口防刷,防黄牛:https://zhuanlan.zhihu.com/p/112713743
抖音电商三面(7.15 10:30)
- 装修是怎么做的?多租户隔离具体怎么做的?
- 从c端开始整体的链路说一下
- 算法题:k个一组翻转链表