字节 今日头条-C++ 一面
1. 请介绍一下你做的“分布式通知中台”项目,整体架构和主流程是怎样的?
- API 网关接收请求并鉴权;
- 通知编排服务做模板渲染、路由决策;
- 通过 MQ 异步投递到各通道子服务;
- 子服务调用第三方渠道并回写投递状态;
- 查询服务聚合状态给前端。
这样做的好处是:高并发下削峰、渠道隔离、失败可重试、可观测性清晰。
2. RESTful HTTP 怎么请求?请求方法和路径如何设计?
核心是“资源化建模 + 语义化方法”:
- POST /api/v1/notifications 创建通知任务
- GET /api/v1/notifications/{id} 查询详情
- GET /api/v1/notifications?userId=xx 列表查询
- DELETE /api/v1/notifications/{id} 取消未发送任务
代码:
POST /api/v1/notifications
Content-Type: application/json
{
"bizId": "order_123",
"channel": "email",
"templateId": "pay_success",
"receiver": "**********",
"params": {"name":"Tom","amount":"99.00"}
}
3. GTest 怎么做测试?如何做数据库相关测试?
分三层:
- 单元测试:mock 外部依赖(MQ、第三方通道);
- 集成测试:连测试库(Docker MySQL),跑迁移脚本后测试;
- 回归测试:覆盖重试、幂等、超时场景。
数据库测试重点:每个用例前后清理数据,保证可重复执行。
代码:
#include <gtest/gtest.h>
TEST(TemplateRenderTest, Basic) {
std::string tpl = "Hi, {{name}}";
std::string out = Render(tpl, {{"name", "Alice"}});
ASSERT_EQ(out, "Hi, Alice");
}
4. MQ 中存储的是什么?如果消息太多放不下怎么办?
MQ 中一般存的是业务事件(如“通知待发送”“投递状态变更”),而不是大文件本体。 队列压力过大时可用:
- 分区扩容 + 多消费者组;
- 延迟队列与重试队列分离;
- 过载时降级(低优先级消息限流/丢弃);
- 大消息改“对象存储 URL + 元数据”;
- 设置消息 TTL + 死信队列。
5. 通知系统里核心数据库表有哪些?关系如何设计?
典型表设计:
- notification_task:任务主表(biz_id, template_id, status)
- notification_recipient:接收人明细(task_id, receiver, channel)
- notification_delivery_log:投递日志(recipient_id, attempt, provider_resp)
- notification_template:模板配置(变量、版本、启停状态)
关系:task 1:N recipient 1:N delivery_log,模板与任务是 1:N。
6. “提交通知成功但数据库没写进去”怎么办?
这是典型一致性问题。做法:
- API 返回成功前,必须先落库(本地事务);
- 发 MQ 用 Outb
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
C++ 常考面试题总结 文章被收录于专栏
本专栏系统梳理C++方向, 大中厂高频高频面试考点 , 内容皆来自真实面试经历,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力.

