美团C++ 二面总结
1. 简单介绍一下你自己和你最有成就感的项目
回答框架:
- 教育背景和技术栈
- 项目背景和业务价值
- 你的核心贡献
- 技术亮点和创新点
- 项目成果(用户量、性能提升等)
2. 如果让你设计一个外卖订单系统,支持千万级日订单,你会怎么设计
答案要点:
需求分析:
- 下单:高并发写入
- 查询:用户查订单、骑手查配送单
- 状态流转:待支付→已支付→配送中→已完成
- 数据量:千万级/天,亿级总量
架构设计:
客户端 → API网关 → 订单服务集群
↓
Redis(缓存) + MySQL(持久化) + MQ(异步)
核心模块:
- 订单创建:生成全局唯一订单号(雪花算法)库存扣减(Redis预减)写入MySQL(分库分表)发送MQ通知下游(支付、配送)
- 数据存储:MySQL分库分表:按用户ID哈希分256库,每库256表Redis缓存:最近7天订单,TTL自动过期ES搜索:支持多条件查询
- 状态机设计:定义状态流转规则防止非法状态跳转状态变更记录日志
- 高可用方案:服务多副本部署数据库主从+读写分离限流降级熔断
关键技术点:
- 分布式事务:本地消息表+定时补偿
- 幂等性:订单号+状态判断
- 超时处理:延迟队列自动取消未支付订单
3. 你们的系统如何做容量规划和性能评估的
答案:
容量规划流程:
- 业务预估:日活用户数(DAU)人均请求次数峰值倍数(平时的3-5倍)计算峰值QPS
- 单机性能测试:压测单台机器的极限QPS观察资源瓶颈(CPU、内存、网络)确定单机承载能力
- 计算所需机器数:机器数 = 峰值QPS / 单机QPS / 0.7(留30%余量)考虑容灾:至少2个机房,每个机房能承载全部流量
- 数据库容量:单表建议不超过2000万行计算需要多少分表预留增长空间
性能评估:
- 定期压测,验证容量
- 监控资源使用率
- 提前扩容(使用率超过70%告警)
实际案例:"我们系统日活100万,人均10次请求,峰值是平时5倍,计算出峰值QPS约5000。单机压测QPS 1000,需要5000/1000/0.7≈8台机器。考虑容灾,部署16台。"
4. 说说你对微服务的理解,微服务拆分的原则是什么
答案:
微服务优势:
- 独立部署:单个服务可独立上线
- 技术栈自由:不同服务可用不同语言
- 故障隔离:一个服务挂了不影响其他
- 团队自治:每个团队负责自己的服务
微服务挑战:
- 分布式事务:跨服务的数据一致性
- 服务治理:服务发现、负载均衡、熔断
- 链路追踪:请求跨多个服务,排查困难
- 运维复杂:服务数量多,部署复杂
拆分原则:
- 按业务领域拆分:用户服务、订单服务、支付服务每个服务对应一个业务领域遵循DDD(领域驱动设计)
- 单一职责:一个服务只做一件事服务边界清晰
- 高内聚低耦合:服务内部高内聚服务之间低耦合通过接口通信
- 数据独立:每个服务有自己的数据库不直接访问其他服务的数据库通过API获取数据
- 团队规模:两个披萨原则(6-8人)一个团队维护1-3个服务
拆分粒度:
- 不要过度拆分:增加复杂度
- 不要拆分不够:失去微服务优势
- 根据业务复杂度和团队规模决定
5. 如何设计一个高性能的RPC框架
答案:
核心组件:
- 序列化:Protobuf:性能好,跨语言JSON:可读性好,性能一般自定义二进制协议:性能最好
- 网络传输:TCP长连接自定义协议:[magic][version][type][requestId][bodyLen][body]支持请求响应匹配(requestId)
- 服务发现:注册中心:Zookeeper、etcd、Nacos客户端缓存服务列表监听变更,动态更新
- 负载均衡:轮询(Round Robin)随机(Random)最小连接数一致性哈希(会话保持)
- 连接管理:连接池:复用连接心跳保活:定期发送心跳断线重连:自动重连
性能优化:
- 零拷贝:sendfile、splice系统调用减少内存拷贝次数
- 批量发送:合并小包,减少系统调用提高网络利用率
- 异步调用:Future/Promise模式不阻塞业务线程
- 线程模型:IO线程:处理网络读写业务线程:处理业务逻辑分离,互不影响
可靠性保证:
- 超时重试:可配置重试次数
- 熔断降级:错误率高时自动熔断
- 限流保护:防止雪崩
参考实现:gRPC、brpc、Thrift
6. 线上服务出现内存泄漏,如何排查和解决
答案:
发现阶段:
- 监控发现内存持续增长
- top命令看RES不断上升
- 服务运行一段时间后OOM
排查工具:
- Valgrind(测试环境):
valgrind --leak-check=full --show-leak-kinds=all ./app
- 优点:详细的泄漏报告和调用栈
- 缺点:性能损耗大(10-50倍)
- AddressSanitizer:
g++ -fsanitize=address -g -o app app.cpp ./app
- 优点:性能损耗小(2倍),能检测多种问题
- 缺点:需要重新编译
- tcmalloc/jemalloc:
LD_PRELOAD=/usr/lib/libtcmalloc.so HEAPPROFILE=/tmp/heap ./app pprof --pdf ./app /tmp/heap.0001.heap > heap.pdf
- 可以在生产环境使用
- 生成heap profile分析
- 查看进程内存:
cat /proc/<PID>/status | grep -i vm cat /proc/<PID>/smaps pmap -x <PID>
定位问题:
- 查看哪个模块内存增长
- 分析调用栈,找到分配点
- 检查是否有delete/free
常见原因:
- new/delete不匹配
- 容器存裸指针,未释放
- shared_ptr循环引用
- 异常导致未释放
- 第三方库泄漏
解决方案:
- 用智能指针管理内存
- RAII原则
- 代码审查
- 定期压测
7. 如何设计一个分布式ID生成器
答案:
需求:
- 全局唯一
- 趋势递增(方便排序、索引)
- 高性能(百万级QPS)
- 高可用
方案对比:
- UUID:优点:简单,本地生成缺点:无序,占用空间大(36字节)
- 数据库自增ID:优点:简单,有序缺点:性能瓶颈,单点故障
- Red
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
C++八股文全集 文章被收录于专栏
本专栏系统梳理C++技术面试核心考点,涵盖语言基础、面向对象、内存管理、STL容器、模板编程及经典算法。从引用指针、虚函数表、智能指针等底层原理,到继承多态、运算符重载等OOP特性从const、static、inline等关键字辨析,到动态规划、KMP算法、并查集等手写实现。每个知识点以面试答题形式呈现,注重原理阐述而非冗长代码,帮助你快速构建完整知识体系,从容应对面试官提问,顺利拿下offer。
