1、项目模块讲解

1、请问你们项目并发量多大?部署有多少台服务器?

我当时主要关注业务功能开发,具体系统的压力测试有测试人员去做。所以具体数据不是非常清楚。
但是按照我的理解,我们那个项目是微服务架构的,设计的并发量应该不低。
至于生产服务器,我们公司一般是运维团队去管理,据我了解,为了实现高可用,一般的中间件和数据库例如MySQL,Redis,MQ,Elasticsearch等都会搭建集群或主从架构。

2、请问你们项目团队大概多少人?怎么分配的?

上家公司的研发团队大概20人左右,1名架构师,13名后端开发,前端3人,有1人运维,1人做测试的,1个项目经理和助理。
我们项目经理那边同时开发的不止一个项目,我当时参与的是那个资讯APP,大概有4名后端开发一起做,前端那边只有1个人

3、你们项目大概有几个微服务模块?项目多少张表?

我的项目大概10几个模块,核心业务微服务大概6-7个左右,比如文章微服务,运营端微服务,自媒体微服务,用户行为微服务,搜索微服务等。
因为每个微服务是独立数据库(10来个微服务,10个数据库),数据库表少的有几张,多的有几十张吧。

4、token过期了怎么办?怎么处理?

token续签。

1)用户登录后生成30分钟过期的token,发回给浏览器保存。
2)浏览器每次请求携带该token访问后台,后台每次取出token的过期时间,判断剩余过期时间小于10分钟了,后台重新生成一个30分钟过期的token给浏览器保存,
浏览器覆盖之前的token,以达到续签效果。

5、请问你们的前后端项目开发流程?(请问你们需求开发的流程?)

1)需求分析。分析业务需求,要实现什么功能
2)定义接口。接口包含请求方式,请求路径,请求参数,响应返回值。后端需要和前端工程师商量
3)开发和测试接口。后端一般使用poastman来测试接口
4)和前端联调。找前端一起调试接口。

6、项目中用到哪些设计模式?(必会)

单例模式:DataSource单例
工厂模式:SqlSessionFactory创建SqlSession SqlSessionFactory.openSession()
模板方法模式:RabbitTemplate RedisTemplate RedisTemplate
代理模式:Spring的AOP做日志(JDK动态接口代理或Cglib类代理)
建造者模式:SqlSessionFactoryBuilder QueryBuilder

7、请说说你在项目中遇到的难点?(高频题)

分布式事务

分布式事务 :
我在xx项目中遇到一个xx业务,该业务跨两个服务,同时更新两个数据库的表,在运行中发现该业务如果失败了,一边表成功,一边表不成功,这种情况组长说不允许出现这种数据不一致的情况,后来知道了是分布式事务的问题。我去研究了下seata,顺利用seata解决这个问题

2、Redis专题

3、MQ专题

1、如何保证Kafka的消息是有序的?

1)kafka每个partition(分区)中的消息在写入时都是有序的,但多个分区的消息时无序的。如果要保证一个topic消息是有序的,需要将partition数量调整为1
2)尽量采用同步发送方式

2、为什么Kafka那么快?

1)利用 Partition (分区)实现并行处理
2)顺序写磁盘
3)充分利用 Page Cache(减少磁盘擦写)
4)零拷贝技术,减少CPU上下文切换成本
5)消息的批处理
6)消息数据压缩

参考文章:https://zhuanlan.zhihu.com/p/183808742

3、RabbitMQ的消息发送模式?

1)简单模式(
2)工作队列模式
3)发布订阅模式
4)路由模式(

5)主题模式(*)

4、RabbitMQ 和 Kafka 有什么区别?

RabbitMQ:
优势:
1)支持语言非常广
2)稳定性很好,采用Erlang语言开发
3)吞吐量不算低,万级
4)RabbitMQ官方提供7种消息发送模式,开发者轻松选择合适的模式进行开发即可
缺点:
1)采用Erlang,太小众,研究源码很难

Kafka:
优势:
1)高吞吐量,百万级
2)稳定性好,采用zookeeper进行注册(Zookeep采用CP模式,高一致模式)
3)可以应用在大数据数据处理领域(KafkaStream)
缺点:
1)支持的开发语言比较少
2)耦合zk,依赖zookeeper进行注册

4、MySQL数据库专题

1、说说悲观锁和乐观锁?有哪些常见的悲观锁和乐观锁?

悲观锁:当要对数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对该数据进行加锁以防止并发问题。

常见的悲观锁实现:关系数据库MySQL的行锁和表锁,Java的 synchronized 关键字,分布式锁Redisson (Redis实现)

悲观锁优点:数据更加安全,不容易出现并发问题
悲观锁缺点:高并发时对性能较大,而且可能出现死锁现象。

乐观锁:乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果冲突,则返回给用户异常信息,让用户决定如何去做。乐观锁适用于读多写少的场景,这样可以提高程序的吞吐量。

常见的乐观锁实现:版本号控制:一般是在数据表中加上一个数据版本号 version 字段,表示数据被修改的次数。当数据被修改时,version 值会 +1。当线程 A 要更新数据时,在读取数据的同时也会读取 version 值,在提交更新时,若刚才读取到的 version 值与当前数据库中的 version 值相等时才更新,否则重试更新操作,直到更新成功。

用户表:tb_user
id name sex version
1 jack 男 1

select version v from tb_user where id = 1; v = 1
update tb_user set sex=’女’ where id = 1 and version = 1

乐观锁优势:并没有真正对操作加锁,对读多写少的场景性能影响小。

2、请说说MySQL表级锁和行级锁?

表级锁:对整个表记录锁定,一个事务修改表数据的时候,另一个事务无法修改表数据。

语法:
lock table tb_user read local;
update tb_user ssss
insert into tb_user
unlock;

特点:锁定范围比较大,比较影响性能
应用场景:在数据迁移场景下使用

行级锁:对表的某条(某些)记录锁定

行级锁分为 共享锁 和 排他锁

update/insert

共享锁:一个事务在修改记录的时候,另一个事务无法修改记录,但是可以读取。
update tb_user set sex=’女’ where id = 1 lock in share mode;

排他锁:一个事务在查询/修改记录的时候,另一个事务无法修改和读取数据。
select * from tb_user where id = 1 for update;

3、MySQL索引有哪些类型?

1)普通索引(INDEX):最基本的索引,没有任何限制 creata index a_index on tb_user(name)
2)唯一索引(UNIQUE):与”普通索引”类似,不同的就是:索引列的值必须唯一,但允许有空值,一张表可用多个唯一索引。
3)主键索引(PRIMARY KEY):是一种特殊的唯一索引,值唯一,但是不允许有空值,一张表只能有一个主键索引。
4)组合索引(INDEX)/复合索引/联合索引:为了更多的提高mysql效率可建立组合索引,遵循”最左前缀“原则。 tb_user(name,sex,age)
5)全文索引(FULLTEXT):仅可用于 MyISAM 表, 用于在一篇文章中,检索文本信息的, 针对较大的数据,生成全文索引很耗时好空间。

4、如何防止SQL注入?

1)JDBC使用PreparedStatement(不要使用Statement),在用mybatis/mybatis-plus时,则尽量使用#{param},不要用${param}
因为PreparedStatement可以先预编译sql语句(SQL语义确定),再进行赋值,这样不会改变sql语义。

2)使用过滤器过滤用户输入的特殊符号( # > < where )

3)对请求参数字符串长度,格式进行限制

5、BTree、B+Tree的区别?

特点:
B树叶子节点和非叶子节点都存数据(索引和数据都存储),且叶子节点数据无链指针;
B+树只有叶子节点存数据(叶子存储数据,非叶子存储索引),且叶子节点数据有链指针。

B树的优势:
在B树中,越靠近根节点的记录查找时间越快,只要找到关键字即可确定记录的存在;

B树的缺点:
当进行范围查找时,存在“回旋查找”的问题,效率低

B+树的优势:
所有叶子节点形成有序链表,便于范围查询(不存在回旋查询的问题)

正是因为B+有这样的特点,所以MySQL的索引采用B+树存储!!!
MySQL底层还对B+树进行优化,叶子节点采用双向链表,这样不管大于还是小于范围查询,都很快了!

6、为什么MySQL的索引采用B+树,而不是B树、Hash、二叉树、红黑树呢?

1)Hash哈希,只适合等值查询,不适合范围查询 id=5
2)一般二叉树,可能会特殊化为一个链表,相当于全表扫描
3)红黑树,是一种特化的平衡二叉树,MySQL 数据量很大的时候,索引的体积也会很大,内存放不下的而从磁盘读取,树的层次太高的话,读取磁盘的次数就多了。
4)B树在范围查询时,存在回旋查找的问题,导致性能不高。B+树叶子节点是有序链表,更有利于范围查询。(MySQL的索引对B+树的叶子节点进行改造,形成双向链表!!!)

4、MySQL表引擎有哪些?这些引擎有什么区别?MySQL的MyISAM和InnoDB的索引使用B+Tree实现有什么不同?

MySQL表引擎常用:
1)InnoDB
2)MyISAM

MySQL表引擎的区别:
1)InnoDB支持事务,InnoDB支持表级和行级锁,InnoDB是采用聚簇索引
2)MyISAM不支持事务,MyISAM只支持表级锁,不支持行级锁,MyISAM采用非聚簇索引

InnoDB采用聚集(聚簇)索引存储,索引和数据存储一个文件中,默认使用表的主键列值来构建B+树(表没定义主键也会包含隐式主键)
.frm
MyISAM采用非聚集(非聚簇)索引存储,索引和数据文件是分两个文件存储的,可以没有主键索引
.myi .myk

7、请问关于设计数据库你有什么心得?(必问)

1)关系数据库的三大范式
第一范式(1NF):字段不可分,否则就不是关系数据库
第二范式(2NF):有主键,非主键字段依赖主键;突出唯一性
第三范式(3NF):非主键字段不能相互依赖。每列都与主键有直接关系

2)冗余字段设计(解决一对多关系)
比如文章表故意冗余了作者名称字段,这样查询文章时直接显示作者名称,减少关联表查找作者表,提高查询效率。

3)一个字段存储多个ID值(用逗号隔开)(解决多对多的关系)
减少表连接,提高查询效率

比如,自媒体或App文章的多个封面图片地址,设计一个封面字段images存储了所有封面地址,每个地址用逗号隔开。

5、SpringCloud组件专题

1、面试题:SpringCloud vs SpringCloudAlibaba 什么关系?

SpringCloud 属于Spring家族的一员
Eureka Gateway Feign Ribbon Hystrix SpringCloudConfig Slueth

  1. 看依赖:spring-cloud-starter-eureka-server/client

SpringCloudAlibaba 属于SpringCloud的一套组件
Nacos Sentinel Seata

         看依赖:spring-cloud-starter-alibaba-xxxx

2、面试题:Sentinel 和 Hystrix 的区别?

1)隔离方式不同,Sentinel采用信号量,Hystrix默认采用线程池,信号号量性能比线程池好

2)熔断策略不同,Sentinel可以基于超时和异常比例,Hystrix只支持异常比例

3)限流功能不同,Sentinel有丰富限流功能(QPS,链路模式等),Hystrix限流功能非弱

4)第三方框架整合,Sentinel可以整合SpringCloud和Dubbo,Hystrix只能整合SpringCLoud

3、面试题:项目中使用了熔断机制吗?

项目也使用了Sentinel作为熔断机制。Sentinel实现熔断机制主要有线程隔离和熔断降级,首先我们项目要
在yml配置中开启Sentinel的线程隔离和熔断降级功能,然后在Sentinel界面加上隔离最大并发线程数或熔断参数配置,接着给Feign接口定制一个服务降级实现类,在隔离和熔断发生后,给用户提示友好信息。

feign:
sentinel:
enabled: true # 开启sentinel支持

public class UserClientFallbackFactory implements FallbackFactory {
@Override
public UserClient create(Throwable throwable) {
return new UserClient() {
@Override
public User findById(Long id) {
User user = new User();
user.setUsername(“查无此人”);
user.setAddress(“查无地址”);
return user;
}
};
}
}

1)线程隔离:
在服务消费方加入服务调用占用线程数统计,一旦超过线程数上限,则做服务降级(在服务消费方定制一个降级处理方法,定制失败消息)

2)熔断降级:
在服务消费方加入超时或异常比例统计程序,该程序一旦统计超过比例,一旦比例超过阈值,则做服务降级(在服务消费方定制一个降级处理方法,定制失败消息),熔断有时长,时间到达会尝试请求1次,如果成功,则正常调用,如果失败,继续熔断。

4、面试题:请问 熔断 和 降级 的区别?

1)熔断:是一个Sentinel或Hystrix框架的一个自带的机制,该机制统计超时比例或异常比例的程序。当熔断达到异常比例或超时比例的阈值时,就会发生降级。
2)降级:其实本质就是一个Fallback实现类,返回给用户友好信息。
3)通常在项目中可以加入线程隔离或熔断机制,一旦程序线程隔离或者熔断了,就会进入降级。

5、面试题:请解释一下SpringCloud中Feign接口调用的过程?

首先,Feign接口写在服务消费方,消费方在调用Feign接口的时候,会扫描Feign接口上面的注解(如@FeignClient、@GetMapping @RequestParam等),然后拼接需要调用的url路径和参数值,接着,在
底层利用JDK动态代理产生代理对象,代理对象底层使用RestTemplate向服务提供方发出请求,获取响应结果
响应结果返回到消费方后,会进行结果解析(如返回json数据的话会利用Jackson框架转换为对象给我们返回)

6、面试题:能不能大概解释一下熔断器的执行流程?

首先,熔断器就是一个超时比例或异常比例的统计程序,该程序放在服务消费方,当超时比例或异常比例没有达到阈值,熔断器处于关闭状态,请求可以正常通过。
但是,当超时比例或异常比例到达阈值,熔断器开启,所有请求会立即被降级,请求降级后会执行我们定制的Fallback接口,返回给用户友好提示信息。
接着,熔断器会等待一段时间(如5s),然后进入半开状态,半开状态会放行一个请求尝试调用,如果失败,继续保持打开状态,如果成功,则回到关闭状态。

7、在SpringBot项目中如何让一个Bean放到IOC容器?

1)直接在Bean上面加@Component,让该Bean的包名在项目启动类同级或子级下。
2)直接在Bean上面加@Component,在项目下写@Configuration配置类,通过@ComponentScan注解自行扫描Bean的目录
3)在项目下写@Configuration配置类(放在启动类同级或子级下),直接写一个方法创建Bean对象,方法上添加@Bean注解
4)在项目下写@Configuration配置类(不放在启动类同级或子级下),在resources/META-INF/spring.factories文件 把配置类添加到SpringBoot自动装配列表中,让其加载,在配置类中写一个方法创建Bean对象,方法上添加@Bean注解

8、Nacos和Eureka的区别?

相同点:
1)两者支持服务注册和服务拉取
2)两者都支持服务者心跳机制实现健康检测(续约)

不同点:
1)Nacos可以实现服务注册发现,也可以做配置管理;Eureka只能做服务注册发现。
2)Nacos临时实例心跳不正常会被剔除,非临时实例(永久实例)则不会被剔除;而Eureka只能注册临时实例,实例失效会被剔除(Eureka不支持永久实例)
spring.cloud.nacos.discovery.ephemeral=false 创建永久实例
3)Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式;而Eureka只有心跳模式;
4)Nacos支持服务列表变更的消息主动通知模式,服务列表更新更及时,减少服务调用失败的机率;而Eureka采用被动定时服务列表拉取更新;

9、请问什么微服务架构?

微服务架构是一种特殊的分布式架构

1)职责独立。尽量每个业务模块拆分成一个服务,每个服务的粒度尽可能小。
2)协议独立。不同于SOA架构的RPC协议,微服务架构多采用Http协议,能做到语言独立,平台独立。
3)数据库独立。每个微服务独立有一个数据库(MySQL),实现数据独立,数据隔离。
4)部署独立。 每个微服务可以独立部署并测试,使用,交付。

10、Feign接口调用超时怎么办?(默认值1秒)

1)加大负载均衡超时时间
ribbon:
ReadTimeout: 4000
ConnectTimeout: 2000

2)给Feign加入熔断器,降级处理(整合Sentinel)

11、如何避免定时任务的重复调度?

利用分布式任务调度技术,如XXL-Job
XXL-Job创建任务时可以设置任务调度规则,规则可以设置为轮询策略或随机或分片广播

12、Spring如何实现异步调用?什么情况会导致异步调用失效?

有了解。在启动类上开启异步线程调用@EnableAsync,在需要异步调用的业务方法添加@Async

以下情况会导致@Async失效:
1)该方法非pubic,会失效
2)该方法被当前类的其他方法调用,也会失效。
3)该方法所在类不被Spring管理

6、SpringBoot专题

1、请问SpringBoot核心注解有哪些?

关键点:根据SpringBoot自动装配的思路来答

@SpringBootApplication: SpringBoot启动类入口标记注解
@EnableAutoConfiguration: 开启自动装配
@AutoConfigurationPackage: 自动导入启动器依赖包
@ConditionalOnClass: 让@Configuration在有条件的情况下生效
@ComponentScan: 设置SpringBoot环境扫描包的路径

2、SpringBoot的自动装配原理?(必问)

1)在启动类启动时加载@SpringBootApplication注解
2)在@SpringBootApplication注解里面包含三个注解:@ComponentScan,@Configuration,@EnableAutoConfiguration
3)@Configuration表明启动类是一个配置类
4)@ComponentScan自动扫描启动类所在目录及子目录在Spring组件,让其实例化
5)@EnableAutoConfiguration注解里面包含AutoConfigurationImportSelector配置类
6)在AutoConfigurationImportSelecto配置类中会读取springboot自动配置包中的META-INF的spring.factories文件
7)该spring.factories文件包含一两百个SpringBoot写好的自动配置类
8)这些自动配置并不是默认生效的,而是根据环境中导入starter启动器依赖及自动配置类上@ConditionalOnClass注解来决定该配置类是否生效。
9)一旦自动配置类生效了,里面@Bean注解会把创建实例放入IOC容器
10)我们在项目中就可以随时使用@Autowired进行注入并使用

7、SSM专题

1、SpringMVC核心原理?执行流程?

围绕三大组件:处理器映射器(HandlerMapping),处理器适配器(HandlerAdapter),视图解析器(ViewResovler)

SpringMVC的核心流程写在DispatcherServlet中的doDispatch方法里面

1)通过处理器映射器,解析request请求,查询到对应的Handler(处理器)(对应的Controller的方法)
HandlerExecutionChain handler = mapping.getHandler(request);

2)通过处理器适配器,执行刚刚找到的Handler(处理器),执行完毕后,返回ModelAndView(执行Controller的方法)
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

3)根据ModelAndView,找到对应View视图(页面/返回Json),渲染视图(如果是页面拼接路径进行转发,如果是json字符串把方法返回值转换成json字符串并写出浏览器)
view.render(mv.getModelInternal(), request, response);

8、多线程专题

1、如何解决详情页高并发访问的问题?

场景:文章详情页,商品详情页,秒杀页面

1)Freemarker静态化技术,FastDFS/MinIO/阿里OSS存储静态页面
2)流程
首先,在后台文章发布后,立即为文章生成静态页面,这里采用Freemarker结合文章模板页面生成静态页面
然后,我们把生成的文章详情静态页存储到MinIO,这样可以提高文章访问的并发量,减少详情页查询数据库的压力。
最后,用户直接访问MinIO中的静态页面,无需访问数据库

静态化技术有什么缺点?

每次文章内容修改,需要重新生成静态页面

2、知道ThreadLocal吗?讲讲你对ThreadLocal的理解 (项目中多线程并发安全问题如何解决?)

先讲作用:在同一个项目中的同一个线程范围内共享数据(一个线程存入数据,另一个线程无法读取或修改的)
防止多线程之间并发问题

再讲使用方式:
其实ThreadLocal底层使用一种Map结构,key是存储当前线程标记,value存储我们写入的值
set(Object obj) 往当前线程存入数据,底层 map.put(‘当前线程唯一标记’,obj);
Object get(): 从当前线程取出之前存入的数据,底层Object map.get(‘当前线程唯一标记’)
remove(): 移除当前线程存入的数据,底层 map.remove(‘当前线程唯一标记’)

最后讲注意事项:(ThreadLocal可能存在内存泄漏的问题(可能存在并发数据问题),怎么解决?)
在使用完TheadLocal的数据后,建议手动移除线程数据,防止内存泄漏和防止并发数据问题。

3、如何等到所有子线程执行完毕再往下执行主线程业务?(如何判断所有子线程都执行完毕主线程才继续执行?)

利用CountDownLatch的计数器实现(JUC包)
创建并执行线程,在子线程run方法中,调用countDown()方法进行计数+1
创建线程完毕完毕后,在主线程方法调用await()方法,该方法会等待所有子线程完毕计数器减为0,主线程才会唤醒继续往下执行。

4、Runnable 和 Callable 的 区别?

=相同点==

1)两者都是接口
2)两者都可以用来编写多线程代码
3)两者都可以调用Thread.start()来启动线程

不同点==
1)最大的区别,Runnable没有返回值,而实现Callable接口的任务线程能返回执行结果
2)Callable接口实现类中的run方法允许异常向上抛出,可以在内部处理,try catch,但是Runnable接口实现类中run方法的异常必须在内部处理,不能抛出
3)Runnable可以作为Thread构造器的参数,通过开启新的线程池来执行,也可以通过线程池来执行;而Callable只能通过线程池来执行。

5、synchronized 和 Lock 的区别?

1)语法不同:
synchronized 是Java的关键字或修饰符,在jvm层面上,修饰方法或代码块。
Lock不是修饰符,是一个接口(加锁的工具类,该类提供很多方法加锁、释放锁等)tryLock() unLock()
2)释放锁不同():
synchronized 以获取锁的线程执行完同步代码,释放锁,且线程执行发生异常,jvm会自动让线程释放锁(不管成功还是失败,都会自动释放锁)
Lock必须手动在finally中释放锁(必须手动释放锁)
3)死锁情况不同(
):
synchronized 在发生异常时候会自动释放占有的锁,因此不会出现死锁
Lock发生异常时候,不会主动释放占有的锁,必须手动unlock来释放锁,可能引起死锁的发生
4)锁判断不同:
synchronized 无法判断当前线程的上锁状态
Lock可以判断当前线程的上锁状态 tryLock unLock isLock
5)锁类型不同:
synchronized是可重入 不可判断 非公平
Lock:是可重入 可判断 可公平

公平性(线程等待时间长,优先获取锁)

6、什么是死锁?怎么防止死锁?

死锁是指多个线程因竞争共享资源而造成的一种互相等待的僵局。

死锁的四个必要条件:

1)互斥:一次只有一个进程可以使用一个资源。其他进程不能访问已分配给其他进程的资源。
2)占有且等待:当一个进程在等待分配得到其他资源时,其继续占有已分配得到的资源。
3)非抢占:不能强行抢占进程中已占有的资源。
4)循环等待:存在一个封闭的进程链,使得每个资源至少占有此链中下一个进程所需要的一个资源。

如何预防死锁?
1)加锁顺序(线程按顺序加锁)
2)加锁时限 (线程请求所加上期限,超时就放弃,同时释放自己占有的锁) 死锁检测
redis作为锁+过期时间(50s) Reddison

5、synchronized 和 volatile 的区别?

1)volatile只能变量修饰符,而synchronized则可以修改代码块或方法。
2)volatile不需要加锁,比synchronized更轻量级,不会阻塞线程;而synchronized加锁,会导致线程阻塞(互斥性)
3)synchronized既能够保证可见性,又能保证原子性,而volatile只能保证可见性,无法保证原子性。
4)synchronized会执行编译优化(对字节码重新排序),编译优化有可能导致运行过程中异常。而volatile禁止字节码重新排序,不会引发编译优化导致的异常。

原子性:一个操作不能被打断,要么全部执行完毕,要么不执行
可见性:一个线程对共享变量做了修改之后,其他的线程立即能够看到(感知到)该变量这种修改(变化)。

6、JDK的四种线程池创建线程的方式?实际开发中用哪个?

ExecutorService接口,JDK线程池接口!!!

1)固定线程数的线程池(newFixedThreadPool)
ExecutorService es = Executors.newFixedThreadPool(5);

这种线程池里面的线程被设计成存放固定数量的线程,具体线程数可以考虑为CPU核数*N(N一般为2),这种线程池适合用在稳定且固定的并发场景。

2)缓存的线程池(newCachedThreadPool)
ExecutorService es = Executors.newCachedThreadPool();

这是一个可以无限扩大的线程池。
适合处理执行时间比较小的任务
线程空闲时间超过60s就会被杀死,所以长时间处于空闲状态的时候,这种线程池几乎不占用资源
使用该线程池是,一定要注意控制并发的任务数,否则创建大量的线程可能导致严重的性能问题

3)单个线程的线程池(newSingleThreadExecutor)
ExecutorService es = Executors.newSingleThreadExecutor();

该线程池可以保证所有任务按照指定顺序执行,所以这个比较适合那些需要按序执行任务的场景

4)固定个数的线程池(newScheduledThreadPool)(延迟执行线程)
Executors.newScheduledThreadPool(5);

但实际开发中,我们比较少用上面的线程池实现类创建线程池,因为比较不好控制线程数量,会导致内存溢出OOM。
建议是ThreadPoolExecutor创建线程池,并且指定7个线程池参数。

9、分布式事务专题

1、事务的特征有哪些?分别是什么意思?

A 原子性 在一个事务的所有操作,要么全部成功,要么全部失败
C 一致性 事务执行的前后,数据是保持一致性,例如转账例子
I 隔离性 多个并发的事务应该要相互隔离
如果隔离行不好,则产生
脏读 一个事务读取到另一个事务未提交的数据
不可重复读 一个事务读到到另一个事务的已经提交更新数据
幻读 一个事务多次读取结果(新增的已提交的数据)不一致

 为了防止这些现象,修改数据库的隔离级别
                                                               脏读             不可重复读          幻读
      read uncommited(读未提交)         有                    有                       有
      read commmited(读已提交)          无                    有                       有     (oracle默认隔离级别)
      repeatable read(可重复读)             无                   无                        有    (mysql默认隔离级别)
       Serializable(串行化)                       无                   无                      无

D 持久性 事务一旦提交,则永久保存,即使故障也不丢失

2、你了解过CAP定理和BASE理论吗?

CAP定理,C是值一致性,A指可用性,P指容错性。
CAP定理,在说P必然存在的,C和A只能选择一个特性。在CAP定理,只存在CP或AP。

BASE理论,是对CAP一种补充:
BA指基本可用,S代表软状态,E代表最终一致性
CAP定理说如果选择了一致性,就放弃了可用性,但BASE理论说选择了一致性,只是损失了部分可用,意味处于基本可用。
CAP定理说如果选择了可用性,就放弃了一致性,但BASE理论说选择了可用行,只是存在临时的不一致状态,这种临时的不一致性称为软状态,这种软状态过后最终会达成一致性。

3、项目中有用到分布式事务么?什么技术?Seata有哪些模式?你们用的哪个模式?

有用到。用到阿里巴巴的Seata,Seata有四种模式,分别为XA模式,AT模式,TCC模式,SAGA模式。
我的项目中使用到AT模式/TCC模式。

4、请问Seata的AT模式是AP还是CP?那大概解释一下Seata的AT模式的原理

AT模式是一种AP模式(强可用,弱一致性)。

Seata的AT模式的执行流程大概就这样:
Seata架构中存在三大组件,TC(TC是事务协调者),TM(事务管理器)和RM(资源管理器)。
首先,由TM向TC发出开始全局事务的请求,TC在全局事务表中记录数据。
接着,由TM通知各个的RM调度各自的分支事务,这时分支事务开始执行啦。分支事务先向TC进行注册分支事务,开始执行SQL语句并提交,在SQL执行的前后,AT模式会把更新记录的前后数据保存到undo_log日志表中作为数据快照,再上报事务执行结果给TC。
最后,TC收集到所有分支事务的执行状态,进行分析,决定是否提交还是回滚,如果提交,则TC向所有RM发出删除undo_log日志记录的请求。如果回滚,则TC向所有RM发出读取undo_log数据快照做数据恢复的请求。

在AT的执行过程中,我了解到会有脏读的情况存在,Seata考虑到了,利用全局事务锁表,在每个分支事务提交之前,判断是否能获取全局事务锁,决定是否提交,这样就控制脏写。

5、请大概解析一下Seata的TCC模式的原理?

Seata的AT模式的执行流程大概就这样:
Seata架构中存在三大组件,TC(TC是事务协调者),TM(事务管理器)和RM(资源管理器)。
其实TCC模式,就是我们在一个业务编写三个方法,成为try方法,confirm方法,cancel方法。

首先,由TM向TC发出开始全局事务的请求,TC在全局事务表中记录数据。
接着,由TM通知各个的RM调度各自的分支事务,这时分支事务开始执行啦。分支事务先执行try方法,进行资源预留(如冻结金额),然后向TC提交事务状态。
最后,TC收集到所有分支事务的执行状态,进行分析,决定是否提交还是回滚,如果提交,则调用confirm方法(把预留资源清除),如果回滚,则调用cancel方法(利用预留资源恢复原有的数据)。

6、请说说哪些情况会导致Spring事务失效?

1)注解@Transactional配置的方法非public权限修饰
2)注解@Transactional所在类非Spring容器管理的bean
3)注解@Transactional所在类中,注解修饰的方法被本类的其他内部方法调用(建议说)
4)业务代码抛出异常类型非RuntimeException,事务失效 FileNotFoundException()
5)业务代码中存在异常时,使用try…catch…语句块捕获,而catch语句块没有throw new RuntimeExecption异常
6)注解@Transactional中Propagation属性值设置错误即Propagation.NOT_SUPPORTED(很少见)
事务传播行为 共7个,只要知道常用的这4个即可

   @Transactional(propagation = Propagation.REQUIRED)  默认值,当前方法必须处在事务中。前面的业务方法有事务,同共享前面的事务;如果前面没有事务,则开启新事务
   @Transactional(propagation = Propagation.SUPPORTS)   前面业务方法有事务,同共享前面的事务,如果前面没有事务,则不开事务,通常在查询业务中
  @Transactional(propagation = Propagation.REQUIRES_NEW)  不管前面业务是否有事务,都要独立创建新事务。
  @Transactional(propagation = Propagation.NOT_SUPPORTED)  不支持事务

7)mysql关系型数据库,且存储引擎是MyISAM而非InnoDB,则事务会不起作用(很少见)MyISAM不支持事务

参考文章:https://blog.csdn.net/xuan_lu/article/details/107797505

5、MySQL一张表中有1千万条数据,现在查询比较慢,有什么优化思路?(必问)
或:请问MySQL优化的思路?

1)SQL语句优化,如:需要什么查询什么避免用* , 尽量比较时用于>= <= 尽可能用exits not exits,少用in not in like的百分号不要放左边
2)需要考虑对查询频繁的字段建立索引或联合(复合)索引。
但是要避免写SQL语句时索引失效的情况,如何得知SQL是否执行索引?使用explain查询执行计划
常见的可能导致索引失效的情况:
使用or,in like查询%放在左边
如在使用联合索引,遵守最左前缀原则
最左前缀原则是这样: (name,age,sex)
where name = jack ok
where name = jack and age>=10 ok
where age >10 and sex = “男” 不ok

3)如果说单表数据太多(过千万),可以采用水平分库分表(采用ShardingJdbc技术)
4)如果业务数据用于复杂的查询场景,把MySQL数据导入到Elasticsearch中,进行全文检索,从而效率更高。

10、Elasticsearch专题

1,Elasticsearch比MySQL的优势在哪里?(为什么要使用Elasticsearch?)

1)MySQL的海量数据时,搜索效率比较低,而Elasticsearch采用倒排索引法检测数据,从而效率更高。
2)MySQL的搜索功能比较弱,只有like这种模糊搜索,而Elasticsearch拥有大量复杂搜索的API,更加适合数据搜索场景

2、请说说Elasticsearch倒排索引原理?

1)首先,Elasticsearch将文档数据进行索引构建。将文档数据需要分词的字段内容使用分词器进行分词,并记录每个词条和原文档的出现位置和出现频率等信息,构建出文档的索引库。
2)然后,用户搜索时,可以对关键词进行分词,使用分词后词条来匹配索引库,在索引库匹配到记录后,通过文档位置频率信息,反查具体的文档数据。

3、请说说什么是分词器?ES有哪些常用的分词器?

分词器是Elasticsearch用于对内容进行分词的工具(程序),Elasticsearch内置许多分词器,默认使用Standard标准分词器,而标准分词器对中文支持并不好友(因为它对中文进行单字分词),
所以在开发中进行中文分词时使用第三方的ik分词器,ik分词器内置有ik_smart和ik_max_word算法,ik_smart是最小分词器法,ik_max_word是最细分词法。

4、你们项目的日志怎么管理的?(你们项目在线上出问题,怎么最快发现问题的?)

通常我之前待的公司上线的项目,都会由运维那边搭建日志分析平台,我了解到上家搭建的是ELK平台(Elasticsearch+Logstash+Kibana),这个平台会自动采集项目运行的日志,并且进行分析,
运维人员只要到Kibana查看日志即可,当然ELK平台也设计一个告警规则,当系统出现异常时,自动给运维实时通知(短信+电话)

5、MySQL、Redis、MongoDB、Elasticsearch各自的优势?

MySQL:是关系型数据库,磁盘。有复杂表关系(一对一,一对多,多对多),并且有完善事务机制(ACID)。 用户,订单,商品
Redis: 非关系数据库,内存。Redis建议只存储热点(用户查询频率极高)的数据,且数据量相对小的数据。秒杀的库存量 手机验证码
MongoDB: 非关系数据库,磁盘。MongoDB适合相对高频擦写(增删改)的海量数据。 评论
Elasticsearch: 非关系数据库,磁盘。Elasticsearch适合海量数据的复杂检索。 商品搜索

效率: Redis > MongoDB /Elasticsearch:> MySQL

6、请问Elasticsearch中match和term检索的区别?

match:全文检索 分词 用在text类型
1)先对搜索内容进行分词,得到词条
2)使用词条匹配倒排索引库,得到文档ID
3)使用文档ID,查询具体的文档记录进行聚合(并集或交集)

term:精确匹配 不分词 用keyword,boolean,日期,数值
1)使用搜索内容全文匹配倒排索引库,得到文档ID
2)使用文档ID,查询具体的文档记录进行聚合(并集或交集)

7、请问Elasticsearch中如何实现多条件检索?must和filter的区别是什么?

使用布尔查询进行多条件检索

must的条件会参与算法过程,影响结果的排序
filter的条件不参与算法过程,不影响结果的排序

8、请问Elasticsearch如何实现搜索附近的酒店? (假如简历上写了这个功能)

1)在hotel表中记录酒店的经度和维度值(后端干的)
2)前端把用户的坐标发送至后端(前端干的活)
3)后端根据用户坐标值,利用Elasticsearch的geo_distance做升序排序,里面参数大概是地理坐标,升降序规则(DESC/ASC),距离单位

“sort”: [
{
“_geo_distance”: {
“location”: “22.57,113.88”,
“order”: “asc”,
“unit”: “km”
}
}
]

9、请问在Elasticsearch如何提升指定搜索结果的权重?(请问如何实现类似百度搜索结果的竞价排名的?)

1)首先,Elasticsearch默认情况下使用BM25算法(5.1版本以前,使用TF-IDF算法)计算_score得到,按照得到倒序
TF-IDF算法:TF(词频)* IDF(逆文档频率)
TF:词条在文档中出现的频率
IDF:计算词条在所有文档中的权限(出现越多文档,权限越低,反之则越高)
BM25:是 TF-IDF算法是升级版,单个词条的算分有一个上限,不至于过高,让曲线更加平滑

2)如果希望改变指定结果的权限,使用 function_score 函数提升权限
function_score 大体三部分条件:
第一部分:原始查询条件
第二部分:过滤条件和权重分值,过滤条件就是哪部分文档需要提分
第三部分:加权模式,对权限分值进行sum,avg,相乘等规则。

10、如何实现酒店拼音搜索?(如果简历写了该功能)

首先用到ELs 查询,因为Els分不了中文和拼音,所以要加装两个插件IK和Py,又因为IK跟py是两个不同的插件
所以要设计一个新的分词器,先ik分词中文,然后再拼音分词。搜索时,避免中文也会转换拼音要search_analyzer来指定自己的新的分词器

1)在Elasticsearch安装拼音分词器的插件
2)因为拼音分词器只是把词的每个字进行转换拼音,无法实现对一个词的拼音转换,不太满足项目的需求
3)这时我们结合ik中文分词器设计自定义分词器
4)我们的自定分词器,配置成先使用ik分词器对中文进行分词,然后再将这些词通过拼音分词器转换为拼音的词条
5)但是为了在搜索时,避免中文也会转换拼音,我们在搜索时还是使用ik分词器去分词,依赖search_analyzer来指定

“analyzer”: “my_analyzer”,
“search_analyzer”: “ik_max_word”

11、如何实现搜索关键词自动补全(如果简历写了该功能)

1)在酒店索引库添加一个completion字段,该字段内容是数组,在里面填充需要补充的数据
2)在用户搜索时,每次输入关键词时,使用suggest搜索进行suggestion搜索,把结果列表返回前端

GET /test/_search
{
“suggest”:{
“title_suggest”:{
“text”:”s”,
“completion”:{
“field”:”title”,
“skip_duplicates”:true,
“size”:10
}
}
}

12、请说说Elasticsearch与MySQL数据如何同步?

1)使用MQ

1.1 在生产者方法在新增、修改、删除数据的方法,发送数据ID给RabbitMQ
1.2 在消费方编写监听类,分别写了监听新增修改方,和监听删除方法的处理业务,根据数据ID查询数据,新增、修改,删除ES的数据

2)使用Canal

13、请问Elasticsearch的脑裂问题如何产生?如何解决?

什么是脑裂?
一个Elasticsearch集群环境中出现多个master节点情况,成为脑裂

如何产生?
master和slave节点间网络延迟或阻塞
master节点负载过重
Elasticsearch的JVM内存不足

导致master节点临时丢失,导致slave重新选举master节点

如何解决:
1)修改Elasticsearch节点通信超时时间,默认3秒,改大一些
2)master节点的职责分离,master不作为数据存储节点,nodes.data=false
3)扩展Elasticsearch的JVM内存,默认1G,改大一些,物理机器内存一半左右
4)Elasticsearch的选举票数,改为备选节点数/2 + 1 , ES7默认改好了,ES6或ES5修改一下这个值

11、Java基础

1、深拷贝和浅拷贝的区别?怎么实现深拷贝?

A a = new A(xxxx);
a.clone();

class A{
String name; ox1
int age;
B b; ox4
}

class A1{
String name; ox2
int age;
B b; ox5
}

浅拷贝(默认情况下):当如果要拷贝一个A对象,而A对象中又有一个B对象,那么如果对A拷贝的时候,重新拷贝出来一个A1对象并且重新分配内存地址,但是对于A中的B对象,仅仅只是把A1中拷贝出来的B1对象的引用指向原来的B对象而已,并没有把拷贝的B1对象也重新进行分配一个新的内存地址。

深拷贝:而深拷贝就是在第1的基础上,不仅重新给A1对象分配了新的内存地址,而且还给A1中的B1也重新进行分配了新的内存地址,而不只是仅仅把原本的B的引用给B1。

如果想要深拷贝一个对象,这个对象必须要实现 Cloneable 接口,实现 重写clone() 方法,并且在 clone 方法内部,把该对象引用的其他对象也要 clone 一份,这就要求这个被引用的对象必须也要实现Cloneable 接口并且实现 clone 方法

2、什么是序列化和反序列化?什么时候需要序列化或反序列化?序列化的底层怎么实现的?

什么是序列化和反序列化?
1)序列化:Java对象变为二进制数据的过程
2)反序列化:二进制的数据变为Java对象的过程

什么时候需要序列化或反序列化?
1)把JavaBean对象读写磁盘
2)让JavaBean通过网络传输 (RPC远程调用就是对象传输,就需要序列化 )

怎么对JavaBean序列化或反序列化:
让JavaBean实现Serializable接口

Java实现序列化的底层代码:
1)ObjectOutputStream: 对象序列化工具 writeObject(Object)
2)ObjectInputStream: 对象反序列化工具 Object readObject()

3、请说说网络七层模型?RPC协议和HTTP协议什么区别?

1)物理层:该层提供网络传输的物理媒体,为网络之间的传输提供最基础的支持。重要的设备有中继器和集线器
2)数据链路层:该层将源网络层的数据可靠的传输到目的临近的网络层。在数据链路层中数据块叫做帧,帧是数据链路层的单位
3)网络层:该层作用于两个端系统之间的数据透明传输,单位为数据包。具体功能包括ip寻址和路由选择,连接的建立,维持和释放等。主要协议:IP协议
4)传输层:负责将上层数据进行分段提供端到端的可靠或不可靠传输。主要协议:TCP协议,UDP协议。(
5)会话层:该层管理主机之间的会话进程,负责建立,维持,终止进程之间的会话。
6)表示层:表示层的数据转换包括数据的加密,压缩,格式转换等。
7)应用层:为网络应用程序提供访问网络服务的接口。 主要协议:HTTP协议(

RPC通信主要建立在传输层的TCP协议之上(RPC远程调用),传输效率比较高,耦合度越高(绑定开发语言)
HTTP通讯主要建立在应用层的HTTP协议之上(SpringCloud的Feign远程调用),传输效率稍低,语言通用性

4、请说说http和https的区别

HTTP:超文本传输协议,简单来说就是一种发布和接收 HTML 页面的方法,被用于在 Web 浏览器和网站服务器之间传递信息。HTTP 协议以明文方式发送内容,不提供任何方式的数据加密,因此,HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。

HTTPS:超文本传输安全协议,是一种透过计算机网络进行安全通信的传输协议。HTTPS 经由 HTTP 进行通信,但利用 SSL/TLS 来加密数据包。HTTPS 开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。

网站从HTTP改造HTTPS,到第三方厂商申请SSL证书服务。

5、HashMap的扩容因子?ArrayList的初始容量和扩容机制?(必问)

HashMap初始容量为16,扩容因子为0.75,扩容2倍。
ArrayList默认容量为10。超过容量上限则扩容,扩容量为原来的1.5倍

12、调优专题

1、请说说JVM调优?( 必问 )

我在开发中一般很少需要进行JVM调优,但我了解过一点JVM调优的参数:

OOM(Out of Memeory 内存溢出)

1)设定堆内存大小(比较常用的)
-Xmx:堆内存最大限制。

2)设定新生代大小。 新生代不宜太小,否则会有大量对象涌入老年代
-XX:NewSize:新生代大小
-XX:NewRatio 新生代和老生代占比
-XX:SurvivorRatio:伊甸园空间和幸存者空间的占比

3)设定垃圾回收器算法
年轻代用 -XX:+UseParNewGC
年老代用-XX:+UseConcMarkSweepGC

13、数据结构专题

演示网址:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

1、二叉查找树(BST)、平衡二叉树(AVL)、红黑树(RBT)的区别?

二叉查找树->平衡二叉树->红黑树

1)二叉查找树(BST):
特点:
左子树的节点值比父亲节点小,而右子树的节点值比父亲节点大
缺点:
二叉查找树因可能退化成链表,故其性能最差(树高很大)

2)平衡二叉树(AVL)特点:(是一种特殊的二叉查找树)
特点:
每个节点的左子树和右子树的高度差至多等于1,如果层高大于1,则进行旋转(左旋(逆时针),右旋(顺势针))
缺点:
平衡二叉树如果在那种插入、删除很频繁的场景中,平衡二叉树需要频繁着进行调整(旋转),这会使平衡树的性能大打折扣

3)红黑树(RBT)特点:(是一种特殊的平衡二叉树)
特点:
根节点是黑色的
每个叶子节点都是黑色的空节点(黑叶子节点不放数据)
任何相邻的节点都不能同时为红色
每个节点,从根节点到达其可达的叶子节点是所有路径,都包含相同数目的黑色节点

优点:
与平衡二叉树不同,红黑树在插入、删除等操作,不会像平衡树那样,频繁着破坏红黑树的规则,所以不需要频繁着调整

一句话总结:平衡二叉树是为了解决二叉查找树退化为链表的情况,而红黑树是为了解决平衡二叉树在插入、删除等操作需要频繁调整树结构的情况。

HashMap底层结构,数组+链表+红黑树

参考文章:https://baijiahao.baidu.com/s?id=1636557496125304849&wfr=spider&for=pc

14、spring基础专题

1、Spring Bean的生命周期?(必会)

1)调用Bean的构建函数(创建对象,底层反射创建对象)(控制反转 IOC)
2)给Bean的成员变量赋值(依赖注入 DI)
3)执行一些Aware接口,这些接口是可选的,例如 BeanNameWare BeanFactoryAware ApplicationContxtAware
4)调用InitializingBean接口的afterProertiesSet方法(可选)
5)调用Bean的init方法(前提是声明该方法)(可选)
@PostConstruct注解声明init方法
6)调用Bean的destroy方法(前提是声明该方法)(可选)(通常不会执行,IOC容器主动销毁 applicationContext.close())
@PreDestroy注解声明destroy方法

2、请说说Spring是如何解决循环依赖问题的?

属性注入的循环依赖:

@Component
public class TestService1{
@Autowired
private TestSerivice2 service2;
}

@Component
public class TestService2{
@Autowired
private TestSerivice1 service1;
}

spring内部有三级缓存(三个Map结构):
1)singletonObjects 一级缓存,用于存放完全初始化好的 bean(最终要被用户使用)
2)earlySingletonObjects 二级缓存,存放原始的 bean 对象(尚未填充属性),避免Bean实例化完成但未初始。
3)singletonFactories 三级缓存,存放 bean 工厂对象(ObjectFactory),用于生成AOP代理对象(@Transactional或@Async)。

用户从SpringIOC容器获取一个Bean的底层,会先从一级缓存获取Bean;一级缓存拿不到,从二级缓存获取;二级缓存获取不到从三级缓存获取。