梦彻底醒了

梦彻底醒了
这话是上周一个学生跟我说的,他双非一本大三下,刚结束人生第一次面试,他跟我说自己那点底细在面试官面前根本藏不住 —— 简历上编的项目,被追问两句就露了馅;头天晚上临时抱佛脚背的八股文,面试的时候一句也想不起来。
他说大学三年是真玩爽了,课能逃就逃,时间大多耗在宿舍里打游戏。直到面试官盯着他问 “这项目你到底做没做过”,他才反应过来,那些偷过的懒,迟早要变成拦路的坎。
现在他暑期实习是指望不上了,目标很明确:冲秋招。
其实像他这样的学生我见过不少,总觉得时间还多,混到毕业再说。可职场不看你过去有多 “爽”,只看你现在能拿出什么本事。编的项目经不住推敲,临时背的知识点撑不起面试,这些都是实实在在的教训。
醒了就不算晚
秋招还有时间,把那些打游戏的功夫用在补八股、做真项目上,比什么都强。别等机会真来了,又只能眼睁睁看着它溜走。
我把他的故事分享出来,也是想给还在迷茫的同学提个醒:与其在虚拟世界里消磨时光,不如尽早认清现实,脚踏实地提升自己,毕竟为未来努力,什么时候开始都值得。
如果你和他有同样的烦恼,欢迎关注并且私信我,我替你出谋划策。
一起加油
话都说到这了,文章的剩余部分我就分享一些数据库和缓存的常见面试题供大家学习(复习):
MySQL 常见面试题
1. 索引的作用是什么?有哪些类型?
答案:
索引是一种数据结构,用于快速定位表中的数据,减少 I/O 操作。其核心作用包括:
加速查询:通过 B+树或哈希结构快速定位数据。
减少锁竞争:缩小查询范围,降低锁的粒度。
支持覆盖索引:避免回表查询,直接从索引中获取数据。
常见索引类型包括:
B+树索引:适用于范围查询和排序(如
WHERE id > 100
)。哈希索引:适用于等值查询(如
WHERE name='Alice'
),但不支持范围查询。全文索引:用于文本搜索(如
MATCH AGAINST
)。组合索引:多个字段联合索引,遵循最左前缀原则。
注意:索引并非越多越好,需避免过度索引导致写入性能下降。
2. 事务的 ACID 特性是什么?如何实现?
答案:
ACID 是事务的四大特性:
原子性(Atomicity):事务中的操作要么全部成功,要么全部回滚。
一致性(Consistency):事务执行前后,数据状态保持合法。
隔离性(Isolation):多个事务并发执行时,相互不干扰。
持久性(Durability):事务提交后,数据永久保存。
实现机制:
原子性:通过 Undo Log 实现回滚。
持久性:通过 Redo Log 实现故障恢复。
隔离性:通过锁机制和 MVCC(多版本并发控制)实现。
一致性:由原子性、隔离性和持久性共同保证。
MySQL 的事务隔离级别(从低到高):
读未提交(Read Uncommitted):可能出现脏读。
读已提交(Read Committed):避免脏读,但可能出现不可重复读。
可重复读(Repeatable Read):默认级别,避免脏读和不可重复读,但可能出现幻读。
串行化(Serializable):最高级别,通过锁表实现,性能较低。
3. InnoDB 和 MyISAM 的区别?
答案:
总结:InnoDB 是 MySQL 的默认引擎,适合电商、金融等需要事务和高并发的场景;MyISAM 已逐渐被淘汰,仅用于历史项目。
4. 数据库锁的类型有哪些?乐观锁和悲观锁的区别?
答案:
数据库锁按粒度分为:
表锁:锁整个表,并发性能差(如 MyISAM)。
行锁:锁单行数据,并发性能好(如 InnoDB)。
页锁:介于表锁和行锁之间。
按操作类型分为:
共享锁(S 锁):允许读取,不允许修改。
排他锁(X 锁):禁止其他事务加锁。
乐观锁 vs 悲观锁:
悲观锁:假设数据冲突频繁,通过
SELECT ... FOR UPDATE
手动加锁,阻塞其他事务。乐观锁:假设数据冲突较少,通过版本号(
version
字段)或 CAS(Compare-And-Swap)实现无锁操作。
场景:悲观锁适用于冲突频繁的场景(如秒杀),乐观锁适用于冲突较少的场景(如商品库存更新)。
5. 如何优化慢查询?
答案:
优化步骤如下:
定位慢查询:开启慢查询日志(
slow_query_log
),使用pt-query-digest
分析。分析执行计划:通过
EXPLAIN
查看索引使用情况,检查是否存在全表扫描。优化索引:
为频繁查询的字段添加索引。
避免索引失效(如避免在索引列使用函数、
OR
条件)。使用覆盖索引(索引包含所有查询字段)。
优化 SQL 语句:
避免
SELECT *
,只查询必要字段。减少子查询,使用
JOIN
替代。分页优化(如
WHERE id > last_id LIMIT 10
)。硬件与配置:
增加内存,提升缓存命中率。
调整 InnoDB 参数(如
innodb_buffer_pool_size
)。分库分表:数据量过大时,按业务拆分数据库或表。
6. 主从复制的原理是什么?如何解决主从延迟?
答案:
主从复制原理:
主库(Master):将更新操作记录到二进制日志(Binlog)。
从库(Slave):通过 I/O 线程读取主库的 Binlog,写入中继日志(Relay Log)。
从库:通过 SQL 线程回放中继日志,实现数据同步。
主从延迟原因:
主库写入压力大,从库处理速度慢。
网络延迟或硬件性能差异。
解决方法:
优化主库性能:减少锁竞争,优化 SQL 语句。
提升从库硬件:增加 CPU、内存或 SSD。
使用并行复制:MySQL 5.7+支持多线程复制,并行回放事务。
监控延迟:通过
SHOW SLAVE STATUS
查看Seconds_Behind_Master
,设置报警阈值。
7. 分库分表的策略有哪些?如何选择?
答案:
分库分表策略分为:
垂直拆分:
垂直分库:按业务模块拆分数据库(如用户库、订单库)。
垂直分表:将大表拆分为主表和扩展表(如用户基本信息表和用户详情表)。
水平拆分:
哈希分片:通过
hash(id) % N
将数据分散到 N 个库/表。范围分片:按时间或数值范围分片(如按年份拆分订单表)。
一致性哈希:减少节点变动时的数据迁移量。
选择策略:
垂直拆分:适用于业务模块清晰、数据耦合度低的场景。
水平拆分:适用于数据量极大、单库性能不足的场景。
哈希分片:数据分布均匀,但扩容复杂。
范围分片:适合时间序列数据(如日志),但可能导致热点问题。
注意事项:
拆分后需解决分布式事务、跨库 Join 和分布式 ID 生成问题。
常用中间件:Sharding-JDBC、Mycat。
8. 数据库范式是什么?为什么需要范式化?
答案:
数据库范式是设计数据库表结构的规则,目的是减少数据冗余,提高数据一致性。常见范式包括:
第一范式(1NF):字段原子性,不可再分。
第二范式(2NF):消除非主属性对主键的部分依赖。
第三范式(3NF):消除非主属性对主键的传递依赖。
范式化的优点:
减少数据冗余,节省存储空间。
降低数据不一致性风险。
便于维护和更新。
缺点:
增加表连接操作,可能影响查询性能。
反范式化:
在性能敏感的场景(如报表系统),可适当引入冗余字段,减少 Join 操作。
9. 如何处理高并发下的写入问题?
答案:
优化索引:避免全表锁,减少锁竞争。
批量写入:使用
INSERT INTO ... VALUES (...),(...)
替代逐条插入。异步写入:通过消息队列(如 Kafka)缓冲写入请求,削峰填谷。
分库分表:分散写入压力,避免单库瓶颈。
读写分离:主库负责写入,从库负责读取,分担压力。
事务优化:减少事务范围,避免长事务。
使用缓存:对高频写入的数据(如点赞数),先写入缓存,再异步同步到数据库。
批量提交:InnoDB 中设置
innodb_flush_log_at_trx_commit=2
,降低日志刷盘频率(牺牲部分持久化)。
10. 解释一下 MVCC(多版本并发控制)?
答案:
MVCC 是 InnoDB 实现可重复读隔离级别的核心机制,通过版本号和 Undo Log 实现多版本数据共存。其原理如下:
版本号:每行数据有两个隐藏字段
trx_id
(事务 ID)和roll_ptr
(指向 Undo Log 的指针)。读视图(Read View):事务执行时生成一个快照,记录当前活跃事务 ID 的集合。
数据可见性:
当前事务修改的数据对自身可见。
其他事务修改的数据,根据版本号和读视图判断是否可见。
Undo Log:保存旧版本数据,用于回滚和 MVCC 读。
优点:
读写互不阻塞,提升并发性能。
避免幻读(通过间隙锁和 MVCC 结合)。
局限性:
增加内存和磁盘空间占用(需维护多个版本)。
长时间未提交的事务可能导致 Undo Log 膨胀。
Redis 常见面试题
1. Redis 支持哪些数据结构?各自的应用场景?
答案:
Redis 支持以下数据结构:
String:
场景:缓存简单对象(如用户 ID 对应的 Session)、计数器(
INCR
)。List:
场景:消息队列(
LPUSH
+BRPOP
)、最新消息列表。Hash:
场景:存储对象(如用户信息:
hset user:1 name Alice
)。Set:
场景:去重(如用户已读消息 ID)、交集/并集运算(
SINTER
/SUNION
)。ZSet(Sorted Set):
场景:排行榜(如按分数排序的用户排名)、带权重的任务队列。
HyperLogLog:
场景:基数统计(如日活用户数),内存占用低。
Geospatial:
场景:地理位置查询(如附近的 POI)。
示例:
微博热搜榜:使用 ZSet,分数为搜索量。
电商购物车:使用 Hash,键为用户 ID,字段为商品 ID,值为数量。
2. Redis 的持久化机制有哪些?RDB 和 AOF 的区别?
答案:
Redis 支持两种持久化机制:
RDB(Redis Database Snapshot):
原理:定期将内存数据快照保存到磁盘(
dump.rdb
)。触发方式:手动执行
SAVE
/BGSAVE
,或配置自动触发(如save 900 1
:900 秒内至少 1 次写操作)。优缺点:
优点:恢复速度快,文件体积小。
缺点:可能丢失最后一次快照后的所有数据。
AOF(Append Only File):
原理:将写命令追加到日志文件(
appendonly.aof
)。同步策略:
always
:每条命令同步到磁盘(安全,性能低)。everysec
:每秒同步一次(默认,平衡安全与性能)。no
:由操作系统决定(性能高,风险大)。优缺点:
优点:数据丢失少,支持增量恢复。
缺点:文件体积大,恢复速度慢。
选择建议:
同时开启 RDB 和 AOF,RDB 用于快速恢复,AOF 用于减少数据丢失。
对数据安全性要求极高的场景,使用
everysec
策略。
3. 缓存穿透、雪崩、击穿是什么?如何解决?
答案:
缓存穿透:
定义:查询不存在的数据,导致请求直达数据库。
解决方案:
布隆过滤器:提前过滤不存在的 Key。
空值缓存:缓存
NULL
值,设置短过期时间。缓存雪崩:
定义:大量缓存同时失效,请求瞬间压垮数据库。
解决方案:
随机过期时间:为缓存设置随机过期时间(如
TTL = 300 + random(60)
)。热点数据永不过期:通过后台线程定期更新缓存。
限流降级:使用 Hystrix 等工具限制流量,返回默认值。
缓存击穿:
定义:热点 Key 失效瞬间,大量请求直达数据库。
解决方案:
互斥锁:使用
SET ... NX
加锁,确保只有一个线程重建缓存。逻辑过期:在缓存中存储过期时间,业务线程主动更新缓存。
4. Redis 事务的特性?与 MySQL 事务的区别?
答案:
Redis 事务特性:
原子性:事务中的命令要么全部执行,要么全部失败。
一致性:事务执行前后,数据状态保持一致。
隔离性:事务执行期间,不会被其他事务打断(单线程模型保证)。
不支持持久性:事务执行结果仅保存在内存,需依赖持久化机制。
与 MySQL 事务的区别:
注意:Redis 事务中的命令在入队时检查语法错误,执行时不回滚。
5. Redis 集群的实现方式?主从复制和哨兵模式的区别?
答案:
Redis 集群实现方式包括:
主从复制:
原理:一个主节点(Master)负责写,多个从节点(Slave)负责读。
作用:提升读性能和数据冗余。
哨兵模式(Sentinel):
原理:哨兵节点监控主从节点状态,自动进行故障转移(选举新主节点)。
优点:实现高可用性,无需人工干预。
Redis Cluster:
原理:数据分片存储(Sharding),每个节点存储部分数据,支持自动故障转移。
优点:水平扩展,支持海量数据。
主从复制 vs 哨兵模式:
主从复制:仅实现数据复制,需手动处理故障。
哨兵模式:在主从复制基础上,增加自动故障转移功能,提升可用性。
选择建议:
小规模场景:主从复制 + 手动切换。
中规模场景:哨兵模式。
大规模场景:Redis Cluster。
6. 如何优化 Redis 的性能?
答案:
优化 Redis 性能的策略包括:
内存优化:
合理设置
maxmemory
和淘汰策略(如allkeys-lru
)。避免大 Key(
bigkey
),减少内存碎片。使用
MEMORY USAGE
监控内存占用。网络优化:
使用短连接(默认)或长连接(
keepalive
)。调整 TCP 参数(如
tcp-backlog
)。命令优化:
使用 Pipeline 减少网络往返次数。
避免在循环中执行 Redis 命令。
合理使用
MULTI
/EXEC
事务。持久化优化:
优先使用 RDB,减少 AOF 日志量。
定期清理 AOF 日志(
BGREWRITEAOF
)。硬件与配置:
使用 SSD 提升持久化速度。
绑定 CPU 核心,避免线程上下文切换。
监控与调优:
使用
redis-cli info
监控指标(如used_memory
、instantaneous_ops_per_sec
)。分析慢查询日志(
slowlog get
),优化慢命令。
7. 如何处理 Redis 的内存不足问题?
答案:
处理 Redis 内存不足的步骤如下:
分析内存使用情况:
使用
redis-cli --rdb memory
分析 RDB 文件的内存占用。找出大 Key(如
redis-cli --bigkeys
)。优化内存占用:
压缩数据(如使用
snappy
压缩 JSON)。调整数据结构(如用
ZSet
替代List
)。淘汰过期 Key(
active-expire-effort
参数)。调整淘汰策略:
根据业务需求选择
maxmemory-policy
(如volatile-ttl
、allkeys-lru
)。避免频繁淘汰热点数据。
扩容:
增加节点,采用 Redis Cluster 分片。
升级硬件,增加内存。
持久化优化:
降低 AOF 日志同步频率(
appendfsync everysec
)。减少 RDB 快照频率,或改用 AOF。
8. 解释一下 Redis 的管道(Pipeline)和事务的区别?
答案:
示例:
批量查询用户信息:使用 Pipeline 发送多个
GET
命令。原子性扣减库存:使用事务
MULTI
+DECR
+SET
。
9. Redis 的过期策略有哪些?内存淘汰策略有哪些?
答案:
过期策略:
定期删除:每秒随机检查少量 Key,删除过期 Key。
惰性删除:访问 Key 时检查是否过期,过期则删除。
内存淘汰策略(通过maxmemory-policy
配置):
volatile-ttl:优先淘汰剩余 TTL 短的 Key。
allkeys-lru:淘汰最近最少使用的 Key(默认策略)。
allkeys-random:随机淘汰 Key。
volatile-lru:在设置了过期时间的 Key 中淘汰最近最少使用的。
volatile-random:在设置了过期时间的 Key 中随机淘汰。
noeviction:内存不足时拒绝写入,只读。
选择建议:
对时效性要求高的场景:
volatile-ttl
。通用场景:
allkeys-lru
。避免内存溢出:不建议使用
noeviction
。
10. Redis 和 Memcached 的区别?
答案:
总结:Redis 功能更全面,适合复杂业务场景;Memcached 轻量级,适合高并发简单缓存。
欢迎关注 ❤
我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。
没准能让你能刷到自己意向公司的最新面试题呢。
感兴趣的朋友们可以加我微信:wangzhongyang1993,备注:面试群。
版权声明: 本文为 InfoQ 作者【王中阳Go】的原创文章。
原文链接:【http://xie.infoq.cn/article/79475322fb992f48bf3a903ff】。文章转载请联系作者。
评论