第4章 并发编程与Akka Actor

章节核心:Akka 是 Scala 生态中实现 Actor 模型的主流框架,面试重点集中在 Actor 模型理解、消息传递语义、监督策略(容错机制)以及 Future/Promise 异步协调。本章提供 3 个高频面试问答 + 1 个真实项目案例模板,帮你快速搭建结构化回答框架。
Actor 模型面试回答框架 面试问题 ① 谈谈 Actor 模型 ② 监督策略怎么设计? ③ Future 与 Promise 区别 回答框架 1. 定义/本质 2. 核心机制 3. 实际应用/例子 4. 权衡/注意事项 5. 补充(如监督/容错) 加分点 ✓ 对比线程/锁 ✓ 提及“错误隔离” ✓ 消息序列化考虑 ✓ 无共享状态 ✓ 可测试性 常见误答 ✗ 只讲语法 ✗ 忽略监督 ✗ 混淆 Future ✗ 无实践场景 ✗ 忽略性能 监督策略与追问路径图 监督策略 OneForOne AllForOne 自定义指令 容错指令 追问路径:选择原因 → 错误恢复机制 → 实际项目异常种类 → 对监督树深度的影响

📌 面试问答卡片

第一问:请介绍 Actor 模型及 Akka 中的实现。

考察点:并发模型理解、与共享内存差异、消息传递语义、Akka 关键概念(ActorRef、Mailbox)。

回答框架:
① 定义:Actor 是并发原语,封装状态+行为,通过异步消息通信;
② 核心:每个 Actor 有邮箱(Mailbox),串行处理消息,无共享状态;
③ Akka 实现:ActorRef 作为引用,ActorSystem 管理生命周期;
④ 优势:错误隔离、位置透明、易扩展;
⑤ 注意:消息不可变性,避免阻塞。

示例回答:
“Actor 模型通过消息传递实现并行,每个 Actor 拥有独立邮箱与行为。Akka 借助 ActorRef 提供位置透明通信,保证消息顺序处理。相比于共享内存锁,它避免了竞态条件并提升了容错性。例如在聊天系统中,每个用户对应一个 Actor 管理会话。”
可能追问:
① Actor 内如何保证只处理一个消息?
② 如果消息处理抛出异常会怎样?
③ 如何跨 JVM 发送消息?
避坑提醒:不要只说“像对象”,要强调无共享、异步、容错;避免将 Actor 与普通线程混为一谈。

第二问:Akka 的监督策略(Supervision Strategy)有哪些?如何选择?

考察点:容错设计思维、错误恢复机制、OneForOne 与 AllForOne 区别、自定义指令。

回答框架:
① 监督者:父 Actor 监督子 Actor,处理失败;
② 策略类型:OneForOne(仅重启失败子 Actor)、AllForOne(重启所有同级);
③ 指令:Resume(忽略错误继续)、Restart(重新初始化)、Stop(终止)、Escalate(向上报告);
④ 选择依据:错误类型、依赖关系、业务原子性;
⑤ 例子:文件处理中文件缺失可用 Resume,网络超时用 Restart。

示例回答:
“Akka 监督策略有两种:OneForOne 只影响出错的子 Actor,适合独立任务;AllForOne 重启全部子 Actor,适合强依赖阶段。默认指令是 Restart,但根据业务可改为 Resume(如临时读取失败)或 Stop(如认证失败后无需重试)。我曾在支付服务中使用 OneForOne 配合 Restart,避免影响正常订单。”
可能追问:
① 如何自定义监督策略?
② 监督策略与 Actor 生命周期关系?
③ 什么场景用 Escalate?
避坑提醒:不要只列举指令不解释场景;注意区分监督策略与 Actor 重启机制。

第三问:Future 与 Promise 的区别?在 Akka 中如何使用?

考察点:异步编程理解、回调组合、Promise 与 Future 的关系、与 Actor 协作。

回答框架:
① Future 是异步结果的只读占位符,用于消费;Promise 是可写的 Future 生产者;
② 区别:Future 由计算产生,Promise 可手动完成;
③ 在 Akka 中:通过 ask 模式获得 Future,用 pipeTo 回传给 Actor;
④ 组合:map/flatMap/onComplete;
⑤ 注意:Actor 内部避免同步等待 Future,应用 pipeTo。

示例回答:
“Future 代表未来值,Promise 提供成功/失败方法填充 Future。在 Akka 中常用 ask 模式获取 Actor 回复得到 Future,再用 pipeTo 将结果发回另一个 Actor,避免阻塞。例如在用户注册中异步校验邮箱,使用 flatMap 组合两个验证 Future 并统一返回。”
可能追问:
① Future 的线程执行机制?
② 如何处理 Future 超时?
③ 与 Actor 的 tell/ask 选择?
避坑提醒:不要混淆 Future 与 Promise 的角色;避免在 Actor 内长期阻塞 Future 导致邮箱堆积。

📁 真实项目案例模板

项目名称:实时风控分析服务(FPG Engine)

业务背景:监控电商交易,实时识别异常行为(刷单、盗号),触发规则引擎与人工审核。

规模指标:日均事件量 5 亿条;QPS 峰值 80K;50+ 个规则 Actor;集群节点 20 台 32C64G。

技术栈:Scala 2.13, Akka 2.8 (Typed), Kafka, Redis, Prometheus, Kubernetes。

核心难点:
① 事件流中部分消息处理慢导致背压;
② Actor 间复杂依赖需要动态监督策略;
③ 规则变更需热更新而不中断服务。

面试高频追问:
① 你们如何实现动态加载规则而不重启 Actor?→ 通过消息分发规则代码,或使用带版本号的配置 Actor 定时更新。
② 高峰时消息丢失风险?→ 使用 Kafka 持久化+最多一次语义,配合监督策略的 Resume 避免重试风暴。
③ 为什么选择 Akka Typed 而非 Classic?→ 类型安全,编译期避免死信,适合多人协作。

可迁移回答话术:
“我们在实时风控场景下使用 Akka Actor 处理高并发事件。每个规则封装为独立 Actor,监督策略采用 OneForOne + Resume 应对瞬态网络错误,防止重试导致负载上升。对于规则热更新,通过配置 Actor 广播版本号,各 Actor 异步拉取新规则,保证零停机。Future 结合 pipeTo 用于异步查询外部黑名单库,避免阻塞 Actor 邮箱。最终系统在 80K QPS 下 p99 延迟低于 50ms。”

💡 章节小结:回答 Actor 模型时务必突出“无共享+消息驱动+容错”核心;监督策略需结合业务场景举例;Future/Promise 要区分角色,并强调 pipeTo 避免 Actor 阻塞。本模板中的项目话术可直接套用于“高并发异步处理”相关面试题。