腾讯 C++ 后台开发 二面总结
1. 做个简单的自我介绍
您好,我是XXX,XX大学计算机科学与技术专业研究生在读,预计明年6月毕业。本科期间我系统学习了数据结构、算法、操作系统、计算机网络等基础课程,研究生阶段主要研究方向是分布式系统和高性能计算。技术栈方面,我主要使用C++进行后端开发,熟悉多线程编程、网络编程和性能优化,熟练使用MySQL、Redis等中间件,了解分布式系统设计。项目经历上,我在XX公司实习期间参与了分布式存储系统的开发,负责元数据管理模块的设计和实现,这个系统目前已经上线运行,服务于公司内部多个业务部门。我的优势是对底层技术有深入研究,读过Redis、Nginx等开源项目的部分源码,注重代码质量和工程实践。今天很高兴有机会和您交流,希望能加入腾讯。
2. 你的项目是在公司实习做的还是学校课题?用户规模有多大?
这个项目是我在XX科技公司实习期间参与的真实商业项目,已经上线运行了半年多。用户主要是公司内部的各个业务系统,包括推荐系统、广告系统、用户画像系统等大约15个业务方。日活跃请求量在千万级别,峰值QPS能达到5万左右。系统存储的数据规模在PB级别,单集群管理的文件数量超过10亿个。这不是一个demo项目,而是承载了公司核心业务数据的生产系统,对可靠性和性能要求都很高,任何故障都会直接影响业务,所以我们在设计和开发过程中非常注重系统的稳定性和容错能力。
3. 讲讲你项目中的一个技术亮点,重点说说你的分析和设计思路
我重点讲一下元数据管理模块的设计。这个模块的核心挑战是在海量文件场景下,如何快速定位文件元数据并保证高可用。
问题分析:
- 文件数量超过10亿,单机内存无法存储全部元数据
- 查询QPS高达5万,需要毫秒级响应
- 元数据修改频繁,需要保证一致性
- 不能有单点故障,要求99.99%可用性
设计思路:
- 采用分片架构,按文件路径hash将元数据分散到多个节点,每个节点负责一部分数据
- 使用跳表作为内存索引结构,相比红黑树实现更简单,性能相当,支持范围查询
- 引入WAL预写日志保证数据持久化,元数据修改先写日志再写内存,宕机后可以从日志恢复
- 实现主从复制,每个分片有一主两从,主节点故障时从节点自动接管
- 使用Raft协议保证主从数据一致性,写操作需要多数派确认才返回成功
优化细节:
- 批量操作支持,将多个小请求合并成一个大请求,减少网络开销
- 读写分离,读请求可以打到从节点,分散主节点压力
- 热点数据识别,对频繁访问的元数据做本地缓存,命中率达到80%以上
效果:
- 查询延迟P99在10毫秒以内
- 支持单节点5万QPS
- 主节点故障切换时间小于3秒
- 半年来系统可用性达到99.995%
4. 你们的系统做了哪些容灾措施?
我们的容灾设计是多层次的。
数据层容灾:
- 主从复制架构,每个分片一主两从,数据三副本存储
- 跨机房部署,主从节点分布在不同机房,防止单机房故障
- WAL日志持久化到磁盘,支持故障恢复
- 定期全量备份和增量备份,备份数据异地存储
服务层容灾:
- 无状态的接入层,任意节点故障不影响服务
- 负载均衡自动摘除故障节点
- 熔断机制,某个分片故障时自动熔断,不影响其他分片
- 降级策略,极端情况下关闭非核心功能保证核心读写
故障检测和切换:
- 心跳检测机制,每秒检测节点健康状态
- 使用Raft协议自动选主,主节点故障3秒内完成切换
- 脑裂保护,通过多数派机制防止出现双主
演练验证:
- 定期进行故障演练,模拟各种故障场景
- 验证过主节点宕机、从节点宕机、网络分区、机房断电等场景
- 每次演练后总结问题并改进
实际运行中经历过两次主节点故障,都在3秒内完成了自动切换,业务基本无感知。
5. 你们做过压力测试吗?发现了什么问题?
做过多轮压力测试。
测试方法:
- 使用自研的压测工具,模拟真实业务场景
- 逐步增加并发,从1000 QPS到10万QPS
- 持续压测24小时验证稳定性
- 监控CPU、内存、网络、磁盘IO等指标
发现的主要问题:
第一个问题是内存泄漏。压测几个小时后内存持续增长,最终OOM。通过Valgrind定位发现是日志模块的缓冲区没有正确释放,异常情况下跳过了清理逻辑。修复后改用RAII封装,确保异常安全。
第二个问题是锁竞争。QPS超过3万时性能不再线性增长,通过perf分析发现是全局锁竞争严重。优化方案是将全局锁改为分段锁,每个分片独立加锁,锁粒度降低后性能提升了60%。
第三个问题是网络瓶颈。单机网络带宽打满,成为瓶颈。优化方案是启用数据压缩,对传输的元数据进行压缩,带宽使用降低40%,同时优化序列化协议,从JSON改为Protobuf,序列化性能提升3倍。
第四个问题是磁盘IO。WAL日志写入成为瓶颈,每次写入都fsync导致性能差。优化方案是批量刷盘,积累一批日志再统一刷盘,同时使用SSD替换机械硬盘,IO性能提升10倍。
经过这些优化,单节点QPS从3万提升到5万,P99延迟从50毫秒降到10毫秒。
6. 遇到过什么比较难排查的问题吗?不是通过日志能简单发现的那种
遇到过一个很诡异的问题,系统运行一段时间后偶尔出现请求超时,但日志里看不出任何异常,监控显示CPU、内存、网络都正常,重启后问题消失但过几天又出现。
排查过程:
一开始怀疑是网络问题,抓包分析发现网络层面没问题,数据包正常收发。然后怀疑是锁等待,加了锁监控发现也不是。查看系统调用发现某些请求的read系统调用耗时异常长,达到几百毫秒,但磁盘IO监控显示没有慢IO。
后来用strace跟踪进程,发现问题出在DNS解析上。我们的日志系统会异步上报到远程服务器,使用域名访问,系统会做DNS解析。由于DNS解析是阻塞的,当DNS服务器响应慢时,虽然是在异步线程里,但由于线程池满了,新的日志请求会阻塞,进而影响主线程。
解决方案:
- 将域名改为IP地址,避免DNS解析
- 日志上报改为完全异步,使用无锁队列,主线程只负责写队列
- 增加日志线程池大小,并设置超时机制
- 添加DNS解析耗时监控
这个问题的难点在于现象不明显,影响范围小,而且涉及到系统底层的DNS解析机制,超出了应用层的范畴。最终通过系统调用跟踪才定位到根因。
7. 系统有没有发生过崩溃?你是如何通过coredump文件分析的?
发生过一次段错误导致的崩溃。线上服务突然挂掉,自动重启后又挂掉,反复几次。
分析过程:
首先确认开启了coredump,通过ulimit -c unlimited设置。拿到coredump文件后用gdb加载,使用gdb ./program core.xxx命令。
执行bt命令查看调用栈,发现崩溃在一个字符串操作函数里,访问了空指针。但这个函数被很多地方调用,不确定是哪个调用路径触发的。
使用frame命令切换到上层栈帧,查看局部变量的值,发现传入的指针确实是NULL。继续往上追溯,发现是从一个map里查询数据,没有判断返回值就直接使用了。
使用info threads查看所有线程状态,发现有个线程在等锁,怀疑是并发问题。打印相关变量的值,发现map在
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
本专栏系统梳理C++技术面试核心考点,涵盖语言基础、面向对象、内存管理、STL容器、模板编程及经典算法。从引用指针、虚函数表、智能指针等底层原理,到继承多态、运算符重载等OOP特性从const、static、inline等关键字辨析,到动态规划、KMP算法、并查集等手写实现。每个知识点以面试答题形式呈现,注重原理阐述而非冗长代码,帮助你快速构建完整知识体系,从容应对面试官提问,顺利拿下offer。
查看13道真题和解析