1、springboot启动流程
总览:
-
进行SpringBoot的初始化模块,配置一些基本的环境变量、资源、构造器、监听器
SpringApplication的run(Class clazz)方法会创建一个SpringApplication对象,在创建的初始化方法中会构建Spring框架所需要的环境变量、资源、构造器、监听器。
spring通过getSpringFactoriesInstances(Class clazz)方法来加载实例化构造器和监听器等,此方法中调用SpringFactoriesLoader.loadFactoryNames(type, classLoader)方法加载配置在模块的spring.factories文件里面的类
spring.factories里面的内容如:
-
实现了应用的具体的启动方案,包括启动流程的监听模块、加载配置环境模块、及核心的创建上下文环境模块
-
自动化配置模块,该模块为springboot自动配置核心
springBoot的自动化配置主要是通过getSpringFactoriesInstances(Class clazz)方法来加载实例化自动配置的实体,自动配置类中的 @ConditionalOnClass、 @CondtionalOnBean、 @ConditionalOnMissingBean会根据条件配置 相关的类
@SpringBootApplication是一个组合注解,包括:
@EnableAutoConfiguration:SpringBoot根据应用所配置的依赖来对spring框架进行自动的配置
@SpringBootConfiguration:加载spring的bean
@ComponentScan: 扫描配置的Bean
2、mybtisplus的原理
3、动态代理
4、数据库锁
数据库锁包括,行锁、表锁、乐观锁、悲观锁、排它锁
INNODB支持行锁,当使用for update如果没有使用到主键,则会导致锁表。因为INNODB引擎的锁是锁索引,所以当where语句后面的条件不是所有的时候会锁全表,但是mysql针对这个进行了优化,虽然会先锁住所有的行,但是条件不满足的行会提前释放锁。
5、导致full gc的情况
6、gc算法
7、mysql为什么会选择b+树
8、mq事务消息要注意点什么
9、地图系统
10、组合索引什么时候会失效
在不满足最左匹配原则的时候会失效
11、怎么保证变量的安全发布
12、java8的新特性
13、beanfactory和factorybean的区别
BeanFactory是接口,提供了IOC容器最基本的形式,给具体的IOC容器的实现提供了规范,它的职责包括:实例化,定位,配置应用程序中的对象及建立这些对象间依赖。只是个接口,不是具体的实现,具体的实现有:xmlBeanFactory、ApplicationContext。FactoryBean也是接口,为IOC容器中Bean的实现提供了更加灵活的方式,FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式。我们可以在getObject()方法中灵活配置。其实在Spring源码中有很多FactoryBean的实现类。
区别:BeanFactory是个Factory,也就是IOC容器或者对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory也就是IOC容器来管理的,但是对于FactoryBean来说,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和装饰着模式类似。
14、spring源码分析
15、Myisam和InnoDB的区别
-
innodb支持事务,myisam不支持事务
-
innodb支持外键,myisam不支持外键
-
innodb是聚簇索引,使用b+树作为索引结构。Myisam使用的是非聚簇索引,也是使用B+树作为索引结构,但是索引和数据结构是分离的,数据保存的是数据文件的指针。主键索引和辅助索引是独立的。
-
innodb不保存表的行数,执行select count(*)时会扫描整张表。myisam则保存了总数据数。因为在myisam中每个事务中的行数是不一样的
-
innodb支持表,行级锁。myisam只支持表级锁。InnoDB的行锁是实现在索引上的,而不是锁在物理行记录上。潜台词是,如果访问没有命中索引,也无法使用行锁,将要退化为表锁。MySQL进行了改进,在进行过滤条件时,发现不满足条件后,会调用 unlock_row 方法,把不满足条件的记录放锁(违背了2PL原则)。这样做,保证了最后满足条件的记录加上锁,但是每条记录的加锁操作是不能省略的。
16、集合源码
如果创建集合时没有选择长度,则初始长度为10。ArrayList扩容
新集合的长度为原来长度+原来长度/2。如果扩容的长度计算出来比ArrayList的最大的长度还要长
17、使用过哪些中间件,挑一个自己熟悉的说一下
rocketMQ:重置消费位点 - 消息队列RocketMQ版 - 阿里云
系统部署架构:
-
Name Server:是一个几乎无状态节点,可集群部署,在消息队列RocketMQ版中提供命名服务,更新和发现Broker服务。
-
Broker:消息中转角色,负责存储消息,转发消息。分为Master Broker和Slave Broker,一个Master Broker可以对应多个Slave Broker,但是一个Slave Broker只能对应一个Master Broker。Broker启动后需要完成一次将自己注册至Name Server的操作;随后每隔30s定期向Name Server上报Topic路由信息。
-
生产者:与Name Server集群中的其中一个节点(随机)建立长链接(Keep-alive),定期从Name Server读取Topic路由信息,并向提供Topic服务的Master Broker建立长链接,且定时向Master Broker发送心跳。
-
消费者:与Name Server集群中的其中一个节点(随机)建立长连接,定期从Name Server拉取Topic路由信息,并向提供Topic服务的Master Broker、Slave Broker建立长连接,且定时向Master Broker、Slave Broker发送心跳。Consumer既可以从Master Broker订阅消息,也可以从Slave Broker订阅消息,订阅规则由Broker配置决定。
RocketMQ的消息存储是由sonsum queue和commit log配合完成的。consume queue是消息的逻辑队列,相当于字典的目录,用来指定消息在物理文件commit log上的位置。
消费模式:
集群消费模式:
-
集群消费模式下,每一条消息都只会分发到一台机器上处理。如果需要被集群下的每一台机器处理,请使用广播模式
-
集群消费模式下,不保证每一次失败重投的消息路由到同一台机器上
广播消费模式:
-
适用于消费端集群化部署,每条消息需要被集群下的每个消费者处理的场景。
-
注意事项:
-
广播消费模式下不支持顺序消息。
-
广播消费模式下不支持重置消费位点。(按需清除堆积的或不想消费的这部分消息再开始消费,或直接跳转到某个时间点消费该时间点之后的消息(不论是否消费过该时间点之前的消息)。广播消费模式不支持重置消费位点。目前不支持指定的Message ID、Message Key和Tag来重置消息消费的位点。当前在控制台上仅能重置TCP协议使用的Group ID的消费位点。)
-
每条消息都需要被相同订阅逻辑的多台机器处理。
-
消费进度在客户端维护,出现重复消费的概率稍大于集群模式。
-
广播模式下,消息队列RocketMQ版保证每条消息至少被每台客户端消费一次,但是并不会重投消费失败的消息,因此业务方需要关注消费失败的情况。
-
广播模式下,客户端每一次重启都会从最新消息消费。客户端在被停止期间发送至服务端的消息将会被自动跳过,请谨慎选择。
-
广播模式下,每条消息都会被大量的客户端重复处理,因此推荐尽可能使用集群模式。
-
广播模式下服务端不维护消费进度,所以消息队列RocketMQ版控制台不支持消息堆积查询、消息堆积报警和订阅关系查询功能。
消息类型:
-
同步发送消息:可靠的同步传输用于重要的通知消息、短信通知、短信营销系统等广泛场景同步消息需要等消息发送成功之后才结束线程,不然将阻塞在消息发送
-
异步发送消息:异步传输通常用于响应时间敏感的业务场景。消息发送不会阻塞当前的线程,消息发送成功之后会调用回调方法通知发送状态
-
以单向模式发送消息:这个方式发送消息只会发送消息,不会阻塞且不提供回执
注意问题:
-
如何解决RocketMq的顺序消费和重复消费。参考:阿里RocketMQ如何解决消息的顺序&重复两大硬伤?
-
RocketMq的顺序消息:RocketMq使用FIFO顺序提供有序消息。
-
消息得堆积和延迟问题:RocketMq的消费模式分为pull拉模式和push推模式。SDK客户端使用Push模式消费消息时,分为一下两个阶段。
-
阶段一:获取消息,SDK客户端通过长轮询批量拉取的方式从消息队列RocketMQ版服务端获取消息,将拉取到的消息缓存到本地缓冲队列中。 SDK获取消息的方式为批量拉取,常见内网环境下都会有很高的吞吐量,例如:1个单线程单分区的低规格机器(4C8GB)可以达到几万TPS,如果是多个分区可以达到几十万TPS。所以这一阶段一般不会成为消息堆积的瓶颈。
-
提交消费线程,SDK客户端将本地缓存的消息提交到消费线程中,使用业务消费逻辑进行处理。 此时客户端的消费能力就完全依赖于业务逻辑的复杂度(消费耗时)和消费逻辑并发度了。如果业务处理逻辑复杂,处理单条消息耗时都较长,则整体的消息吞吐量肯定不会高,此时就会导致客户端本地缓冲队列达到上限,停止从服务端拉取消息。
通过以上客户端的消费原理可以看出,消息堆积的主要瓶颈在于本地客户端的消费能力,即消费耗时和消费并发度。想要避免和解决消息堆积问题,必须合理的控制消费耗时和消息并发度,其中消费耗时的优先级高于消费并发度,必须先保证消费耗时的合理性,再考虑消费并发度问题。
如何避免和解决消息堆积和延迟:消息堆积和延迟问题 - 消息队列RocketMQ版 - 阿里云
-
同一个groupid的消费者应该只消费同一种topic和tag的消息,不然会导致消息的混乱
-
保证消息的可靠性,消息的不丢失
-
采用同步的方式发送消息,等待消息发送回调成功后才进行下面的处理。发送失败的时候重试
-
broker设置多个master节点,即使某台broker宕机了,可以保证消息投递到另外一台broker上
-
提供同步刷盘策略,即等待消息落盘之后再返回消息发送成功
-
在消费端保证消息的可靠性:
-
消费端的ack机制分为两种思路:一种是先提交后消费,第二种是先消费,消费成功之后再提交。第一种可以解决重复消费的问题,rocketmq默认采用第二种方式,并再业务的保证幂等性
死信队列:
当一条消息初次消费失败,消息队列RocketMQ版会自动进行消息重试,达到最大重试次数后,若消费依然失败,则表明消费者在正常情况下无法正确地消费该消息。此时,消息队列RocketMQ版不会立刻将消息丢弃,而是将其发送到该消费者对应的特殊队列中。
死信消息特性:
-
不会再被消费者正常消费。
-
有效期与正常消息相同,均为3天,3天后会被自动删除。因此,请在死信消息产生后的3天内及时处理。
死信队列特性:
-
一个死信队列对应一个Group ID, 而不是对应单个消费者实例。
-
如果一个Group ID未产生死信消息,消息队列RocketMQ版不会为其创建相应的死信队列。
-
一个死信队列包含了对应Group ID产生的所有死信消息,不论该消息属于哪个Topic。
18、java中的类加载机制,为什么要采用双亲委派机制
源码参考:我竟然被“双亲委派”给虐了
19、怎么实现消息的顺序消费
20、熔断器
21、zk分布式锁
22、数据库日志级别
23、使用redis实现一个阻塞队列,缓存的淘汰策略,redis的key过期是通过什么实现的
24、数据库事务的原理,数据库日志级别
数据库事务通过各种操作日志保证事务得原子性、隔离性、一致性、持久性
原子性:
-
当事务提交成功,但是此时数据库发生异常,当数据库恢复之后怎么保证提交完成得事务得操作。实际上是和上文说的持久性是相关联的,而这个是基于重做日志(redo log)来保证提交完成的事务在异常情况下保证数据操作能够进行:
-
事务提交失败,那么事务中得操作都失败:事务提交失败,那么事务中的操作都失败,这个是通过数据库的撤销操作日志来保证的,也称之为undo log
25、限流算法:高并发的场景下,不能不说的限流算法
-
单位时间内计算请求的次数,当达到最大的请求数时则限流。如果请求集中在一个时间断的结尾和另外一个时间段的开始,虽然两个时间段的请求数都在最大请求数之内,但单位时间最大请求数已经超过
-
滑块法:将时间段分成更小的时间段,并将请求限制数分到时间段内,当时间到了之后则移动滑块到另外一个时间段
-
漏捅算法: 就是我们有一个固定容量的桶,有水流进来,也有水流出去,我们不需要控制流进来的速度,只需要控制流出去的速度,如果水流进来的太快,桶满了,多余的水会溢出去,并不会影响水流出去的速度。
-
令牌捅算法:均匀的速度产生令牌,并将令牌放到一个桶中,当有请求过来的时候取到令牌桶中的令牌才能够请求。漏桶算法和令牌桶算法的区别: 漏桶算法能够强行限制数据的传输速率,而令牌桶算法能够在限制数据的平均传输速率的同时还允许某种程度的突发传输;
26、redis支持哪种数据类型,都在哪些场景使用
-
redis的数据类型
-
String key-value:redis是单线程的,不适合存储大容量数据。自增value可以转成数字
-
Hash:key-filed-value:相当于一个key对应一个map