Redis
缓存穿透
查询一个不存在的数据,mysql查询不到数据也不会直接写入缓存,就会导致每次请求都查数据库
解决
方案一:null结果缓存(缓存空数据),并加入短暂过期时间
方案二:布隆过滤器(hash算法,bitmap)
面试回答
缓存击穿
给某一个key设置了过期时间,当key过期的时候,恰好这时间点对这个key有大量的并发请求过来,这些并发的请求可能会瞬间把DB压垮
解决方案一:互斥锁,强一致,性能差
解决方案二:逻辑过期,高可用,性能优,不能保证数据绝对一致
面试回答
缓存雪崩
缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务容机,导致大量请求到达数据库,带来巨大压力。
方案一:给不同的Key的TTL添加随机值
方案二:利用Redis集群提高服务的可用性
方案三:给缓存业务添加降级限流策略降级(可做为系统的保底策略,适用于穿透、击穿、雪崩)
方案四:给业务添加多级缓存
面试回答:
缓存三兄弟
双写一致性
问题:redis做为缓存,mysql的数据如何与redis进行同步呢?(双写一致性)
- 延迟一致性:介绍自己简历上的业务,我们当时是把文章的热点数据存入到了缓存中,虽然是热点数据,但是实时要求性并没有那么高,所以,我们当时采用的是异步的方案同步的数据
- 强一致性:我们当时是把抢券的库存存入到了缓存中,这个需要实时的进行数据同步,为了保证数据的强一致,我们当时采用的是redisson提供的读写锁来保证数据的同步
问题:那你来介绍一下异步的方案(你来介绍-下redisson读写锁的这种方案)
- 允许延时一致的业务,采用异步通知
- 使用MQ中间中间件,更新数据之后,通知缓存删除
- 利用canal中间件,不需要修改业务代码,伪装为mysql的一个从节点,canal通过读取binlog数据更新缓存
- 强一致性的,采用Redisson提供的读写锁
- 共享锁:读锁readLock,加锁之后,其他线程可以共享读操作
- 排他锁:独占锁writeLock也叫,加锁之后,阻塞其他线程读写操作
面试回答:
强一致性
最终一致性
Redis持久化
面试回答:
数据过期策略
惰性删除:访问key的时候判断是否过期,如果过期,则删除
定期删除:定期检查一定量的key是否过期(SLOW模式+FAST模式)
Redis的过期删除策略:惰性删除 +定期删除两种策略进行配合使用
面试回答:
数据淘汰策略
- Redis提供了8种不同的数据淘汰策略,默认是noeviction不删除任何数据,内存不足直接报错
- LRU:最少最近使用。用当前时间减去最后一次访问时间,这个值越大则淘汰优先级越高。
- LFU:最少频率使用。会统计每个key的访问频率,值越小淘汰优先级越高
平时开发过程中用的比较多的就是allkeys-lru(结合自己的业务场景)
面试回答:
分布式锁(Redisson)
- redis分布式锁,是如何实现的?
先按照自己简历上的业务进行描述分布式锁使用的场景
我们当使用的redisson实现的分布式锁,底层是setnx和lua脚本(保证原子性)
- Redisson实现分布式锁如何合理的控制锁的有效时长?
在redisson的分布式锁中,提供了一个WatchDog(看门狗)-个线程获取锁成功以后
WatchDog会给持有锁的线程续期(默认是每隔10秒续期一次)
WatchDog(看门狗):当一个业务执行的时间,超过了看门狗默认时间10秒,看门狗就会续期
- Redisson的这个锁,可以重入吗?
可以重入,多个锁重入需要判断是否是当前线程,在redis中进行存储的时候使用的hash结构来存储线程信息和重入的次数
- Redisson锁能解决主从数据一致的问题吗
不能解决,但是可以使用redisson提供的红锁来解决,但是这样的话,性能就太低了,如果业务中非要保证数据的强一致性,建议采用zookeeper实现的分布式锁
面试回答:
Redis主从复制
- 介绍一下redis的主从同步
单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离。-般都是一主多从,主节点负责写数据,从节点负责读数据
- 能说一下,主从同步数据的流程
全量同步:
1.从节点请求主节点同步数据(replicationid、offset)
2.主节点判断是否是第一次请求,是第一次就与从节点同步版本信息(replication id和offset)
3.主节点执行bgsave,生成rdb文件后,发送给从节点去执行
4.在rdb生成执行期间,主节点会以命令的方式记录到缓冲区(一个日志文件)
5.把生成之后的命令日志文件发送给从节点进行同步
增量同步:
1.从节点请求主节点同步数据,主节点判断不是第一次请求,不是第一次就获取从节点的offset值
2.主节点从命令日志中获取offset值之后的数据,发送给从节点进行数据同步
面试回答:
哨兵模式、集群脑裂
- 怎么保证Redis的高并发高可用
哨兵模式:实现主从集群的自动故障恢复(监控、自动故障恢复、通知)
- 你们使用redis是单点还是集群,哪种集群
主从(1主1从)+哨兵就可以了。单节点不超过10G内存,如果Redis内存不足则可以给不同服务分配独立的Redis主从节点
- redis集群脑裂,该怎么解决呢?
集群脑裂是由于主节点和从节点和sentinel处于不同的网络分区,使得sentinel没有能够心跳感知到主节点,所以通过选举的方式提升了一个从节点为主,这样就存在了两个master,就像大脑分裂了一样,这样会导致客户端还在老的主节点那里写入数据,新节点无法同步数据,当网络恢复后,sentinel会将老的主节点降为从节点,这时再从新master同步数据,就会导致数据丢失
解决:我们可以修改redis的配置,可以设置最少的从节点数量以及缩短主从数据同步的延迟时间,达不到要求就拒绝请求就可以避免大量的数据丢失
面试回答:
分片集群
- redis的分片集群有什么作用
- 集群中有多个master,每个master保存不同数据
- 每个master都可以有多个slave节点
- master之间通过ping监测彼此健康状态
- 客户端请求可以访问集群任意节点,最终都会被转发到正确节点
- Redis分片集群中数据是怎么存储和读取的?
- Redis 分片集群引入了哈希槽的概念,Redis 集群有 16384 个哈希槽
- 将16384个插槽分配到不同的实例
- 读写数据:根据key的有效部分计算哈希值,对16384取余(有效部分,如果key前面有太括号,大括号的内容就是有效部分,如果没有,则以key本身做为有效部分)余数做为插槽,寻找插槽所在的实例
面试回答:
Redis为什么快
1、完全基于内存的,C语言编写
2、采用单线程,避免不必要的上下文切换可竞争条件
3、使用多路I/0复用模型,非阻塞I0
例如:bgsave和 bgrewriteaof 都是在后台执行操作,不影响主线程的正常使用,不会产生阻塞
I/O多路复用
I/0多路复用是指利用单个线程来同时监听多个Socket,并在某个Socket可读、可写时得到通知,从而避免无效的等待,充分利用CPU资源。目前的I/0多路复用都是采用的epoll模式实现,它会在通知用户进程Socket就绪的同时,把已就绪的Socket写入用户空间,不需要挨个遍历Socket来判断是否就绪,提升了性能。
其中Redis的网络模型就是使用I/0多路复用结合事件的处理器来应对多个Socket请求,比如,提供了连接应答处理器、命令回复处理器,命令请求处理器;
在Redis6.0之后,为了提升更好的性能,在命令回复处理器使用了多线程来处理回复事件,在命令请求处理器中,将命令的转换使用了多线程,增加命令转换速度,在命令执行的时候,依然是单线程
MySQL
如何定位慢查询
1.介绍一下当时产生问题的场景(我们当时的一个接口测试的时候非常的慢,压测的结果大概5秒钟)
2.我们系统中当时采用了运维工具(Skywalking),可以监测出哪个接口,最终因为是sql的问题
3.在mysql中开启了慢日志查询,我们设置的值就是2秒,一旦sql执行超过2秒就会记录到日志中(调试阶段)
面试回答:
explain分析
- 那这个SQL语句执行很慢,如何分析呢?
可以采用MySQL自带的分析工具 EXPLAIN
- 通过key和key len检查是否命中了索引(索引本身存在是否有失效的情况)
- 通过type字段查看sql是否有进一步的优化空间,是否存在全索引扫描或全盘扫描
- 通过extra建议判断,是否出现了回表的情况,如果出现了,可以尝试添加索引或修改返回字段来修复
面试回答:
索引
- 什么是索引
索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定査找算法的数据结构(B+树),这些数据结构以某种方式引用(指向)数据, 这样就可以在这些数据结构上实现高级查找算法这种数据结构就是索引。
B+树
- 了解过索引吗?(什么是索引)
- 索引(index)是帮助MySQL高效获取数据的数据结构(有序)
- 提高数据检索的效率,降低数据库的I0成本(不需要全表扫描)
- 通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗
- 索引的底层数据结构了解过嘛?
MySQL的InnoDB引擎采用的B+树的数据结构来存储索引
- 阶数更多,路径更短
- 磁盘读写代价B+树更低,非叶子节点只存储指针,叶子阶段存储数据
- B+树便于扫库和区间查询,叶子节点是一个双向链表
面试回答:
聚簇索引 、非聚簇索引、回表查询
面试回答:
覆盖索引、超大分页优化
覆盖索引是指查询使用了索引,返回的列,必须在索引中全部能够找到
- 使用id查询,直接走聚集索引查询,一次索引扫描,直接返回数据,性能高。
- 如果返回的列中没有创建索引,有可能会触发回表查询,尽量避免使用select *
MYSQL超大分页怎么处理
问题:在数据量比较大时,limit分页查询,需要对数据进行排序,效率低
解决方案:覆盖索引+子查询
面试回答:
索引创建原则
1).数据量较大,且查询比较频繁的表
2).常作为查询条件、排序、分组的字段
3).字段内容区分度高
4).内容较长,使用前缀索引
5).尽量联合索引
6).要控制索引的数量
7).如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它
面试回答:
索引失效
- 什么情况下索引会失效 ?
- 违反最左前缀法则
- 范围查询右边的列,不能使用索引
- 不要在索引列上进行运算操作,索引将失效
- 字符串不加单引号,造成索引失效。(类型转换)
- 以%开头的Like模糊查询,索引失效
面试回答:
SQL优化
- 谈一谈你对sql的优化的经验
- 表的设计优化,数据类型的选择
- 索引优化,索引创建原则
- sql语句优化,避免索引失效,避免使用select *
- 主从复制、读写分离,不让数据的写入,影响读操作
- 分库分表
面试回答:
事务
- ACID是什么?可以详细说一下吗?
- 原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
- 一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态。
- 隔离性(lsolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
- 持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。
面试回答:
事务问题、隔离级别
并发事务带来哪些问题?怎么解决这些问题呢?MySQL的默认隔离级别是?
- 并发事务的问题:
- 脏读:一个事务读到另外一个事务还没有提交的数据。
- 不可重复读:一个事务先后读取同一条记录,但两次读取的数据不同
- 幻读:一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了”幻影”。
- 隔离级别:
- READ UNCOMMITTED 未提交读 解决不了 脏读、不可重复读、幻读
- READ COMMITTED 读已提交 解决不了 不可重复读、幻读
- REPEATABLE READ 可重复读 解决不了 幻读
- SERIALIZABLE 串行化
面试回答:
undo log 和 redo log的区别
- redo log:记录的是数据页的物理变化,服务宕机可用来同步数据
- undo log:记录的是逻辑日志,当事务回滚时,通过逆操作恢复原来的数据
- redo log保证了事务的持久性,undolog保证了事务的原子性和一致性
面试回答:
事务隔离性
事务中的隔离性是如何保证的呢?
- 锁:排他锁(如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁)
- mvcc:多版本并发控制
MVCC
解释一下MVCC
全称 Multi-Version Concurrency Control,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突
实现原理
问题:
面试回答:
主从同步
- 实现原理
MySQL主从复制的核心就是二进制日志binlog(DDL(数据定义语言)语句和 DML(数据操纵语言)语句)
① 主库在事务提交时,会把数据变更记录在二进制日志文件 Binlog 中。
② 从库读取主库的二进制日志文件 Binlog ,写入到从库的中继日志 Relay Log 。
③ 从库重做中继日志中的事件,将改变反映它自己的数据
面试回答:
分库分表
分库分表时机预判:
1,前提,项目业务数据逐渐增多,或业务发展比较迅速单表的数据量达1000W或20G以后
2,优化已解决不了性能问题(主从读写分离、查询索引...)
3,I/0瓶颈(磁盘10、网络I0)、CPU瓶颈(聚合查询、连接数太多)
垂直分库
垂直分表
水平分库
水平分表
分库分表遇到的问题
面试回答
Spring
单例bean是线程安全吗
不是线程安全的
Spring框架中有一个@Scope注解,默认的值就是singleton,单例的。
因为一般在spring的bean的中都是注入无状态的对象,没有线程安全问题,如果在bean中定义了可修改的成员变量,是要考虑线程安全问题的,可以使用多例或者加锁来解决
面试回答:
AOP
什么是AOP
- 你们项目中有没有使用到AOP
- 记录操作日志,缓存,spring实现的事务
- 核心是:使用aop中的环绕通知+切点表达式(找到要记录日志的方法)通过环绕通知的参数获取请求方法的参数(类、方法、注解、请求方式等),获取到这些参数以后,保存到数据库
- Spring中的事务是如何实现的
其本质是通过AOP功能,对方法前后进行拦截,在执行方法之前开启事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
事务失效
- 异常捕获处理,自己处理了异常,没有抛出,解决:手动抛出
- 抛出检查异常,配置rollbackFor属性为Exception
- 非public方法导致的事务失效,改为public
bean的生命周期
bean的循环依赖
- 构造方法出现了循环依赖怎么解决?
A依赖于B,B依赖于A,注入的方式是构造函数
原因:由于bean的生命周期中构造函数是第一个执行的,spring框架并不能解决构造函数的的依
赖注入
解决方案:使用@Lazy进行懒加载,什么时候需要对象再进行bean对象的创建
SpringMVC
JSP版
SpringMVC的执行流程知道嘛
① 用户发送出请求到前端控制器DispatcherServlet
② DispatcherServlet收到请求调用HandlerMapping(处理器映射器)
③ HandlerMapping找到具体的处理器,生成处理器对象及处理器拦截器(如果有),再一起返回给DispatcherServlet.
④ DispatcherServlet调用HandlerAdapter(处理器适配器)
⑤ HandlerAdapter经过适配调用具体的处理器(Handler/Controller)
⑥ Controller执行完成返回ModelAndView对象
⑦ HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet
⑧ DispatcherServlet将ModelAndView传给ViewReslover(视图解析器)
⑨ViewReslover解析后返回具体View(视图)
⑩ DispatcherServet根据View进行渲染视图(即将模型数据填充至视图中)
⑪. DispatcherServlet响应用户
前后端开发版
① 用户发送出请求到前端控制器DispatcherServlet
② DispatcherServlet收到请求调用HandlerMapping(处理器映射器)
③ HandlerMapping找到具体的处理器,生成处理器对象及处理器拦截器(如果有),再一起返回给DispatcherServlet。
④ DispatcherServlet调用HandlerAdapter(处理器适配器)
⑤ HandlerAdapter经过适配调用具体的处理器(Handler/Controller)
⑥ 方法上添加了@ResponseBody
⑦ 通过HttpMessageConverter来返回结果转换为JSON并响应
spring boot自动配置
源码
1,在Spring Boot项目中的引导类上有一个注解@SpringBootApplication,这个注解是对三个注解进行了封装,分别是:
@SpringBootConfiquration
@EnableAutoConfiguration
@ComponentScan
2,其中@EnableAutoConfiguration是实现自动化配置的核心注解。 该注解通过@Import注解导入对应的配置选择器,内部就是读取了该项目和该项目引用的Jar包的的classpath路径下META-INF/spring.factories文件中的所配置的类的全类名。 在这些配置类中所定义的Bean会根据条件注解所指定的条件来决定是否需要将其导入到Spring容器中。
3,条件判断会有像@ConditionalOnClass这样的注解,判断是否有对应的class文件,如果有则加载该类,把这个配置类的所有的Bean放入spring容器中使用。
面试回答:
spring的常见注解
mybatis的执行流程
① 读取MyBatis配置文件:mybatis-config.xml加载运行环境和映射文件
② 构造会话工厂SqlSessionFactory
③ 会话工厂创建SqlSession对象(包含了执行SQL语句的所有方法)
④ 操作数据库的接口,Executor执行器,同时负责查询缓存的维护
⑤ Executor接口的执行方法中有一个MappedStatement类型的参数,封装了映射信息
⑥ 输入参数映射
⑦ 输出结果映射
mybatis延迟加载
mybatis 一级、二级缓存
一级缓存
二级缓存
面试回答:
spring cloud
五大组件
注册中心Eureka、Nacos
Eureka作用
面试回答:
Nacos作用
面试回答:
Ribbon负载均衡
面试回答:
服务雪崩、服务降级
降级
自己编写降级策略
面试回答
skywalking 监控
作用
问题定位:
性能分析:
服务关系:
服务告警:
面试回答:
服务限流
Nginx限流方案一(漏桶算法):
Nginx限流方案二(控制并发连接数):
网关限流
面试回答:
分布式 CAP 和 BASE
CAP
C
A
P
结论:
BASE:
BASE理论是对CAP的一种解决思路,包含三个思想:
- Basically Available(基本可用):分布式系统在出现故障时,允许损失部分可用性,即保证核心可用。
- Soft state(软状态):在一定时间内,允许出现中间状态,比如临时的不一致状态。
- Eventually Consistent(最终一致性):虽然无法保证强一致性,但是在软状态结束后,最终达到数据一致。
面试回答:
分布式事务
Seata 架构
XA模式,强一致性CP
AT模式,AP 高可用
TCC模式 ,AP 高可用
MQ 分布式事务
面试回答:
幂等性
接口幂等
分布式锁
面试回答:
分布式任务调度
分片广播
面试回答:
消息中间件
RabbitMQ如何保证消息不丢失
生产者确认
消息持久化,三者必做持久化
消费者确认,一般选择自动ack
面试回答:
RabbitMQ重复消费问题
面试回答:
死信交换机
面试回答:
延迟队列TTL
方案一:
方案二:插件
面试回答:
100w 消息如何解决
惰性队列
面试回答:
RabbitMQ高可用
普通集群(很少用)
镜像集群(高可用)
仲裁队列(强一致)
面试回答:
算法复杂度分析
时间复杂度
O(n) :只有 n 影响整体时间
常见的复杂度表示(常对幂指阶)
O(1)
O(n)
O(n²)
O(log n)
O(n * log n):O(n) 和 O(log n) 相结合
空间复杂度
O(1)
O(n)
作用
面试回答:
集合
ArrayList 数据结构
为什么数组索引从0开始
操作数组时间复杂度(查找)
操作数组时间复杂度(插入、删除)
面试回答:
ArrayList 源码分析
成员变量
构造方法
第一次添加数据(需扩容)
第2-10次添加数据(不需扩容)
第11次添加数据(需扩容)
面试回答:
数组和 List 之间的转换
单向链表 和 双向链表
单向链表
双向链表
面试回答
ArrayList 和 linkedList 区别
二叉树
面试回答:
红黑树
复杂度
面试回答:
散列表
散列冲突
解决冲突
时间复杂度
链表 改造成 红黑树查询
面试回答:
HashMap 实现原理
面试回答:
HashMap 源码分析
构造方法
添加数据
面试回答:
HashMap 扩容机制
面试回答:
HashMap 动画演示
未扩容
扩容
链表添加
HashMap 寻址算法
面试回答:
HashMap 在jdk1.7扩容导致死循环
并发编程-线程
进程 与 线程
进程
线程
区别
并行 与 并发
面试回答:
线程创建方式
面试回答:
线程状态
面试回答:
线程按顺序执行
wait 和 sleep 方法的不同
如何停止一个正在运行的线程
synchronized 关键字原理
synchronized 进阶
JMM (Java内存模型)
CAS 自旋锁
面试回答:
volatile 关键字
保证线程的可见性
禁止指令重排
面试回答:
AQS 锁
面试回答:
ReentrantLock
synchronized 和 Lock 的区别
可打断:在锁等待的时候,可打断等待
可超时:在第一次获取锁失败后,可指定时间再次获取
多条件变量:可自定义设置多个锁变量,每个线程对应每个变量加锁和释放锁
死锁产生的条件
命令行检查
可视化工具
面试回答:
ConcorrentHashMap 线程安全
jdk 1.7
jdk 1.8
面试回答:
保证多线程执行安全
并发程序出现问题的根本原因
原子性:
可见性:
有序性:
面试回答:
线程池原理
正在执行的线程有三个,任务队列有两个线程,如果再进来一个,则抛出异常
线程池 如何确定核心线程数
线程池的种类
种类一
种类二:
种类三:
种类四:
面试回答:
为什么不允许用 Executors 创建线程池
线程池使用场景一
等待其他线程执行完成
线程池使用场景二
数据汇总,获取线程执行结果
线程池使用场景三
项目用到哪些多线程场景
如何控制某个方法允许并发访问线程的数量
信号量
面试回答
ThreadLocal 的理解
设置并获取当前线程的值
源码
内存泄漏问题
面试回答:
JVM
JVM介绍
程序计数器
堆
面试回答:
虚拟机栈
栈内存溢出
面试回答:
堆 和 栈 的区别
方法区
常量池
运行时常量池
面试回答:
直接内存
类加载器
双亲委派机制
类装载的执行过程
对象什么时候可以被拉机器回收
JVM 垃圾回收算法
JVM 分代回收
JVM 垃圾回收器
G1 垃圾回收器
强引用、软引用、弱引用、虚引用
Java 调优参数设置
JVM 调优工具
Java 内存泄漏排查思路
获取离线的 dump 文件
面试回答:
CPU 飙高排查方案
面试回答:
设计模式
简单工厂模式
缺点:不遵循开闭原则
工厂方法模式
遵循开闭原则
缺点:增加系统复杂度
抽象工厂模式
三种工厂区别
策略模式
策略+工厂模式
面试回答:
责任链模式
案例
企业场景
单点登录
上传数据安全性
对称加密:前后端同一把秘钥
非对称加密:前端公钥,后端私钥
面试回答:
项目遇到的一些棘手的问题
日志采集
查看日志的命令
生产问题怎么排查
系统瓶颈定位
火焰图
资料
https://pan.baidu.com/s/1NQZDW-9_VCnEUXcXp_G-bA 提取码: 9987