OS+MySQL+(其他)八股小记
鲁迅先生曾经说过,每天进步一点点,妈妈夸我小天才。
依旧今日八股,这是我在多个文档整合一起的,可能格式有些问题,请谅解。
操作系统
1.进程和线程的区别?
- 进程是代码在数据集合的一次执行活动,是系统调度资源和分配的基本单位。
- 线程是进程的执行路径,一个进程至少有一个线程,进程中的多个线程共享进程的资源(堆和方法区)。
- 线程中有自己的程序计数器和栈。
2.线程上下文切换要做什么,进程呢?
说到线程我们得先了解一下进程的上下文切换。
进程:上下文切换是一种将CPU资源从一个进程分配给另一个进程的机制。切换过程中,操作系统需要先存储当前进程的状态(包括内存空间的指针、当前执行完的指令等等),再读入下一个就进程的状态,然后执行此进程。
线程:
- 当两个线程不属于同一个进程,切换过程与进程上下文切换一样。
- 如果线程属于同一个进程,因为虚拟内存是共享的,所以切换时,虚拟内存这些资源保持不动,只需要切换线程的私有数据、寄存器等不共享的数据。
3.死锁的四个条件?如何避免?
- 互斥条件
对某资源同时只允许一个线程占用,如果还有其他线程请求获取该资源,则请求者只能等待、直至占有资源的线程释放该资源。
- 请求并持有
一个线程已经占有了某资源,但又提出了新的资源请求,而新的资源已被其他线程占有,所以当前线程会阻塞,但不会释放自己已持有的资源。
- 不可剥夺条件
指线程占有的资源在使用前不会被其他线程抢占,只能在自己使用完毕后由自己释放资源。
- 环路等待条件
发生死锁时必然存在一个 资源–线程的环形链。
其他细节
- AOP 日志:
- 为什么用 AOP 而不是过滤器/拦截器?
Spring AOP 底层其实就是基于代理和拦截器机制实现的。
但是从开发者视角来看:
- Filter(过滤器) → Servlet 层面,适合处理请求/响应,比如跨域、编码、权限。
- Interceptor(拦截器) → Spring MVC 层面,适合处理 Controller 前后的逻辑,比如登录校验、参数预处理。
- AOP(切面) → 主要用在业务方法层(Service/DAO),可以做到更细粒度的横切逻辑,比如公共字段填充、统一日志、事务、埋点。
所以我用 AOP,不是因为它和拦截器完全不同,而是:
- 它提供了更细粒度的切入点(不仅限于 Controller,还能作用在 Service、DAO)。
- 和注解结合更自然,可以精确控制哪些方法要切入,而不是所有请求都走一遍。
- 非侵入性更好,业务代码不用关心。
- OSS 文件上传:
- 分片上传和断点续传的原理?
分片上传和断点续传的核心逻辑其实在前端。前端把文件切成固定大小的分片,并发调用 OSS 的分片上传 API。断点续传时,前端会保存 uploadId
和已上传分片的状态(本地或数据库),下次上传时只补传未完成分片。
服务端这边比较轻量,主要就是对接 OSS API,做上传凭证签名和回调处理。
后:
-
后端主要做 安全控制:前端要上传前,先请求后端获取 OSS 签名凭证
-
负责接收 OSS 的 回调通知(上传完成/失败),更新数据库中文件的状态。
-
如果有大文件秒传需求,还可以在后端做 文件唯一性校验(MD5 校验),避免重复上传。
- 断点续传是怎么记录上传进度的?
-
Nginx + Tomcat:
- Nginx 常见负载均衡策略?
-
轮询(默认):请求均匀分配。
-
加权轮询:根据服务器性能分配权重。
-
IP Hash:同一客户端 IP 访问固定节点。
-
最少连接数:请求分配给当前连接数最少的节点。
-
一致性哈希(第三方模块):保证同一用户尽量落到相同节点。
- 项目中 session 怎么解决共享问题?
有一个地方涉及到了session共享问题,就是在登录获取验证码的时候,将验证码存到哪里的问题,起初是用HttpSession保存验证码。但是因为多台Tomcat不共享数据,而复制数据给其他Tomcat比较浪费空间,所以考虑使用Redis。
MySQL
Q9: 为什么索引用 B+ 树而不是 B 树?
A9:
- 二叉树/红黑树的储存数据的层数太深,磁盘IO多。
- B+ 树非叶子节点只存索引,只在叶子节点存储数据,叶子节点之间由链表相连,范围查询效率高
- 磁盘页一般16KB,一个B+树节点能储存很多key,树高一般3、4层就能覆盖百万级别的数据
Q10: 覆盖索引和回表的区别?
A10:
假设user表,id为主键,name不加修饰,创建这两个字段的索引
- 覆盖索引:查询的数据都能在辅助索引里拿到,不用回表。
比如select name from user where name = 'xxx'
,这样本身数据就能从辅助索引里找到,不需要回表。
- 回表:
select * from user where id = 1
这样是不需要回表的,聚簇索引(也就是主键索引)他是通过B+树储存数据,在叶子节点储存所有数据记录和主键索引,所以会直接查询到id=1的全部数据。但是,如果执行select * from user where name = 'xxx'
,因为name属于辅助索引,辅助索引储存name索引和主键,需要先根据name索引查询到对应的主键,然后根据主键去主键索引里找对应数据,所以多扫描了一个索引树,这个过程叫做回表操作。
Q10:什么是最左匹配原则/最左前缀原则?
A10:
- 当我们为多个列创建 联合索引(Composite Index)时,索引的查询利用遵循 从最左边的列开始匹配。
- 只要中间某个字段没有使用,就无法继续利用后续字段的索引。
- 假如有一个联合索引
CREATE INDEX idx_user_name_age ON user(name, age, gender);
相当于创建了三个索引组合
(name)
(name, age)
(name, age, gender)
B+树按照最左有序排列,从左到右建立索引树,也就是name部分是有序的,查询数据时会优先比较name来确定下一步搜索的方向,但是如果隔过name的话,那就无从下手了,就不知道下一步该查哪个节点了,就用不上索引了。
Q11: MySQL 事务四大特性 & 隔离级别?
A11:
ACID:原子性、一致性、隔离性、持久性。
- 原子性:事务作为一个整体被执行,其中包括的对数据库的操作要么全部成功,要么全部失败。
- 一致性:事务执行前,与事务执行后数据不会被破坏。比如a转账b账户10块钱,执行完后,帐户的金额总和是不变的。
- 隔离性:多个事务并发访问时,事务之间是隔离的,一个事务不会影响另一个事务的执行。
- 持久性:事务执行对数据库的操作,将持久的保存在数据库中。
隔离级别:读未提交、读已提交、可重复读(默认)、串行化。
- 脏读:事务A、B交替执行,事务A读到了事务B未提交的数据
- 幻读:事务A查询一个范围的结果集,事务B在这之间插入或者删除了数据,并静悄悄的提交,导致事务A再次查询相同的范围与发现数据行数多了或者少了。
- 不可重复读:在一个事务范围,两个相同的查询,读取同一条记录,返回了不同的数据。
Q12: MVCC 是怎么实现的?
A12:
多版本并发控制。通过维护数据历史版本,从而解决并发访问情况下的读一致性问题。
关键点:隐式字段、undo 日志、版本链、快照读&当前读、Read View。
MVCC 的核心是 版本链 + ReadView 可见性判断。
InnoDB 在每行数据后面维护 trx_id
和 roll_pointer
,更新时不覆盖旧数据,而是把旧值写入 Undo Log,形成一个版本链。事务在读的时候会生成 ReadView,通过事务 ID 和活跃事务列表来判断哪个版本对自己可见。这样不同事务就能同时读取到各自一致的数据版本,从而避免了脏读和不可重复读。
Q13: SQL 查询很慢,你怎么排查?
A13:
慢查询日志和服务监控
- **慢查询日志: **开启 MySQL 的慢查询日志,再通过一些工具比如 mysqldumpslow 去分析对应的慢查询日志,当然现在一般的云厂商都提供了可视化的平台。
- 服务监控: 可以在业务的基建中加入对慢SQL的监控,常见的方案有字节码插桩、连接池扩展ORM 框架过程,对服务运行中的慢SQL进行监控和告警。
Q14:有哪些方式优化?
A14:
SQL语句的优化,数据库设计的优化
一般我们会从几个方面考虑:
- SQL 本身:检查是否有不必要的字段、函数操作,是否可以改写成更优的形式;
- 索引:查看是否建了合适的索引,能否使用覆盖索引;
- 执行计划:用
EXPLAIN
看看是否走了全表扫描,rows 预估量大不大; - 表结构:字段类型是否合理,表是否过大,是否需要拆分;
- 系统层面:比如加缓存、读写分离、分库分表等。