Meta SWE 面经(2024 E4 New Grad)

Meta 2024 年 SWE E4 面试全流程复盘,包含两轮 Coding(算法 + 多线程编程)、一轮 System Design(News Feed)、一轮 Behavior(Leadership & Design Sense)的详细解析。

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 1Coding45min算法 + 数据结构
Round 2Coding45min算法(可能涉及多线程/并发)
Round 3System Design45min设计一个大规模系统
Round 4Behavior45minLeadership + 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()

追问:

  1. 时间/空间复杂度? $O(n)$ 时间,$O(n)$ 空间(递归栈最坏 $O(n)$)
  2. 如果是完全二叉树,能否用数组序列化? 可以,按层序遍历的下标关系 left=2i, right=2i+1,更省空间。
  3. 序列化字符串中,逗号分隔符可以用更短的方式吗? 可以用变长编码(如 Protocol Buffers)替代文本格式。
  4. 如果树的节点值范围很大(如 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()

追问:

  1. 如果是 K 个线程交替打印怎么办?(使用一个共享计数器 + 条件变量,每个线程检查 count % K == my_id)
  2. 性能上哪个最优? Semaphore 通常最快,因为内核级别的信号量实现比 Event 的轮询/阻塞切换更高效。
  3. Python 的 GIL 对这个问题有影响吗? 不影响,因为 GIL 保证字节码级别的原子性,而且 threading 模块的信号量实现是在 C 层面 acquire/release GIL。

Round 3:System Design

题目:设计 Facebook News Feed

这是 Meta 面试的最高频系统设计题。

需求分析

Functional Requirements:

  1. 用户发布 Post(文本、图片、视频)
  2. 用户查看自己的 News Feed(按时间倒序/算法排序)
  3. 点赞、评论、分享
  4. 好友关系(双向关注)

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 ModelPull 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)
);

追问

  1. 如果 Redis 挂了,News Feed 怎么降级?
    • 直接从 MySQL 按时间排序拉取(慢但可用)
    • 本地缓存(Caffeine)兜底最近 1 小时数据
  2. 如何应对热点 key(如某个 post 被频繁查看)?
    • 本地缓存 + 副本 Redis(将热点 key 复制到多个 shard)
  3. Feed 排序只做时间倒序吗?
    • 基础版:时间倒序
    • 进阶版:Edge Rank 算法(考虑亲密度、内容类型、互动率、时间衰减)

Round 4:Behavior(Leadership + Design Sense)

Meta 的行为面试有两个特色:

  1. Leadership Principles(类似 Amazon,但没有 16 条那么多,核心就几条)
  2. 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,你会增加什么功能来提升用户参与度?

我的回答框架:

  1. 问题:观察到什么现象?(很多 Group 活跃度低,成员潜水)
  2. 方案:引入"本周话题"功能和群组挑战(如 7 天打卡)
  3. 验证:A/B 测试,核心指标是 DAU/MAU 和发帖率
  4. 风险:避免过度推送导致的用户疲劳

面试官追问:如果 A/B 测试结果是负面的,你会怎么排查?

  • 答:分层分析(新老用户、不同 Group 类型),检查是否有 Simpson’s Paradox。

面试复盘与建议

维度表现建议
算法⭐⭐⭐⭐⭐Meta 算法难度不算最高,但要求写得快、一次过
多线程⭐⭐⭐⭐准备锁、信号量、条件变量三种并发模型
系统设计⭐⭐⭐⭐⭐News Feed 必会,Push/Pull/Hybrid 要讲清楚
Behavior⭐⭐⭐⭐准备 3-5 个领导力故事 + 产品改进 ideas

Meta 面试的核心竞争力:

  1. 速度:45 分钟很短,要快速理解题目、提出方案、写出代码。不要纠结于"完美"。
  2. 交流:边写边说。 silence 超过 30 秒会让面试官担心。
  3. Hack 精神:Meta 文化鼓励快速原型和迭代,面试中体现"先做出东西再优化"的思维。

推荐阅读:

  • 《Elements of Programming Interviews》(Meta 面试官推荐)
  • Meta 工程博客:engineering.fb.com
  • “How Facebook News Feed Works”(YouTube 上有 Meta 工程师的公开分享)

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页