应届生面试规划
2025-09-27 14:40:50 0 举报
AI智能生成
应届生面试规划
作者其他创作
大纲/内容
准备八股(5)
知识领域
C/C++语言
操作系统相关
网络原理
数据库
环境编程、工具、命令等
数据结构
构建技术栈(65)
基础组件
线程池实现与性能分析
一、核心组成
工作线程:复用的执行线程(如std::vector<std::thread>)
任务队列:存储待执行任务(线程安全队列,如std::queue+锁)
同步机制:互斥锁(保护队列)+条件变量(线程唤醒)
控制参数:核心线程数、最大线程数、队列容量、空闲超时时间
二、基础实现流程
初始化:创建核心线程,循环从队列取任务执行
提交任务:任务入队,唤醒空闲线程
关闭:设置停止标志,唤醒所有线程并等待结束
三、性能优化
减少锁竞争:无锁队列、批量取任务、分段锁
动态管理:根据负载扩缩容、任务窃取(负载均衡)
任务适配:优先级队列(高优任务优先)、区分CPU/IO密集型任务
四、性能分析
核心指标:吞吐量(QPS)、响应时间(P95/P99)、资源占用(CPU/内存)、拒绝率
工具:Java(JVisualVM)、C++(perf/自定义统计)
数据库连接池实现
数据库连接池实现
一、核心组成
连接集合:存储空闲/活跃连接(如队列/列表,含数据库连接对象)
配置参数:初始连接数、最大连接数、最小空闲连接数、连接超时时间
同步机制:互斥锁(保护连接操作)+条件变量(等待空闲连接)
连接管理:连接创建(基于驱动初始化)、销毁(释放资源)逻辑
二、基础实现流程
初始化:创建初始数量连接,存入空闲队列
获取连接:
有空闲连接:直接取出并标记为活跃
无空闲且未达最大连接数:创建新连接
否则:等待超时(或抛出异常)
释放连接:将活跃连接放回空闲队列(重置状态,如关闭事务)
关闭池:销毁所有连接,释放资源
三、性能优化
连接心跳:定期检测空闲连接有效性(如执行SELECT 1)
超时回收:清理长期空闲连接(释放资源)
动态扩缩容:根据并发量自动调整连接数(避免资源浪费)
减少锁竞争:拆分空闲队列(按线程绑定子队列)
四、性能分析
核心指标:连接复用率、获取连接耗时、最大并发连接数、超时率
工具:自定义监控(空闲/活跃连接数)、数据库性能工具(如MySQL的show processlist)
原子操作以及多线程队列设计
原子操作及多线程队列设计
一、原子操作
核心概念
不可中断的操作:执行过程中不会被其他线程干扰,直接操作内存,避免数据竞争
底层支持:依赖CPU指令(如x86的lock前缀),无需锁即可保证线程安全
常见操作
基础操作:加载(load)、存储(store)、交换(exchange)、比较交换(CAS,Compare-And-Swap)
复合操作:自增(fetch_add)、自减(fetch_sub)等(如std::atomic<int>::fetch_add(1))
内存序:控制指令重排(如seq_cst强序、acquire/release弱序,平衡性能与安全性)
应用场景
计数器(如请求量统计)、标志位(如线程退出标记)、无锁数据结构基础
二、多线程队列设计
核心需求
线程安全:并发读写队列时保证数据一致性
高效性:减少阻塞,适配高并发场景
实现方式
锁-based队列
结构:普通队列(如std::queue)+互斥锁(std::mutex)+条件变量(唤醒等待线程)
特点:实现简单,低并发场景适用,高并发下锁竞争影响性能
无锁队列(基于原子操作)
核心:用原子指针(std::atomic<Node*>)和CAS操作实现入队/出队
经典实现:Michael-Scott队列(链表结构,头尾指针原子操作)
解决ABA问题:为指针添加版本号(如std::atomic<std::pair<Node*, int>>)
关键挑战
无锁队列的内存管理(避免悬垂指针)、极端场景下的性能抖动(如CAS重试)
缓冲区设计
缓冲区设计
一、核心作用
解耦数据生产/消费速度差异(如网络IO与业务处理)
减少频繁IO操作(批量读写,降低系统开销)
暂存数据,避免数据丢失或阻塞
二、核心设计要素
类型:固定大小(内存可控)、动态大小(适配不定长数据)
大小:根据场景确定(如网络缓冲区常用4KB/8KB,避免内存浪费)
数据结构:数组(随机访问快)、链表(动态扩容灵活)、环形队列(复用空间,无碎片)
同步机制:多线程场景需加锁/原子操作(保证读写安全)
三、常见实现模式
环形缓冲区(环形队列)
特点:首尾相连,用读写指针控制,无内存碎片
适用:生产者-消费者场景(如日志缓存、串口数据传输)
链式缓冲区
特点:节点动态申请,支持不定长数据
适用:网络传输(如TCP分包/粘包处理)
四、性能优化
内存对齐:按CPU缓存行对齐(如64B),减少缓存失效
预分配内存:提前申请缓冲区,避免频繁malloc/free
零拷贝:用mmap/DirectBuffer等,减少数据拷贝次数(如内核态→用户态)
五、典型场景
网络IO:TCP发送/接收缓冲区、HTTP请求体暂存
文件读写:磁盘IO批量缓存(如数据库页缓存)
日志系统:内存日志缓冲区(减少磁盘IO频率)
定时器方案设计与实现
中心主题
三、常见实现方案
基于最小堆(优先队列)
原理:用堆存储任务(按到期时间排序),每次取堆顶(最早到期)任务,计算等待时间后休眠,到期后执行并重新调整堆
特点:实现简单,适合任务量小(<1万)场景;删除任务效率低(O(n),需遍历堆)
时间轮(Time Wheel)
原理:将时间划分为“槽”(如1秒/槽),任务按到期时间放入对应槽;通过指针周期性转动(每槽间隔触发),执行槽内任务
优化:多层时间轮(如秒轮→分轮→时轮),支持长定时(任务从高层轮逐步下沉到低层)
特点:添加/删除任务O(1)(单轮)或O(k)(k为轮层数),适合高并发、大量任务场景(如服务器超时管理)
基于系统接口
利用操作系统定时接口(如Linux的timerfd、Windows的SetTimer),结合IO多路复用(epoll/select)监听定时事件
特点:精度依赖系统,适合与IO事件统一处理的场景(如网络框架)
四、关键细节
精度控制:根据场景选择毫秒/秒级精度(避免过度消耗CPU)
线程安全:多线程操作任务容器时加锁(如std::mutex)或用无锁结构
延迟处理:任务执行耗时可能影响后续触发,建议用线程池异步执行回调
避免空转:无任务时阻塞等待(如condition_variable休眠),减少CPU占用
五、适用场景
堆方案:轻量定时(如客户端本地闹钟)
时间轮:高并发服务(如TCP连接超时检测、心跳包定时发送)
系统接口:与IO密集型业务结合(如HTTP长连接超时管理)
应用层协议设计
中心主题
文本协议
特点:用分隔符(如换行、空格)分隔字段,易读易调试
示例:HTTP(GET /index.html HTTP/1.1\r\n)、Redis协议(*3\r\n$3\r\nSET\r\n)
二进制协议
特点:紧凑无冗余,效率高,可读性差
示例:Protobuf编码协议、自定义二进制格式(字段按固定偏移存储)
中间件
redis
redis 命令详解以及原理
Redis 命令详解及原理
一、核心命令分类与原理(关联底层数据结构)
1. 键(Key)操作命令
常用命令:DEL key(删除键)、EXISTS key(判断键存在)、EXPIRE key seconds(设置过期时间)、TTL key(查看剩余过期时间)
原理:Redis 用全局哈希表(dict)存储键值对,键为字符串(SDS),DEL 直接删除哈希表中键对应的节点;EXPIRE 会将键存入过期字典(单独的dict),记录过期时间,定期删除或惰性删除。
2. 字符串(String)命令
常用命令:SET key value(设值)、GET key(取值)、INCR key(自增)、APPEND key str(追加)
原理:底层用 SDS(简单动态字符串) 存储,兼容C字符串但支持动态扩容、二进制安全。INCR 基于SDS的整数编码(若值为整数),通过原子操作实现自增,避免并发问题。
3. 哈希(Hash)命令
常用命令:HSET key field value(设字段值)、HGET key field(取字段值)、HKEYS key(获取所有字段)、HDEL key field(删除字段)
原理:底层用 哈希表(dict) 或 压缩列表(ziplist,小数据优化) 存储。HSET 会先检查哈希表是否需要扩容(负载因子>1),通过链地址法解决哈希冲突;小数据时用ziplist节省内存(字段-值连续存储)。
4. 列表(List)命令
常用命令:LPUSH key value(左插)、RPOP key(右删)、LRANGE key start end(获取区间元素)
原理:底层用 双向链表(linkedlist) 或 压缩列表(ziplist,小数据) 存储。LPUSH/RPOP 操作链表头尾指针(O(1));LRANGE 需遍历链表(O(n)),ziplist则通过偏移量计算位置。
5. 集合(Set)命令
常用命令:SADD key member(添加元素)、SMEMBERS key(获取所有元素)、SINTER key1 key2(交集)
原理:底层用 哈希表(dict,value为null) 或 整数集合(intset,元素为整数且数量少)。SADD 通过哈希表快速去重(O(1));SINTER 遍历较小集合,检查元素是否在其他集合中。
6. 有序集合(ZSet)命令
常用命令:ZADD key score member(添加带分数元素)、ZRANGE key start end(按分数升序取元素)、ZSCORE key member(获取分数)
原理:底层用 跳表(skiplist)+ 哈希表 存储。跳表按分数排序(支持范围查询,O(logn)),哈希表映射member到score(O(1)查分数)。ZADD 需同时更新跳表和哈希表。
7. 事务与原子命令
常用命令:MULTI(开始事务)、EXEC(执行事务)、WATCH key(监视键,防止并发修改)
原理:Redis 事务为“批量执行+隔离性”,不支持回滚(仅缓冲命令,EXEC 时一次性执行)。WATCH 基于乐观锁,通过检测键的版本号变化决定是否取消事务。
二、核心原理总结
单线程模型:所有命令在单线程中串行执行,避免线程切换开销,依赖IO多路复用(epoll/kqueue)处理并发连接。
数据结构优化:根据数据大小/类型动态选择底层结构(如ziplist、intset),平衡性能与内存占用。
原子性保障:单个命令天然原子(单线程执行),复杂操作可通过事务或Lua脚本实现原子性。
redis 协议与异步驱动实现
Redis 协议与异步驱动实现
一、Redis 协议(RESP,Redis Serialization Protocol)
核心类型与格式(文本协议,换行符\r\n分隔)
简单字符串:+开头,如 +OK\r\n(成功响应)
错误:-开头,如 -Error message\r\n(错误提示)
整数::开头,如 :10086\r\n(INCR 等命令返回值)
批量字符串:$+长度+内容,如 $5\r\nhello\r\n(二进制安全,支持空值 $-1\r\n)
数组:*+元素数+子元素,如 *3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n(命令请求格式)
协议特点
人类可读,易调试(文本格式)
解析简单(按前缀和长度标识,无需复杂语法分析)
二进制安全(批量字符串支持任意字节流,如图片、序列化数据)
二、异步驱动实现(非阻塞IO模式)
核心机制
IO多路复用:基于 epoll(Linux)/kqueue(BSD)监听套接字读写事件,避免阻塞等待
非阻塞IO:套接字设为非阻塞模式(O_NONBLOCK),读写操作立即返回,不阻塞线程
事件循环:主线程循环处理就绪事件(读/写/连接),分发至对应回调
协议解析状态机:分阶段处理分片数据(如先读数组长度,再逐个解析元素)
关键要点
连接池:复用TCP连接,减少握手开销(维护空闲连接队列,按需分配)
Pipeline批量发送:一次性发送多个命令(数组格式),减少往返次数(提升吞吐量)
回调绑定:每个命令注册回调函数,响应返回后触发(异步结果处理)
超时管理:用定时器检测命令响应超时(避免永久等待)
redis 存储原理与数据模型
Redis 存储原理与数据模型
一、核心数据模型
1. 全局键空间(Key Space)
所有键(Key)统一存储在全局哈希表中,键为字符串(SDS 类型),唯一标识一个值(Value)
支持“命名空间”:通过键名前缀划分(如 user:100:name),无物理隔离,仅逻辑区分
2. 值(Value)的数据类型与底层结构
数据类型
String
Hash
List
Set
ZSet
二、存储原理
1. 内存存储核心
全内存数据库:所有数据默认存于内存,读写效率极高(微秒级响应)
数据结构优化:按数据规模动态切换底层结构(如 Hash 元素数<512 用 ziplist,超阈值转 dict)
2. 持久化机制(防内存数据丢失)
RDB:定时快照(如 save 60 1000),将内存数据压缩为二进制文件,恢复快但可能丢数据
AOF:记录所有写命令(如 SET key value),按日志追加,可配置“每秒刷盘”或“每次命令刷盘”,数据更安全但恢复慢
3. 内存管理
过期键删除:
惰性删除:访问时才检查过期,节省CPU
定期删除:每隔一段时间扫描部分过期键,平衡CPU与内存
内存淘汰策略:内存满时,按规则删除非过期键(如 LRU 最近最少使用、LFU 最近最不常用)
MySQL
SQL 基本操作
SQL 基本操作
一、数据查询(SELECT)
基础查询:SELECT 字段1, 字段2 FROM 表名;(查询指定字段)
条件查询:SELECT * FROM 表名 WHERE 条件;(如 WHERE id=1 AND age>18)
排序:SELECT * FROM 表名 ORDER BY 字段 [ASC/DESC];(升序/降序)
二、数据操纵
插入:INSERT INTO 表名(字段1, 字段2) VALUES(值1, 值2);
更新:UPDATE 表名 SET 字段=新值 WHERE 条件;(如 SET age=20 WHERE id=1)
删除:DELETE FROM 表名 WHERE 条件;(无WHERE则删除全表数据)
三、表结构操作
创建表:CREATE TABLE 表名(字段1 类型, 字段2 类型 PRIMARY KEY);(如 id INT PRIMARY KEY)
修改表:ALTER TABLE 表名 ADD 字段 类型;(添加字段)
删除表:DROP TABLE 表名;
索引原理以及 SQL 优化
索引原理及 SQL 优化
一、索引原理
1. 核心作用
加速查询(类似“书的目录”),减少磁盘IO次数,避免全表扫描。
2. 常见类型与结构
B+树索引(主流,如MySQL InnoDB):
结构:平衡树,非叶子节点存索引键,叶子节点有序相连(存数据或主键,支持范围查询)。
聚簇索引:叶子节点存完整行数据(InnoDB中主键默认聚簇索引)。
非聚簇索引:叶子节点存主键,需回表查完整数据(二次查询)。
其他类型:
哈希索引:适合等值查询(如=),不支持范围查询。
联合索引:多字段组合索引,遵循“最左前缀原则”(需按顺序匹配)。
二、SQL 优化
1. 索引优化
避免索引失效:
不对索引列做函数操作(如WHERE SUBSTR(name,1,1)='a')。
避免隐式类型转换(如字符串列用数字查询:WHERE phone=13800138000)。
不使用NOT IN、!=、OR(连接非索引列),避免LIKE '%xxx'(%开头)。
合理设计索引:
频繁查询字段优先建索引,更新频繁字段少建索引。
控制索引数量(过多拖慢插入/更新),联合索引按“字段区分度”排序(高区分度放前)。
2. 查询语句优化
避免SELECT *,只查需要的字段(减少数据传输和内存占用)。
小表驱动大表(JOIN时,用小表做驱动表,减少循环次数)。
用LIMIT限制返回行数,避免一次性返回大量数据。
ORDER BY/GROUP BY优先使用索引字段(避免临时表排序)。
事务原理
三、实现核心机制
日志:
redo log:记录数据变更,保证提交后持久化(崩溃恢复用)。
undo log:记录操作前状态,用于事务回滚(保证原子性)。
锁:行锁(精细控制)、表锁(粗粒度),避免并发修改冲突。
MVCC(多版本并发控制):通过数据版本链实现读不加锁,提升隔离性与并发效率(如InnoDB的可重复读依赖此机制)。
缓存方案设计
三、核心设计策略
缓存更新策略
Cache Aside:读时先查缓存,无则查库并回写缓存;写时先更库,再删缓存(避免脏数据)
Write Through:写时先更缓存,缓存同步更库(一致性高,性能略低)
Write Back:写时只更缓存,异步批量更库(性能高,有数据丢失风险)
缓存粒度:避免过粗(如缓存整个表)或过细(如单字段),平衡命中率与更新成本
过期策略:结合TTL(固定过期时间)+ LRU/LFU(淘汰策略),防止缓存膨胀
性能测试以及调优
测试框架 googletest
性能工具与性能分析
mysqlslap
redis-benchmark
http 性能测试工具 wrk
tcp 性能测试 tcpbenchmarks
磁盘、内存、网络性能分析
细分模块
设计模式(9)
网络编程
网络 io 与 io 多路复用(select/poll/epoll)
网络 IO 与 IO 多路复用(select/poll/epoll)
一、网络 IO 核心流程
网络 IO(如 socket 读写)包含两个阶段:
等待数据就绪:内核接收网络数据并复制到内核缓冲区(阻塞/非阻塞)。
数据拷贝:将内核缓冲区数据复制到用户空间缓冲区。
二、IO 多路复用核心作用
允许单进程/线程同时监控多个文件描述符(socket 等),当某个描述符就绪(可读/可写/异常)时,再进行 IO 操作,避免单线程阻塞在单个 IO 上,提升并发效率。
三、三种多路复用机制对比
机制
select
poll
epoll
核心原理
用位图存储监控的文件描述符,每次调用需将位图从用户态拷贝到内核态,遍历所有描述符检查就绪状态
用动态数组(链表) 存储描述符,无数量限制,同样需遍历检查就绪状态
Linux 特有,用红黑树存储描述符(无需频繁拷贝),就绪事件通过就绪列表主动通知,无需遍历
优点
跨平台(Linux/Windows)
无描述符数量限制
高并发下效率极高(O(1)就绪检查);无数量限制
缺点
最大描述符数限制(默认1024);遍历开销随数量增加而增大
仍需遍历所有描述符,高并发下效率低
仅支持 Linux 平台
适用场景
低并发、简单场景
中等并发,跨平台需求
高并发服务(如 Nginx、Redis)
事件驱动 reactor 的原理与实现
事件驱动 Reactor 原理与实现
一、核心概念
Reactor 是事件驱动架构的核心模式,通过 I/O 多路复用 监控事件(如 socket 可读/可写、连接建立),并将事件分发到对应的处理器,实现异步高效处理。
核心思想:“等待事件→分发事件→处理事件”的循环,避免线程阻塞在单个 I/O 操作上。
二、核心组件
Reactor(反应器):核心调度器,负责注册/注销事件、监听事件就绪、分发事件到对应处理器。
事件多路分发器:基于 select/poll/epoll 实现,监控多个文件描述符(socket)的事件状态(就绪/未就绪)。
事件处理器(Handler):处理特定事件的逻辑(如 AcceptHandler 处理新连接、ReadHandler 处理读事件),包含回调方法(如 handleRead())。
事件(Event):定义事件类型(如 EVENT_READ 读事件、EVENT_WRITE 写事件、EVENT_CONNECT 连接事件)。
三、工作原理(流程)
初始化:
注册事件与处理器(如将监听 socket 的 EVENT_READ 事件绑定到 AcceptHandler)。
事件多路分发器初始化(如创建 epoll 实例)。
事件循环:
Reactor 调用事件多路分发器,阻塞等待事件就绪(如 epoll_wait)。
事件就绪后,多路分发器返回就绪事件列表。
事件分发与处理:
Reactor 遍历就绪事件,找到对应的处理器。
调用处理器的回调方法(如就绪 socket 可读时,调用 ReadHandler::handleRead() 读取数据)。
http 服务器的实现
kvstore 的实现
kv 存储的架构设计
网络同步与事务序列化
内存池的使用与 Lru 的实现
kv 存储的性能测试
高性能异步 io 机制
与 epoll 媲美的 io_uring
io_uring 的使用场景
windows 异步机制 iocp
准备项目(16)
项目整体架构
项目拆解
模块拆解
模块封装
子主题
功能拆解
业务实现
技术方案
设计模式
基础组件
中间件的使用
针对技术提问
技术是什么
技术解决了什么问题
技术是怎么解决的
技术在开源框架和项目中是怎么用的
书写简历(9)
复盘(7)
0 条评论
下一页