首发于

介绍

17 年毕业双非一本。面试抖音社区安全部门,以 java 进行面试。

字节一面

  1. 先进行自我介绍
  2. 问:数据库,中间件用了什么?答:mysql+postgres+kafka+redis
  3. 问:有用过 ThreadLocal 吗?使用的场景是什么?答:用过,在登录的时候记录用户的登录信息。
  4. 问:具体怎么实现?答:在拦截器中对 token 进行解析,然后将用户信息写入 ThreadLocal。
  5. 问:拦截器具体要实现哪个接口记得吗?答:不记得。
  6. 问:有的接口需要进行登录判断,有的不需要这个怎么处理?答:使用注解,标记不需要登录判断的接口。
  7. 问:ThreadLocal 原理有了解吗?答:内部是一个 Map,由线程持有,这是它线程安全的原因。ThreadLocal 与 Map 之间是弱引用,误用会造成内存泄漏。
  8. 问:为什么会造成内存泄漏?答:弱引用在 GC 时会被回收,由于线程还是活跃的,还是有强引用在 Value 上,所以 value 不会被回收,但是 Map 中对应的 key 会变成 null。
  9. 问:什么时候去请求 key 为 null 的数据(如何避免)?答:get/set/remove(和面试官产生分歧,我坚持自己印象中的内容),使用完 ThreadLocal 之后及时 remove。
  10. 问:线程池核心参数?答:五个,核心线程数、最大线程数、最长活跃时间、阻塞队列、拒绝策略。
  11. 问:阻塞队列用过哪些,使用场景是怎么样的?答:只用过 ArrayBlockingQueue 和 PriorityBlockingQueue。
  12. 问:锁升级过程?答:~
  13. 问:遇到过线上 JVM 问题吗?答:没有
  14. 问:线上 JVM 配置是怎么样的?答:设置最大堆,最小堆,gc 收集器为 G1
  15. 问:为什么线上使用 G1?答:没想过。。。
  16. 问:G1 和 CMS 什么区别?答:CMS 多线程并发,采用标记清除算法,追求更快的 GC 速度。G1 将内存分为小块,追求更高的回收效率。
  17. 问:什么时候用 G1,什么时候用 CMS?答:不清楚
  18. 问:介绍下项目,和一些细节?答:。。。主要介绍一下项目背景和方案,然后将一下有亮点的设计,比如为何要这样设计:我有个设计就是借用了 HashMap 的链表变红黑树的阈值 8,红黑树变链表的阈值时 6 这个思想(留下一定的缓冲空间避免频繁变化)。然后可以谈谈这个方案的不足,与改进的方向与思考。
  19. 问:解决热点 key 的方案?答:1.内存缓存 2.拆分多份
  20. 问:限流算法?答:窗口计数,漏桶,令牌桶(详细解释一下)
  21. 问:分别使用的场景?答:不清楚
  22. 问:分布式情况下如何实现漏桶和令牌桶?答:令牌桶可以以一定速率写到 redislist 中,然后接口上来先拿一个令牌。漏桶不知道。
  23. 问:mysql 什么时候用主库,什么时候用从库?答:事务,写用主,读操作用从。因对主从复制延迟,需要马上知道的数据,使用主。
  24. 问:主从复制,基于什么?答:binlog,复制八股文。
  25. 问:主从复制有几个线程?答:这里答错了,应该是有三种线程。
  26. 问:主从复制模式?答:同步,半同步,异步(介绍)。
  27. 问:半同步是等待几个从回答?答:一个。
  28. 问:binlog 模式?(这里应该是想问 binlog 的格式)答:不知道(应该是 statement,row,mixed)
  29. 算法:有一个递增数组,但是拥有重复数字,需要原地将重复数字移到数组的后面。 比如 [10,11,11,12,12,12,13,14,15,15,15] 移动之后 [10,11,12,13,14,15,11,12,12,15,15] 前面的部分自增有序,后面的部分,不要求递增与有序 空间复杂度要求为 O(1)

总结:这轮面试,答得不是很好,很多东西都没答上来,最后的算法也写了有二十多分钟。总得来看表现不是特别好,但还是过了面试。 平时还是更注重积累一些工具的使用场景。

字节二面

  1. 自我介绍
  2. 介绍项目(很细,各种细节,持续了半个多小时)
  3. 问:Redis zset 结构,底层数据结构。答:ziplist,跳表+字典
  4. 问:跳表的数据结构。答:多层的链表结构
  5. 问:跳表的插入过程。答:略
  6. 问:如何确定层数。答:抛硬币算法
  7. 问:为什么要用抛硬币,解决什么问题。答:应该是为了让层数分布更均衡(不确定)
  8. 问:抛硬币正反面概率是 50%吗?答:不清楚
  9. 问:跳表查询过程。答:略
  10. 问:数据重复怎么办。答:字典+跳表。score 不一样,再插入一个。值一样,更新 score
  11. 问:http 协议了解吗?答:了解不是特别多(跳过了)
  12. 问:常用索引类型?答:聚簇索引,非聚簇索引。
  13. 问:非聚簇索引与聚簇索引使用说明数据结构?答:使用 B+Tree
  14. 问:B+Tree 有哪些好处?答:1. 优化 IO 2. 方便范围查询 3. 局部访问原则
  15. 问:B Tree 与 B+Tree 的区别?答:B Tree 节点上存数据,IO 更多。范围查找支持不好
  16. 问:非聚簇索引与聚簇索引的却别?答:非聚簇索引只存索引与主键。
  17. 问:ABC 三个字段联合索引,什么时候不需要回表?答:只查询 id+ABC 三个字段不需要回表
  18. 问:ABC 联合索引,where A and B > 2 and C =3,能否使用索引,为什么?答:A,B 能用,C 不行。最左前缀原则。(但是不会回表,c=3 会由索引下推规则判断)
  19. 问:原子性如何实现?答:支持 rollback,由 undolog 实现
  20. 问:事务开启到回滚如何实现?答:略
  21. 问:undolog 存的是什么?答:逻辑日志,记录改动内容
  22. 问:持久性如何实现?答:保证 crash-safe 能力,redolog + binlog 的二阶段提交。
  23. 问:如何表现?答:二阶段提交过程(略)
  24. 问:事务提交成功,redolog 可能没写到磁盘吗?答:redolog 不 fsync (redo log 刷盘的三个策略)(事务没提交也可能已经落盘)。
  25. 问:此时能否保证数据不丢?答:不行。
  26. 设计题:设计拼手气红包(并发是春晚发红包)?答:(避免重复抢、红包分配问题、超发问题)略。
  27. 算法:最长无重复子串

总结:这一面表现的不错,面试官问的问题基本都答上来了。给我的感觉就是,面试官及其的细致,细致到一个 redis 键的键名怎么设计都需要说清楚。

字节三面

  1. 自我介绍
  2. 介绍项目
  3. 问:如何解决死锁?答:锁定资源顺序,优先级保持一致。(答的不是很好)
  4. 问:事务管理器如何设计?答:threadlocal,aop 加 栈。在栈里保存方法的执行先后顺序。
  5. 问:Concurrenthashmap 做了哪些优化?答:分段锁改为 cas+自旋,synchronized。
  6. SQL 题:公司部门表与部门员工表,找出部门人数最多的部门列表(人数最多的部门可能不止一个)答:
select a.dept_id from (select dept_id,count(id) as count from dept_user group by dept_id) as a ,(select dept_id,count(id) as count from dept_user group by dept_id order by count desc limit 1) as b where a.count = b.count
  1. 设计题:抖音关注设计,要求:1. 判断自己是否关注对方。2. 判断对方是否关注自己 。答:使用 redis 的 hash,维护自己的关注列表和粉丝列表。注意判断 大 V 是否关注自己,使用自己的粉丝类别来判断。

  2. 设计题:观看抖音的视频 feed 流。答:核心为 读扩散和写扩散。

    1. 每个用户都有一个观看列表
    2. 小 V 发布视频写入自己粉丝的观看列表(写扩散)
    3. 大 V 发布视频,粉丝从大 V 的发布列表读取数据(读扩散)
    4. 拉去视频流,从自己的观看列表中选取 N 个视频,然后从自己关注的大 V 中选取 M 个大 V,分别去他们的发布列表拿去一个视频。共 N + M 个视频,下发给观众。
  3. 问:大 V 掉粉变成小 V 过程,如何避免频繁变化?答:参考 HashMap,列表变红黑树过程,设置一个缓冲区。例如:10 万粉丝变大 V,但是要掉到 8 万粉丝一下才会变小 V。

总结:细,还是很细。但是三面关注的更多的是系统设计。属于凑巧了,在面试前研究过很多 feed 流的设计,而且自己本身的工作也和 feed 比较类似,所以这面答的还不错。这面没有算法题,估计是因为太晚的缘故。

总结

三场面试,历时一个半星期,之后就是 HR 面和等着走流程发 offer。整个过程持续三个星期,最终还是拿到 offer 了。 感觉下来,这次的面试很细致,面试官给我的感觉很也好。感觉上一面最难,因为知识点的广度很深度都涉及到了。