面试题总结

103 阅读16分钟

1.MySQL

1) MySQL常见的日志有哪些,分别介绍下作用

  • 错误日志(error log) : 对 MySQL 的启动、运行、关闭过程进行了记录。

  • 二进制日志(binary log) : 主要记录的是更改数据库数据的 SQL 语句。

  • 一般查询日志(general query log) : 已建立连接的客户端发送给 MySQL 服务器的所有 SQL 记录,因为 SQL 的量比较大,默认是不开启的,也不建议开启。

  • 慢查询日志(slow query log) : 执行时间超过 long_query_time秒钟的查询,解决 SQL 慢查询问题的时候会用到。

  • 事务日志(redo log 和 undo log) : redo log 是重做日志,undo log 是回滚日志。

  • 中继日志(relay log) : relay log 是复制过程中产生的日志,很多方面都跟 binary log 差不多。不过,relay log 针对的是主从复制中的从库。

  • DDL 日志(metadata log) : DDL 语句执行的元数据操作。

2) Innodb的结构了解么,磁盘页和缓存区是怎么配合,以及查找的,缓冲区和磁盘数据不一致怎么办,mysql突然宕机了会出现数据丢失么

image.png

1、Buffer Pool 缓冲池是主内存中的一个区域,InnoDB在访问表和索引数据时会在其中进行缓存。 缓冲池允许直接从内存中处理经常使用的数据,从而加快了处理速度。 在专用服务器上,通常将多达80%的物理内存分配给缓冲池。 缓存的单位是页,使用LRU算法的变体将很少使用的数据从缓存中老化掉。

InnoDB的缓冲池缓存什么?有什么用? 缓存表数据与索引数据,把磁盘上的数据加载到缓冲池,避免每次访问都进行磁盘IO,起到加速访问的作用。 总结: (1)缓冲池(buffer pool)是一种常见的降低磁盘访问的机制; (2)缓冲池通常以页(page)为单位缓存数据,缓存最热的数据页(data page)与索引页(index page); (3)缓冲池的常见管理算法是LRU。memcache,OS,InnoDB都使用了这种算法; (4)InnoDB对普通LRU进行了优化:

缓冲池使用最近最少使用(LRU)算法的变体对缓冲数据的列表进行管理。 按照5:3的比例将Buffer pool空间划分成年轻代和老年代。 1、年轻代的头部是经常被访问的数据。 2、在老年代的尾部是很少被访问的数据。 什么时候需要一个空间向缓冲池中添加新页面时,删除老年代最近最少使用的页面(最尾部的页),并创建一个新页面添加到列表的中间。

2、Change Buffer 什么是InnoDB的写缓冲? 在MySQL5.5之前,叫插入缓冲(insert buffer),只针对insert做了优化;现在对delete和update也有效,叫做写缓冲(change buffer)。

Change Buffer是缓存那些不在buffer pool里的辅助索引的变化的特殊数据结构 。 在辅助索引发生改变时,如果辅助索引在buffer pool里面就会直接进行修改。如果发生变化的辅助索引页不在buffer pool里,则由Change Buffer先缓存这些辅助索引页的变更动作。等未来辅助索引页被读取时,再将数据再将数据合并(merge)恢复到缓冲池中的技术。写缓冲的目的是降低写操作的磁盘IO,提升数据库性能。

在内存中,Change Buffer是缓冲池的一个组成部分。在磁盘上,Change Buffer是system tablespace(系统表空间)的一部分,当数据库宕机时,索引的变更会被缓冲到磁盘的Change Buffer区域。

总结: 1、写缓冲只有在要修改的辅助索引页不在buffer pool内时,才会将写入操作缓存在change buffer 2、定期对写辅助索引页的changes buffer进行合并,写到到buffer pool 中 3、change buffer既包含内存结构,也包含磁盘结构。内存中的change buffer主要是缓冲辅助索引的变更操作,以便对变更操作进行合并,提高对辅助索引修改效率。 磁盘部分的change buffer主要是数据库宕机时,会将索引的变更缓冲到磁盘的Change Buffer区域。

为什么change buffer只对辅助索引生效? 以insert新增操作为例,插入顺序一般是按照主键递增顺序进行插入的,插入聚集索引(主键索引)一般是顺序的,不需要磁盘的随机读取。这种情况下对聚集索引的修改速度是非常快的,所以不需要进行写缓冲。 而对于辅助索引的插入或者更新操作,由于B+树的索引结构的特性决定了辅助索引插入的离散型。所以,对于辅助索引的插入或者更新操作,InnoDB中不是每一次都直接插入到索引页中,而是先判断插入的辅助索引页是否在缓存区中,若在直接插入;若不在,则先放入到change buffer中,然后再以一定频率和情况进行change buffer和辅助索引页子节点的merge(合并)操作,这时通常能将多个插入合并到一个操作中(因为在一个索引页中),这就大大提高了对于辅助索引插入的性能。

3、自适应hash索引(Adaptive Hash Index) InnoDB存储引擎会监控对表上各索引页的查询,如果观察到建立hash索引可以提高查询速度,则自动建立hash索引。这就是自适应哈希索引(Adaptive Hash Index,AHI) AHI是通过缓存池的B+树页构造而来,因此建立的速度很快,而且不需要对整张表构建hash索引。 InnoDB存储引擎会自动根据访问的频率和模式来自动的为某些热点也建立hash索引。

从这个层面上来说,InnoDB的自使用哈希索引,更像“索引的索引”,毕竟其目的是为了加速索引寻路。

AHI的要求: 1、对页连续访问的模式必须是一样的,即查询条件一样。 2、hash索引只能用来搜索等值的查询

4、Log Buffer 日志缓冲区是用于保存要写入磁盘上的日志文件数据的内存区域。 日志缓冲区大小由innodb_log_buffer_size变量定义, 默认大小为16MB。 日志缓冲区的内容定期刷新到磁盘。 较大的日志缓冲区使大型事务可以运行,而无需在事务提交之前将redo日志数据写入磁盘。 因此,如果您有更新,插入或删除许多行的事务,则增加日志缓冲区的大小可以节省磁盘I / O。 innodb_flush_log_at_trx_commit变量控制如何将日志缓冲区的内容写入并刷新到磁盘。 innodb_flush_log_at_timeout变量控制日志刷新频率。

为什么要有 Log Buffer? 事务提交后,必须将事务对数据页的修改刷(fsync)到磁盘上,才能保证事务的ACID特性。 这个刷盘,是一个随机写,随机写性能较低,如果每次事务提交都刷盘,会极大影响数据库的性能。 日志缓冲区使大型事务可以运行,而无需在事务提交之前将redo日志数据写入磁盘,节省了磁盘I/O.

log buffer刷写的三种策略:

为了满足不用业务对于吞吐量与一致性的需求,MySQL事务提交时刷redo log有三种策略:innodb_flush_log_at_trx_commit (1)0:每秒写入一次日志并将其刷新到磁盘。 尚未刷新日志的事务可能会在崩溃中丢失。 (2)1:要完全符合ACID,必须使用默认设置1。 日志在每次事务提交时写入并刷新到磁盘。 (3)2:日志在每次事务提交后写入,并每秒刷新一次到磁盘。 尚未刷新日志的事务可能会在崩溃中丢失。 这里的写入都只是写入到系统的OS Cache中,如果不刷写到redo log中,数据可能在崩溃中丢失。

高并发业务,行业最佳实践,是使用第三种折衷配置(=2),这是因为: (1)配置为2和配置为0,性能差异并不大,因为将数据从Log Buffer拷贝到OS cache,虽然跨越用户态与内核态,但毕竟只是内存的数据拷贝,速度很快; (2)配置为2和配置为0,安全性差异巨大,操作系统崩溃的概率相比MySQL应用程序崩溃的概率,小很多,设置为2,只要操作系统不奔溃,也绝对不会丢数据。

高并发业务,行业内的最佳实践,是: innodb_flush_log_at_trx_commit=2

如果缓冲区和磁盘数据不一致我们可以进行如下操作:

  1. 手动执行刷新操作: 使用 FLUSH TABLES 命令来刷新所有表,或者使用 FLUSH TABLES table_name 来刷新指定的表。这会将缓冲池中的数据刷新到磁盘上。
  2. 使用 FLUSH 命令: 使用 FLUSH 命令可以刷新不同的缓冲池,例如 FLUSH TABLESFLUSH LOGS 等。你可以根据需要选择不同的 FLUSH 命令。
  3. 等待数据同步: 确保 MySQL 的数据同步机制正常工作,等待系统自动将缓冲区中的数据刷新到磁盘。
  4. 查看错误日志: 检查 MySQL 的错误日志,查找是否有关于缓冲区和磁盘数据不一致的错误信息。错误日志通常位于 MySQL 的数据目录下的 hostname.err 文件中。
  5. 适时重启 MySQL: 在确保没有正在进行的重要事务时,可以考虑重启 MySQL 服务。这将清空缓冲区并重新加载数据,但请确保你了解重启 MySQL 的影响,以及在生产环境中适时选择合适的时间进行操作。

3) mysql事务、acid实现原理,脏读、脏写、隔离级别实现原理,mvcc、幻读、间隙锁原理,什么情况下会使用间隙锁,锁失效怎么办,其他锁了解么,行锁,表锁

4) msyql索引左前匹配原理,怎么优化,哪些字段适合建立索引,索引有什么缺点

MySQL的索引是使用B-tree(B树)数据结构来实现的。对于复合索引(Composite Index),左前缀匹配指的是索引的最左边的一部分。当你在查询中使用索引的时候,如果查询条件只涉及到索引的最左边的列,那么索引就可以被用到。如果查询条件包括索引的最左边的列以及后面的列,那么仍然可以使用索引,但是不会充分利用索引的性能。

如何优化左前匹配:

  1. 合理设计复合索引: 尽量将最常用于查询的列放在最左边。这样可以增加索引的覆盖度,提高查询效率。
  2. 避免不必要的列: 不要在复合索引中包含不必要的列。索引越宽,占用的存储空间越大,维护的成本也越高。
  3. 分析查询条件: 了解查询条件中哪些列经常用于过滤,然后根据这些列设计复合索引。

哪些字段适合建立索引:

  1. 主键和唯一键: 默认会创建主键索引,用于唯一标识表中的每一行。
  2. 经常用于查询和排序的列: 如果某个列经常出现在查询条件中,或者经常用于排序,考虑为该列创建索引。
  3. 连接条件的列: 当表进行连接操作时,连接条件的列可以创建索引以提高连接性能。

索引的缺点:

  1. 占用存储空间: 索引需要额外的存储空间,随着数据量的增加,索引的大小也会增加。
  2. 写操作性能下降: 对表进行插入、更新、删除等写操作时,索引需要维护,可能导致写操作的性能下降。
  3. 选择不当可能导致性能问题: 如果选择了不合适的索引或者创建了过多的索引,可能导致查询性能下降。
  4. 不适用于所有类型的查询: 对于一些特定的查询,索引可能不会被使用,例如模糊查询的%开头的情况。

5) 慢查询怎么定位,如何优化,explain、using filesort表示什么意思,产生原因,如何解决

6) mysql聚簇索引、覆盖索引底层结构,主键索引,没有主键怎么办,会自己生成主键为什么还要自定义主键,自动生成的主键有什么问题

7) mysql中有一个索引(a,b,c),有一条sql,where a = 1 and b > 1 and c =1;可以用到索引么,为什么没用到,B+树的结构,为什么不用红黑树,B树,一千万的数据大概多少次io

8) mysql主从复制,主从延时怎么解决

9)如何建立索引,基于什么原则,索引失效怎么办,如何进行优化

10) 建表会定义自增id吗,为什么,自增id用完了怎么办

11) 分库分表做过么,怎么做到不停机扩容,双写数据丢失怎么办,跨库事务怎么解决

12) mysql多事务执行会产生哪些问题,怎么解决这些问题

13) 线上有遇到大流量的情况么,产生了什么问题,为什么数据库2000qps就撑不住了,有想过原因么,你们当时怎么处理的

14)一张大表怎么更改表的数据结构,字段,用alter会有什么问题,怎么解决呢,有什么好的方案,双写的话会有什么问题,还有其他方案么

Redis

1) redis字典数据结构,hash冲突怎么办,rehash,负载因子

2) redis集群,为什么槽位是16384,哨兵模式,选举过程,会有脑裂问题吗,raft算法,优缺点

3)redis字符串实现,sds和c区别,空间预分配

4)redis有序集合怎么实现的,跳表是什么,往跳表添加一个元素的过程,添加和获取元素,获取分数的时间复杂度,为什么不用红黑树,红黑树有什么特点,左旋右旋操作

5)redis缓存穿透,布隆过滤器,怎么使用,有什么问题,怎么解决这个问题

6)redis分布式锁,过期时间怎么定的,如果一个业务执行时间比较长,锁过期了怎么办,怎么保证释放锁的一个原子性,你们redis是集群的么,讲讲redlock算法

7)redis线程模型,单线程有什么优缺点,为什么单线程能保证高性能,什么情况下会出现阻塞,怎么解决

8)你们用的redis集群么,扩容的过程,各个节点间怎么通信的

9)redis持久化过程,aof持久化会出现阻塞么,一般什么情况下使用rdb,aof

10)你们用redis么,用来做什么,什么场景使用的,遇到过什么问题,怎么解决的

11)redis管道用过么,用来做什么,它的原理是,保证原子性么,和事务的区别,redis事务保证原子性么

12)redis强一致性么,怎么保证强一致性,有什么方案

13)redis分布式锁,过期时间怎么定的,如果一个业务执行时间比较长,锁过期了怎么办,怎么保证释放锁的一个原子性,你们redis是集群的么,讲讲redlock算法

JVM

1)jvm了解哪些参数,用过哪些指令

2)jvm类加载器,自定义类加载器,双亲委派机制,优缺点,tomcat类加载机制

3)cms收集器过程,g1收集器原理,怎么实现可预测停顿的,region的大小,结构

4)内存溢出,内存泄漏遇到过么,什么场景产生的,怎么解决的

5)垃圾收集算法,各有什么优缺点,gc roots有哪些,什么情况下会发生full gc

6)jvm元空间内存结构,永久代有什么问题

7)垃圾收集器,cms垃圾收集过程,为什么停顿时间短,有什么缺点,concurrent mode failure怎么办,内存碎片怎么解决,为什么不用标记整理法

8)jvm内存结构,堆结构,栈结构,a+b操作数栈过程,方法返回地址什么时候回收,程序计数器什么时候为空

9)什么对象会进入老年代,eden和survivor比例可以调整么,参数是什么,调整后会有什么问题

10)对象一定分配在堆上么,JIT,分层编译,逃逸分析

11)new Object[100]对象大小,它的一个对象引用大小,对象头结构

并发

1)线程安全的类有哪些,平时有使用么,用来解决什么问题

2)锁升级过程,轻量锁可以变成偏向锁么,偏向锁可以变成无锁么,自旋锁,对象头结构,锁状态变化过程

3)对于高并发怎么看,怎么算高并发,你们项目有么,如果有会产生什么问题,怎么解决

4)你了解那些锁,乐观锁和悲观锁,为什么读要加锁,乐观锁为什么适合读场景,写场景不行么,会有什么问题,cas原理

5)什么情况下产生死锁,怎么排查,怎么解决

6)了解哪些并发工具类

7)reentrantlock的实现原理,加锁和释放锁的一个过程,aqs,公平和非公平,可重入,可中断怎么实现的

8)threadlocal用过么,什么场景下使用的,原理,hash冲突怎么办,扩容实现,会有线程安全问题么,内存泄漏产生原因,怎么解决

9)线程有哪些状态,等待状态怎么产生,死锁状态的变化过程,中止状态,interrupt()方法

10)你怎么理解线程安全,哪些场景会产生线程安全问题,有什么解决办法

11)while(true)里面一直new thread().start()会有什么问题

12)线程池原理,核心参数,线程数设置,参数动态调整后变化过程,Tomcat线程池原理,常用的线程池,你们一般使用哪种,为什么,会有什么问题,线程抛异常怎么办,阻塞队列原理