ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

映客2020春招研发A卷拆解:直播高并发与系统设计考点全解析

映客2020春招研发A卷拆解:直播高并发与系统设计考点全解析 说实话第一次完整刷完一套直播行业的春招研发笔试题比我想象中要“值”得多。映客2020春招研发A卷这份卷子单看名字可能以为只是普通的一套校招笔试题但它把直播业务里真正折磨人的点几乎都问了一遍高并发读写、实时消息、网络传输、缓存和一致性。我当时刷完的感受是这套卷子不是拿来凑数的是真的在筛选“能直接上手干活”的研发。这份卷子适合谁看如果你是准备春招/秋招的后端、客户端方向应届生或者想转行直播/IM行业的研发都值得认真过一遍。它不是那种纯刷题就能过的卷子算法题占比适中但网络、操作系统、系统设计的深度明显比普通互联网公司笔试要狠。接下来我就按卷子结构把每一块的考察意图、解题思路、容易踩的坑全部拆开讲清楚。1. 一套直播题把研发能力模型全串起来了先别急着看具体题目我建议你拿到任何一套公司笔试题第一步都先想一个问题这家公司到底想招什么人映客的核心业务是视频直播直播是典型的“实时互动”场景用户对延迟、流畅度、消息到达率极其敏感。研发团队要解决的核心矛盾就是有限的服务资源扛住不定期的流量尖峰同时保证用户之间互动不卡顿、不丢消息。带着这个视角再回看A卷可以发现整张卷子都在围绕直播业务做能力筛查网络题考的是推流和拉流链路涉及到的协议底层操作系统和并发题对应的是弹幕、礼物这种高并发写场景算法题表面上是常规题但套了一层“礼物排行榜”“用户去重”之类的直播业务壳最后一道系统设计题更是直接让你设计一个弹幕/聊天系统。说白了这家公司想知道的是你懂不懂实时互动系统会遇到的真实问题有没有能力给出可落地的方案。1.1 从直播功能反推考点我把直播场景里的核心功能列过一张表再看这张卷子基本上可以对号入座直播模块背后技术问题A卷对应考点推流、拉流播放网络协议、弱网优化、CDN调度TCP/UDP、HTTP、DNS弹幕、评论、送礼高并发写入、消息广播、有序性线程池、锁、消息队列礼物榜、热度榜海量数据排序、实时TopK堆、快排、数据结构直播间状态、用户信息缓存加速、数据一致性缓存穿透、击穿、雪崩用户进房、断线重连连接管理、消息补偿系统设计题这套对应关系不是我自己硬凑的而是直播行业里后端研发每天都会面对的问题。你如果平时只是写CRUD接口看到这些题可能觉得“偏难”但如果你真在直播或IM类产品实习过就会觉得卷子里每个题都特别“贴业务”。1.2 研发岗需要什么样的能力从这套卷子的体裁看映客春招研发岗的考察模型可以拆成四层第一层是语言基础不管写Java还是Go集合、并发、异常处理这些基本功得过关。第二层是网络与系统知识TCP、HTTP、线程、内存这些在学校里觉得“理论”的知识在这里全部变成实际业务问题的底层依据。第三层是算法与数据结构考察的是代码落地能力很多方案背下来容易但能写出 bug-free 的代码才是关键。第四层是系统设计这是区分“会做题”和“能做事”的分水岭也是这套卷子含金量最高的地方。所以刷这套卷子不能只刷“答案”得把每个考点连接到直播业务上想清楚“为什么会这么考”才算真正吃透。2. 网络基础题直播卡不卡全看这一层网络部分的题目看着基础其实就是直播链路的核心。直播推流用RTMP播放端看直播用HTTP-FLV或HLS互动消息走WebSocket这些全都建立在TCP/IP协议族上。考卷里出现的TCP、UDP、HTTP相关题目本质上是在问你视频数据是怎么从主播手机传到用户手机上的中间哪个环节可能卡顿可能丢包怎么优化。2.1 TCP为什么“又稳又慢”我记得这道题是结合“为什么直播推流只用TCP而不用UDP”来问的。TCP的优势是有序、可靠、拥塞控制代价是连接管理和确认重传机制会带来额外的延迟。视频帧数据量大传输层要拆包、排序如果中间一个包丢了TCP会等待重传后到的数据可能在缓冲区排队这就是所谓的“队头阻塞”。直播是实时性优先的场景一旦网络抖动用户感知到的就是画面卡住、音画不同步。答题的时候不能只说“TCP可靠UDP不可靠”要往业务上引。直播推流采用RTMP它是基于TCP的原因是推流端对延迟要求没那么极端但数据完整性比较重要播放端越来越多人研究WebRTC基于UDP的实时传输因为WebRTC可以在应用层做丢包重传、FEC前向纠错、JitterBuffer抖动缓冲灵活性比TCP高很多。如果能答出“TCP可靠但存在队头阻塞UDP不可靠但可以在应用层配合FEC和NACK实现弱网自适应”这题就稳了。2.2 HTTP/DNS/CDN看一次直播到底发生了什么直播里有一个高频问题用户从点开直播间到看到画面中间做了什么这题喜欢拆成链路来考客户端输入直播间URL先做DNS解析把域名换成边缘节点IP建立TCP连接如果是HTTPS还要TLS握手这一点在直播App上做优化时会用到HTTPDNS避免运营商DNS被劫持或调度到不合适的节点请求经过CDN边缘节点边缘节点如果没有缓存会回源到中心源站播放器拿到直播流地址后开始拉流解码渲染。这里面有几个容易被问到的细节。HTTPDNS不是改造DNS协议而是把域名解析放到HTTP接口上让客户端直接拿到最优节点IP还能绕过Local DNS的缓存污染和调度不准。CDN的缓存策略对直播也特殊直播间状态、用户信息这类接口可以有短时缓存但弹幕、礼物这种实时数据不能缓存否则用户会看到延迟。A卷里有道题问“哪些接口适合加缓存”答案就得按实时性来区分不能一刀切。2.3 选择题里的那些“记忆点”网络部分还有不少选择题当时做题时容易拿不准的点建议反复背301是永久重定向、302是临时重定向、304是命中协商缓存四次挥手里TIME_WAIT出现在主动关闭连接的一方等到2MSL是为了让旧连接的报文在网络中消失避免干扰新连接TCP三次握手里SYN Flood攻击就是让服务器大量处于SYN_RCVD状态消耗半连接队列HTTP/2通过多路复用解决队头阻塞但TCP层丢包仍然存在队头阻塞所以后来才有HTTP/3基于QUIC。这些点单独看都不难但在笔试里经常组合起来考。比如问“用户访问直播间状态码304是什么意思”很多学生直接懵了其实就是在考缓存协商。网络这块的建议是别只背状态码要把每次请求在链路上留下的痕迹串起来理解遇到问题能倒推出哪一层出错。3. 操作系统与并发高并发弹幕背后的线程博弈直播业务里并发是最绕不开的话题。一个热门直播间可能有几十万人在线弹幕、点赞、礼物、进场通知。A卷的操作系统和并发题基本都在问这么多请求同时打进来你的服务端怎么扛住线程池参数、锁、内存模型这些知识点都是为这个核心问题服务的。3.1 线程池参数不能只背公式“线程池核心线程数怎么设置”这道题非常经典。很多答案上来就背公式CPU密集就用CPU核数1IO密集就用CPU核数×2。但这么答只能算及格面试官想看的是你会不会根据具体任务来调。弹幕服务是典型的IO密集型任务线程大量时间花在Socket读写、网络等待上CPU并没有跑满。如果核心线程数设得太小消息处理不过来直播弹幕就会越积越多设得太大线程切换开销反而把CPU拖垮。常见的估算思路是先拿机器的CPU核数通过压测得出单线程每秒能处理多少消息再按目标QPS算出需要的线程数最后留30%~50%的冗余。我一般建议在代码里把核心线程数和最大线程数通过配置项暴露出来上线后根据监控动态调整而不是一次写死。线程池的任务队列选型也有讲究。LinkedBlockingQueue可以无界但一旦消费速度跟不上队列会无限膨胀造成内存溢出ArrayBlockingQueue有界满了之后就会触发拒绝策略。直播弹幕请求的特点是突刺性很强大主播开播瞬间流量瞬间暴涨所以不能选无界队列也不能一满就丢弃消息最好是使用有界队列配合“调用者执行”或“丢弃最老消息”的策略保证系统不被打挂。3.2 锁、CAS与消息有序性直播间里所有用户共享一个消息流如果多个线程同时写某条直播间消息怎么保证顺序这道题考的是锁和CAS机制。Java里synchronized是悲观锁简单可靠但并发竞争激烈时性能差ReentrantLock支持公平锁、非公平锁、可中断CAS是乐观锁适合竞争不激烈的场景。直播弹幕这种写多场景单纯靠锁保护一个全局变量是不行的更合理的方式是分区。比如按直播间ID做哈希同一个直播间的消息永远进入同一个线程/队列处理这样天然串行化不需要在业务代码里加锁又能保证单直播间内的消息有序。这里有个容易踩的坑分布式环境下单机锁解决不了多实例之间的竞争。所以消费端一般会配合Redis分布式锁或消息队列的分区特性来做。笔试里如果问“保证弹幕有序且不重复”不能只答锁而要答分片 单线程消费 消息序号去重这样才能体现你有分布式思路。3.3 JVM与内存分配A卷里还有一类题跟JVM相关频繁创建小对象、老年代增长快怎么办直播场景里弹幕消息如果每一条都new一个对象量一大就会触发频繁Young GC甚至Survivor区放不下直接晋升老年代。答题思路主要集中在几块调整新生代大小给短生命周期对象更充足的空间使用 -XX:UseConcMarkSweepGC 或 G1 这类低停顿垃圾回收器避免在循环里重复创建对象能复用的用对象池尽量用基本类型避免自动装箱产生额外对象。不过别只在JVM参数层面回答最好往代码设计上引。弹幕消息是很典型的事件流可以设计成不可变对象统一复用配合Netty的堆外内存和对象池来降低GC压力。这样回答会让面试官觉得你真调过线上系统而不是只背过调优参数表。4. 算法与数据结构披着业务外衣的经典题A卷的算法题不算变态但每道题都跟直播业务扣得很紧。我记得有TopK问题、LRU缓存还有字符串处理类问题。这部分的难点不在于题目本身而在于你能不能从题面里快速识别出“这是在考某个数据结构”并写出干净、健壮的代码。4.1 TopK问题直播间热度榜怎么做“如何从海量直播间里找出实时热度Top10”这题有几种解法全局排序把所有直播间热度排序取前10复杂度O(n log n)数据量一上来就不适用最小堆维护一个大小为10的小顶堆遍历直播间热度遇到比堆顶大的就替换复杂度O(n log k)k10时接近O(n)快排分割利用partition找到第k大的元素平均O(n)但代码容易写出边界bug分布式场景每个节点先算局部TopK再合并类似于MapReduce思路。面试时最好先确认数据量级。如果说同时在线直播间有百万个直接全排序肯定不现实。我会选择最小堆方案在代码里直接实现PriorityQueue。这个题最有价值的地方是它可以自然延伸到“实时”两个字热度不是固定文件里的数据而是动态增长的流数据这时候是不是要用到窗口计数、布隆过滤器、基数统计之类的技术能主动聊到这层说明你真的想明白了而不是背了一个PriorityQueue的用法。下面是我刷题时写的一个模板public ListInteger topK(int[] data, int k) { if (data null || data.length 0 || k 0) return Collections.emptyList(); PriorityQueueInteger minHeap new PriorityQueue(k); for (int num : data) { if (minHeap.size() k) { minHeap.offer(num); } else if (num minHeap.peek()) { minHeap.poll(); minHeap.offer(num); } } return new ArrayList(minHeap); }这里有个笔试时特别容易忽略的细节堆里存的顺序不等于最终逆序输出。如果题目要求按热度从高到低展示需要再反转一次。另外PriorityQueue底层是数组实现的小顶堆插入和删除的时间复杂度都是O(log k)整体性能没问题。4.2 LRU缓存直播间用户状态怎么存储另一道经典题是LRU缓存题面可能包装成“最近直播间的最活跃用户列表”。核心数据结构是“哈希表双向链表”哈希表负责O(1)查找双向链表负责O(1)移动节点到头部。Java里可以直接用LinkedHashMap构造时把accessOrder设为true即可。class LRUCache extends LinkedHashMapInteger, Integer { private final int capacity; public LRUCache(int capacity) { super(capacity, 0.75f, true); this.capacity capacity; } Override protected boolean removeEldestEntry(Map.EntryInteger, Integer eldest) { return size() capacity; } }这种写法刷题够用但在真实项目里不能直接用默认实现。LinkedHashMap是线程不安全的多线程读写需要加锁加了锁又损失性能。直播场景里可以按直播间分片每个分片一个缓存实例或者直接使用Caffeine/CaffeineCache它基于W-TinyLFU策略在热点数据识别和内存占用上更优秀。笔试时先把基础实现写对面试官追问再展开到工程化方案。4.3 字符串和数组题的边界意识卷子里还经常出现反转字符串、最长公共前缀、合并有序数组这些题难度不大但每年都有人挂在边界条件上。我给你几个刷题时的硬性习惯入参判空永远最先做字符串题目先看字符集是只含小写字母还是ASCII全部字符数组题注意循环结束条件是left right还是left right用辅助数组/哈希表时想清楚下标从0开始还是从1开始写完代码后拿一个最小输入和一个最大输入逼着自己走一遍。这些习惯看着琐碎但笔试环境里没有IDE提示很容易写一个“看起来对但实际上无法编译”的版本。这种题的目标不是炫技是用最稳的方式拿满分。5. 系统设计题现场手写一个直播弹幕系统这套A卷最重头的部分就是系统设计题。我印象里是让你设计一个直播间的弹幕/消息系统支持高并发读写、实时推送。这类题没有标准答案但考官心里有一套完整的评分维度下面我把当时整理的方案完整拆开你可以直接当参考答案用。5.1 先别动手画架构先问需求很多同学拿到设计题上来就画Redis、Kafka、Nginx结果画了一堆组件但都没有根据场景定参数。正确做法是先和面试官确认需求边界。我当时先确认了几个关键信息推拉模式弹幕是单向广播不需要客户端主动拉取历史记录实时性要求端到端延迟目标在200ms以内超过1秒用户就会明显不适规模假设有2万直播间同时在线热门直播间峰值在线10万人峰值弹幕QPS约20万可靠性弹幕系统允许极端情况下丢少量非关键消息但系统通知、礼物这类核心消息不能丢数据保存弹幕需要保存一段时间支持翻查和后台审核。这些问题一问出来方案的核心约束就清楚了高并发读多写多、实时性优先、允许一定程度的最终一致性。5.2 整体架构接入层到推送层我给出的架构是四层结构客户端通过长连接连到接入网关首选WebSocket不用HTTP轮询。接入网关集群根据roomId做路由同一个直播间的WebSocket连接尽量落在同一组机器上。收到弹幕消息后先写入日志和消息队列再经过消息处理服务做内容和频率校验。校验通过的消息发送到推送层推送层根据roomId找到该房间的在线连接列表通过长连接实时推给所有用户。这里有一个关键权衡要不要用Redis Pub/Sub做广播我当时的想法是可以用Redis Pub/Sub做同机房内广播但Redis Pub/Sub的消息没有持久化消费者掉线就丢如果做跨机房Redis Pub/Sub也不适合。所以推送层内部还是用自研的基于TCP的长连接网关每个房间维护一个连接集合通过网关内广播推送。消息队列在这里起的作用是削峰和异步化客户端发弹幕的QPS可能瞬间很高但真正消费处理的速率是可控的消息队列在中间做一个缓冲区保证后端不会被瞬时流量打垮。5.3 数据存储与缓存设计弹幕消息本身要落库但不能直接写MySQL因为写入量太大且读少写多。选型上更合理的是实时在线数据用Redis例如每个房间最新的100条弹幕用LIST结构存超过容量就裁剪冷数据落到消息队列消费后写入ClickHouse或ElasticSearch用于翻查和运营后台房间成员状态用Redis Hash维护value可以是用户基础信息过期时间设置为10分钟避免冷房间占用过多内存礼物、系统通知等需要一定事务性的消息可以走单独的Topic保证不丢不重。写消息的时候还要做小粒度合并比如同一用户短时间内的连续点赞合并成一条批量记录既能减DB压力也不影响用户感知。这个方案要是自己没做过真实项目很容易漏掉“开播瞬间流量尖峰”这个隐患。大主播开播时几十万人同时涌入如果每人都触发一次全量查询Redis连接数和DB连接数瞬间爆炸。解决思路是“进房令牌”房间热门状态下先用本地缓存做一级屏障只对少量关键请求放行到Redis。5.4 稳定性设计与降级方案面试官一定会追问“系统挂了怎么办”所以方案里必须包含高可用设计限流接入网关按roomId做令牌桶限流单房间弹幕发送速率超过阈值时丢弃非核心消息并给客户端返回“发送过快”的提示降级如果消息队列消费积压先保证核心礼物消息的优先级普通弹幕可以降级为只写日志不实时广播隔离热门直播间和普通直播间做资源池隔离避免一个超级大主播的房间把整个集群资源吃光重连补偿客户端断开后重连需要从服务端拉取断线期间的消息这里给每条消息分配自增seq客户端保存最新偏移量重连时按偏移量补拉。高可用方案是区分刚毕业学生和有经验研发的重要分水岭只画一个正常链路是远远不够的。你能主动说出降级、限流、补偿这些点考官基本就会在系统设计这一项给你高分。6. 笔试现场容易踩的坑和备战心得最后这部分想聊聊实际操作层面的东西。刷这套卷子的时候我踩过一些坑也请教过几个不同公司直播业务后端的朋友整理出下面几个容易出问题的地方。6.1 网络和系统题最容易“想当然”选择题里关于TCP和HTTP的陷阱特别多。比如“HTTP请求可以复用同一个TCP连接吗”很多人选“不能”但HTTP/1.1默认支持Keep-Alive一个TCP连接上可以连续发送多个HTTP请求。直播App里的接口请求就大量复用了长连接避免频繁三次握手。答题时一定要看清题目问的是HTTP/1.0还是HTTP/1.1是否带Keep-Alive否则很容易丢分。操作系统里线程池和内存的题也很容易答得不完整。线程池不只要答参数还要答拒绝策略。拒绝策略有AbortPolicy抛出异常、CallerRunsPolicy调用者线程执行、DiscardPolicy丢弃、DiscardOldestPolicy丢弃最老任务每种策略适合什么场景要能说清楚。直播弹幕服务一般不用AbortPolicy因为异常会刷爆日志也不建议DiscardPolicy因为弹幕虽不关键但不能一条都收不到。我一般选CallerRunsPolicy配合有界队列让服务端在过载时把压力反向传导到调用方。6.2 算法题卡壳时怎么自救笔试的时候算法题最容易出现“看一眼有思路写起来就bug遍地”的情况。我的建议是先用中文注释把伪代码写出来再翻译成正式代码。比如LRU先写注释1. 查哈希表不存在返回-12. 存在则把节点移到链表头部3. 插入新节点时如果容量满了先删尾部节点。这样边写边理清逻辑比闷头敲代码稳得多。如果题目没要求最优解先用暴力解法把用例跑通再慢慢优化一定能拿部分分数。千万不要在某一道题上死磕超过20分钟。我自己刷这套卷子时前面选择题花了一半时间导致后面设计题写得仓促重新分配时间后才稳下来。笔试的时间策略应该是选择和简答控制在总时长的1/3算法题每题15到20分钟系统设计留足30分钟。6.3 独家备战清单如果你正准备类似岗位的春招我建议按下面这个清单准备网络TCP握手挥手状态机、HTTP缓存、WebSocket握手流程、TCP与UDP的区别、HTTPS加密流程OS线程与进程、线程池参数、进程间通信、死锁条件、锁优化数据结构数组、链表、栈、队列、哈希表、堆、二叉树遍历、并查集算法二分、双指针、滑动窗口、DFS/BFS、动态规划基础、TopK、LRU、字符串匹配系统设计短链接、弹幕、直播间、秒杀、Feed流至少完整练习3个场景项目准备简历里至少有一个跟高并发、消息、缓存的真实项目没有就去开源项目里找一个深度研究。另一个建议是笔试前一定要去了解目标公司的业务。映客是直播平台你提前准备直播场景的调优案例比如直播间进房流程、弹幕链路优化、礼物系统性能优化这些东西写到简历和面试回答里会比背一堆八股文有说服力得多。写在最后的一些私货经验这套卷子刷完之后我最大的一个感觉是纯粹刷题已经不太够用了。像映客这类业务驱动的公司笔试题不再满足于考察你会不会写快排而是要看你能不能把快排用在“实时榜单”这个场景里不再满足于问你TCP三次握手而是要看你能不能解释直播推流为什么卡顿。所以备战春招的这段时间我建议你每天抽出半小时把学校里学的基础知识和一个具体业务场景强行做映射。比如今天学TCP就想一下直播App里用户发一条弹幕这条消息从手机到服务器再到其他用户手机经历了些什么明天学线程池就想一下弹幕服务到底该怎么配参数。如果只靠考前突击背答案笔试过了面试深挖也会露馅。反过来如果你能把这些知识点全部串到“做一个直播系统”这条主线上你不仅能应付这套A卷任何一家互联网公司的研发笔试你都有底气。我自己现在写代码前也会习惯性画一遍“流量从哪来到哪去”的链路图这个习惯就是刷完这套卷子养成的也算是一个很值回票价的收获。
返回列表