Meta SWE 面经(2024 E4 New Grad)
岗位:Software Engineer, E4(Menlo Park)
背景:CMU 硕士 CS,两段 Meta 实习(已拿 return)
结果: E4 offer(return 直接进 E4,New Grad 通常是 E3)
时间线:8.20 启动 return process → 8.30 一面 coding → 9.5 二面 coding → 9.12 三面 system design → 9.18 四面 behavior → 9.25 offer
Meta 面试流程
Meta 的 SWE 面试通常是 4 轮 onsite(或 virtual onsite):
| 轮次 | 类型 | 时长 | 重点 |
|---|---|---|---|
| Round 1 | Coding | 45min | 算法 + 数据结构 |
| Round 2 | Coding | 45min | 算法(可能涉及多线程/并发) |
| Round 3 | System Design | 45min | 设计一个大规模系统 |
| Round 4 | Behavior | 45min | Leadership + Design Sense |
Meta 的面试以 快速、高效、结果导向 著称,面试官很少闲聊,上来就是题目。
Round 1:算法(经典题变形)
面试官是一位 L5 工程师,非常直接:“Let’s start with a coding question.”
题目:二叉树的序列化与反序列化
LeetCode 297. 二叉树的序列化与反序列化
要求:设计一个算法来序列化和反序列化二叉树,不限制序列化格式。但要支持所有二叉树的结构。
# Definition for a binary tree node.
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Codec:
def serialize(self, root):
"""Encodes a tree to a single string."""
def dfs(node):
if not node:
res.append('#')
return
res.append(str(node.val))
dfs(node.left)
dfs(node.right)
res = []
dfs(root)
return ','.join(res)
def deserialize(self, data):
"""Decodes your encoded data to tree."""
def dfs():
val = next(vals)
if val == '#':
return None
node = TreeNode(int(val))
node.left = dfs()
node.right = dfs()
return node
vals = iter(data.split(','))
return dfs()
追问:
- 时间/空间复杂度? $O(n)$ 时间,$O(n)$ 空间(递归栈最坏 $O(n)$)
- 如果是完全二叉树,能否用数组序列化? 可以,按层序遍历的下标关系
left=2i, right=2i+1,更省空间。 - 序列化字符串中,逗号分隔符可以用更短的方式吗? 可以用变长编码(如 Protocol Buffers)替代文本格式。
- 如果树的节点值范围很大(如 64 位整数),你的序列化会怎么处理? 使用定长二进制编码,而不是字符串。
这个追问链的要点是:Meta 喜欢看到候选人对工程细节的敏感度。
Round 2:算法(多线程)
Meta 的第二轮 coding 有时会涉及并发编程,特别是在后端/基础设施相关的岗位。
题目:按序打印 FooBar
LeetCode 1115. 交替打印 FooBar
要求:实现 FooBar 类,让两个线程交替打印 “foo” 和 “bar” 共 n 次。
我提供了三种解法,并比较了它们的适用场景:
解法 1:Lock + Condition Variable(Python 版)
import threading
class FooBar:
def __init__(self, n):
self.n = n
self.foo_lock = threading.Lock()
self.bar_lock = threading.Lock()
self.bar_lock.acquire() # bar 先阻塞
def foo(self, printFoo: 'Callable[[], None]') -> None:
for i in range(self.n):
self.foo_lock.acquire()
printFoo()
self.bar_lock.release()
def bar(self, printBar: 'Callable[[], None]') -> None:
for i in range(self.n):
self.bar_lock.acquire()
printBar()
self.foo_lock.release()
解法 2:Semaphore(更简洁)
from threading import Semaphore
class FooBar:
def __init__(self, n):
self.n = n
self.foo_sem = Semaphore(1) # foo 初始可用
self.bar_sem = Semaphore(0) # bar 初始阻塞
def foo(self, printFoo):
for _ in range(self.n):
self.foo_sem.acquire()
printFoo()
self.bar_sem.release()
def bar(self, printBar):
for _ in range(self.n):
self.bar_sem.acquire()
printBar()
self.foo_sem.release()
解法 3:Event(最简单)
from threading import Event
class FooBar:
def __init__(self, n):
self.n = n
self.foo_event = Event()
self.bar_event = Event()
self.foo_event.set() # foo 先执行
def foo(self, printFoo):
for _ in range(self.n):
self.foo_event.wait()
self.foo_event.clear()
printFoo()
self.bar_event.set()
def bar(self, printBar):
for _ in range(self.n):
self.bar_event.wait()
self.bar_event.clear()
printBar()
self.foo_event.set()
追问:
- 如果是 K 个线程交替打印怎么办?(使用一个共享计数器 + 条件变量,每个线程检查
count % K == my_id) - 性能上哪个最优? Semaphore 通常最快,因为内核级别的信号量实现比 Event 的轮询/阻塞切换更高效。
- Python 的 GIL 对这个问题有影响吗? 不影响,因为 GIL 保证字节码级别的原子性,而且
threading模块的信号量实现是在 C 层面 acquire/release GIL。
Round 3:System Design
题目:设计 Facebook News Feed
这是 Meta 面试的最高频系统设计题。
需求分析
Functional Requirements:
- 用户发布 Post(文本、图片、视频)
- 用户查看自己的 News Feed(按时间倒序/算法排序)
- 点赞、评论、分享
- 好友关系(双向关注)
Non-Functional Requirements:
- DAU 20 亿,平均每人每天 5 次刷新
- 每次刷新显示 20-50 条 Feed
- P99 延迟 < 500ms
- 可用性 99.99%
核心架构
┌─────────────────┐
│ Load Balancer │
└────────┬────────┘
│
┌────────────────┼────────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ Feed │ │ Post │ │ Social │
│ Service │ │ Service │ │ Graph │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ News Feed│ │ Post │ │ User │
│ Cache │ │ DB │ │ DB │
│ (Redis) │ │(MySQL) │ │(MySQL)│
└─────────┘ └────────┘ └────────┘
核心问题:Push vs Pull
News Feed 的核心设计决策是 Push(写扩散)vs Pull(读扩散)。
| 维度 | Push Model | Pull Model |
|---|---|---|
| 实现 | 发贴时写入所有粉丝的时间线 | 读取时实时聚合关注对象的发贴 |
| 优点 | 读极快(直接查缓存) | 写极快(无扩散成本) |
| 缺点 | 大 V 写入量爆炸 | 读延迟高,需要多源聚合 |
| 适用 | 普通用户 | 大 V/ celebrity |
Meta 实际采用 Hybrid(混合)模式:
- 普通用户:Push,预计算 News Feed 存入 Redis
- 大 V:Pull,读取时实时从 Post DB 拉取
- 阈值:粉丝数 > 100 万自动切换为 Pull
存储设计
News Feed 缓存:Redis Sorted Set
key: feed:user:<user_id>
score: timestamp
member: post_id
# 每次分页取前 50 条
ZREVRANGE feed:user:123 0 49
Post 数据:MySQL + S3(多媒体文件)
create table posts (
id bigint primary key auto_increment,
author_id bigint not null,
content text,
media_urls json,
created_at timestamp default now(),
index idx_author_created (author_id, created_at)
);
Social Graph:图数据库(Neo4j / JanusGraph)或 MySQL 关系表
create table friendships (
user_id bigint,
friend_id bigint,
status enum('pending', 'accepted'),
created_at timestamp,
primary key (user_id, friend_id)
);
追问
- 如果 Redis 挂了,News Feed 怎么降级?
- 直接从 MySQL 按时间排序拉取(慢但可用)
- 本地缓存(Caffeine)兜底最近 1 小时数据
- 如何应对热点 key(如某个 post 被频繁查看)?
- 本地缓存 + 副本 Redis(将热点 key 复制到多个 shard)
- Feed 排序只做时间倒序吗?
- 基础版:时间倒序
- 进阶版:Edge Rank 算法(考虑亲密度、内容类型、互动率、时间衰减)
Round 4:Behavior(Leadership + Design Sense)
Meta 的行为面试有两个特色:
- Leadership Principles(类似 Amazon,但没有 16 条那么多,核心就几条)
- Design Sense(产品敏感度,会问"如果让你改进 Facebook 的某个功能")
Leadership 问题
问题 1:Tell me about a time you significantly improved a team’s productivity.
我分享了实习期间搭建 CI/CD pipeline 的经历,将部署时间从 30 分钟缩短到 5 分钟,并引入自动化测试将回归 bug 减少 60%。
追问:如果有人反对你的方案呢?
问题 2:Describe a time you had to make a decision with incomplete information.
我讲了在实习中需要在两种技术方案(GraphQL vs REST)间快速做选择,由于时间紧迫,我通过原型测试和团队投票在 2 天内做出了决策。
Design Sense 问题
问题:如果你负责 Facebook Groups,你会增加什么功能来提升用户参与度?
我的回答框架:
- 问题:观察到什么现象?(很多 Group 活跃度低,成员潜水)
- 方案:引入"本周话题"功能和群组挑战(如 7 天打卡)
- 验证:A/B 测试,核心指标是 DAU/MAU 和发帖率
- 风险:避免过度推送导致的用户疲劳
面试官追问:如果 A/B 测试结果是负面的,你会怎么排查?
- 答:分层分析(新老用户、不同 Group 类型),检查是否有 Simpson’s Paradox。
面试复盘与建议
| 维度 | 表现 | 建议 |
|---|---|---|
| 算法 | ⭐⭐⭐⭐⭐ | Meta 算法难度不算最高,但要求写得快、一次过 |
| 多线程 | ⭐⭐⭐⭐ | 准备锁、信号量、条件变量三种并发模型 |
| 系统设计 | ⭐⭐⭐⭐⭐ | News Feed 必会,Push/Pull/Hybrid 要讲清楚 |
| Behavior | ⭐⭐⭐⭐ | 准备 3-5 个领导力故事 + 产品改进 ideas |
Meta 面试的核心竞争力:
- 速度:45 分钟很短,要快速理解题目、提出方案、写出代码。不要纠结于"完美"。
- 交流:边写边说。 silence 超过 30 秒会让面试官担心。
- Hack 精神:Meta 文化鼓励快速原型和迭代,面试中体现"先做出东西再优化"的思维。
推荐阅读:
- 《Elements of Programming Interviews》(Meta 面试官推荐)
- Meta 工程博客:engineering.fb.com
- “How Facebook News Feed Works”(YouTube 上有 Meta 工程师的公开分享)
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。