2022年7月面试总结
- 1. 2022年7-8月面试总结
- 1.1. 面试题整理
- 1.1.1. 线程的关闭有几种方法
- 1.1.2. 如何控制程序请求线程数量
- 1.1.3. Synchronized与Lock的区别
- 1.1.4. ReentrantLock 在什么情况下使用
- 1.1.5. jdk中的并发包下面用过哪些类
- 1.1.6. redis支持哪些数据类型
- 1.1.7. 如何保证redis中的数据与数据库中一致
- 1.1.8. redis如何保证高可用
- 1.1.9. redis两种持久化模式对比
- 1.1.10. redis如何实现延迟队列
- 1.1.11. mysql索引的数据结构有哪些,为什么有些字段加了索引却比没加索引查询要慢
- 1.1.12. mysql的数据结构,叶子结点存放的是什么
- 1.1.13. B-Tree数据结构中由哪些部分组成
- 1.1.14. mysql数据库达到2千万条数据时,会有性能瓶颈,请问有什么依据
- 1.1.15. mysql数据库使用自增ID做主键,有什么优势
- 1.1.16. mysql数据库中,用limit做分页查询有什么缺点
- 1.1.17. jvm有哪几个装载器
- 1.1.18. springcloud有使用哪些组件
- 1.1.19. 微服务监控用的什么
- 1.1.20. rpc和http restfull优缺点
- 1.1.21. 对方系统与我方系统采用接口协议不一样,如何设计让对方系统调用我方系统兼容
- 1.1.22. 七层网络分层与TCP/IP分层对应图
- 1.1.23. TCP协议和UDP协议,分别处于七层网络结构里的哪一层
- 1.1.24. rabbitmq消息类型
- 1.1.25. rabbitmq如何保证消息不丢失
- 1.1.26. 为什么选rabbitmq不选kafka
- 1.1.27. 为什么kafka是亿级消息中间件,性能比rabbitMQ要好
- 1.1.28. http各状态码意义
- 1.1.29. http不同协议版本对比
- 1.1.30. restful协议与标准有哪些
- 1.1.31. char类型能存中文吗
- 1.1.32. 系统开发与设计中,需要遵循哪些规范
- 1.1.33. spring启动时,如何加载一些自定义类(如配置文件, bean)
- 1.1.34. spring三级缓存是用来解决什么问题的
- 1.1.35. springboot中,如何开发start依赖组件
- 1.1.36. springcloud中,是如何做到注册中心的切换的(eureka、consul、nacos等)
- 1.1.37. springcloud-gateway和zuul网关有什么区别
- 1.1.38. 架构的本质是什么
- 1.1. 面试题整理
2022年7-8月面试总结
2022年7月,是个不平凡的一个月,因为从年初到现在,上海有无数的企业被疫情拖垮倒闭,从而也导致大量的人找不到工作,而7月,还有不少企业还在继续裁员中。7月中旬离职后,一周只有两三家面试,而面试通过后,还有漫长的等待期(企业筛选候选人),这个是之前不曾有的体验,很酸爽……….
面试题整理
- 线程的关闭有几种方法
- 如何控制程序请求线程数量
- 在程序中如何控制线程信号量
- Synchronized与Lock的区别
- ReentrantLock 在什么情况下使用?如何使用?
- 自定义线程池具体实现
- jdk中的AQS包下面用过哪个类
- Fauture类如何实现异步线程的
- redis支持哪些数据类型
- 如何保证redis中的数据与数据库中一致
- redis如何保证高可用,你们是用的哪一种
- redis两种持久化模式对比
- redis如何实现延迟队列
- redis是单线程模型,为什么还是那么快
- redis的hash类型如何做扩容的
- redis有哪些内存淘汰机制,分别介绍一下
- mysql索引的数据结构有哪些,为什么有些字段加了索引却比没加索引查询要慢
- mysql的数据结构,叶子结点存放的是什么
- B-Tree数据结构中由哪些部分组成
- mysql数据库达到2千万条数据时,会有性能瓶颈,请问有什么依据
- mysql数据库使用自增ID做主键,有什么优势
- 数据库第一、二、三范式
- mysq数据库设计有哪些规范需要遵守
- mysql默认的隔离级别是什么
- mysql的mvcc结构是什么样的
- mysql数据库中,用limit做分页查询有什么缺点
- 国产数据库?
- 时序数据库?
- jvm有哪几个装载器
- springcloud有使用哪些组件?监控用的什么?
- rpc和http restfull优缺点
- 对方系统与我方系统采用接口协议不一样,如何设计让对方系统调用我方系统兼容
- rabbitmq消息类型
- rabbitmq如何保证消息不丢失
- 你们公司为啥选rabbitmq不选kafka, 它们俩有啥区别
- kafka会丢消息吗?如何防止丢消息
- http各状态码意义
- restful协议与标准有哪些
- char类型能存中文吗
- TCP协议和UDP协议,分别处于七层网络结构里的哪一层
- 系统开发与设计中,需要遵循哪些规范
- spring启动时,如何加载一些自定义组件
- spring三级缓存是用来解决什么问题的
- springboot中,如何开发start依赖组件
- springcloud中,是如何做到注册中心的切换的(eureka、consul、nacos)
- 订单、库存等数据如何在系统中保持数据一致性
- 架构的本质是什么
- springcloud-gateway和zuul网关有什么区别
https://cloud.tencent.com/developer/article/1770201
线程的关闭有几种方法
- 使用取消标志位正常运行完线程并退出(可能因阻塞的程序无法正确执行到标志位从而导致循环的线程程序永远无法关闭)
- 调用Thread类的interrupt方法,发出中断线程执行信号(更多的时候是抛出InterruptedException异常作为中断响应)
- 定时运行线程,超时则主动调用interrupt方法中断线程执行
- Future 类的cancel方法来中断线程执行
如何控制程序请求线程数量
信号量(Semaphore)是Java多线程兵法中的一种JDK内置同步器,通过它可以实现多线程对公共资源的并发访问控制。一个线程在进入公共资源时需要先获取一个许可,如果获取不到许可则要等待其它线程释放许可,每个线程在离开公共资源时都会释放许可。
Semaphore类的实现是基于AQS同步器来实现的,不管是公平模式还是非公平模式都是基于AQS的共享模式,只是在获取许可的操作逻辑有差异。Semaphore的默认模式为非公平模式,我们先看非公平模式的实现。
AQS数据结构
AbstractQueuedSynchronizer(AQS)主要就是维护了一个state属性、一个FIFO队列和线程的阻塞与解除阻塞操作。
FIFO队列结构
- Node prev:前驱节点,指向前一个节点
- Node next:后续节点,指向后一个节点
- Node nextWaiter:用于存储condition队列的后续节点
- Thread thread:入队列时的当前线程
- int waitStatus:有五种状态:
- SIGNAL,值为-1,表示当前节点的后续节点中的线程通过park被阻塞了,当前节点在释放或取消时要通过unpark解除它的阻塞。
- CANCELLED,值为1,表示当前节点的线程因为超时或中断被取消了。
- CONDITION,值为-2,表示当前节点在condition队列中。
- PROPAGATE,值为-3,共享模式的头结点可能处于此状态,表示无条件往下传播,引入此状态是为了优化锁竞争,使队列中线程有序地一个一个唤醒。
- 0,除了以上四种状态的第五种状态,一般是节点初始状态。
前驱节点prev的引入主要是为了完成超时及取消语义,前驱节点取消后只需向前找到一个未取消的前驱节点即可;后续节点的引入主要是为了优化后续节点的查找,避免每次从尾部向前查找;nextWaiter用于表示condition队列的后续节点,此时prev和next属性将不再使用,而且节点状态处于Node.CONDITION; waitStatus表示的是后续节点状态,这是因为AQS中使用CLH队列实现线程的结构管理,而CLH结构正是用前一节点某一属性表示当前节点的状态,这样更容易实现取消和超时功能。
https://www.cnblogs.com/jiading/articles/12519704.html
https://blog.csdn.net/hbtj_1216/article/details/109060367
https://cloud.tencent.com/developer/article/1770201
Synchronized与Lock的区别
名称 | 运行层次 | 释放锁 | 获取锁 | 引发死锁 | 锁状态是否可判断 | 锁类型 | 性能 | 调度 | 用法 | 底层实现 |
---|---|---|---|---|---|---|---|---|---|---|
Synchronized | 关键字,运行在jvm层面上 | 1. 以获取锁的线程执行完同步代码,释放锁 2. 线程执行发生异常,jvm会让线程释放锁 |
假设A线程获得锁,B线程等待。如果A线程阻塞,B线程会一直等待 | 发生异常时候会自动释放占有的锁,因此不会出现死锁 | 无法判断 | 可重入锁,不可判断 | 少量同步性能好,资源竞争不激烈的情况,性能优于ReetrantLock | |||
Lock | 是一个接口 | 在finally中必须手动释放锁,不然容易造成线程死锁 | 分情况而定,Lock有多个锁获取的方式,大致就是可以尝试获得锁,线程可以不用一直等待(可以通过tryLock判断有没有锁) | 发生异常时候,不会主动释放占有的锁,必须手动unlock来释放锁,可能引起死锁的发生 | 可以判断 | |||||
ReentrantLock 在什么情况下使用
多线程访问共享数据资源时使用,与semaphore的实现类似,都包含了sync类,都是基于AQS的队列同步锁机制。
ReentrantLock、Semaphore、AQS类之间的关系:
pic-id: 1621
ReentrantLock,即重入锁。按处理方式来划分,它属于排它锁。
Semaphore 它属于共享锁。因为它请求许可时,调用的是:
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
pic-id: 1620
ReentantLock如何使用
jdk中的并发包下面用过哪些类
- 抽象队列同步器 AQS
- 控制并发线程数 Semaphore
- 排它同步锁ReentantLock
- 等待多线程完成CountDownLatch
- 同步屏障CyclicBarrier
- 线程间交换数据Exchanger
redis支持哪些数据类型
类型 | 简介 | 特性 | 场景 |
---|---|---|---|
String(字符串) | 二进制安全 | 可以包含任何数据,比.png图片或者序列化的对象,一个键最大能存储512M | — |
Hash(字典) | 键值对集合,即编程语言中的Map类型,标准的hashtable结构 | 适合存储对象,并且可以像数据库中update一个属性一样只修改某一项属性值(Memcached中需要取出整个字符串反序列化成对象修改完再序列化存回去) | 存储、读取、修改用户属性 |
List(列表) | 链表(双向链表) | 增删快,提供了操作某一段元素的API | 1,最新消息排行等功能(比如朋友圈的时间线) 2,消息队列 |
Set(集合) | 哈希表实现,元素不重复 | 1、添加、删除,查找的复杂度都是O(1) 2、为集合提供了求交集、并集、差集等操作 | 1、共同好友 2、利用唯一性,统计访问网站的所有独立ip 3、好友推荐时,根据tag求交集,大于某个阈值就可以推荐 |
Sorted Set(有序集合) | 将Set中的元素增加一个权重参数score,元素按score有序排列 | 数据插入集合时,已经进行天然排序 | 1、排行榜 2、带权重的消息队列 |
Hash类型是如何扩容的
标准的表字典的实现,通过渐进式的方式进行数据扩容:
- 一次性将
ht[0]
的数据复制到ht[1]
中,redis会有一段时间暂停服务,影响较大 - 当
ht[0]
中的table大小超过了4个,则触发rehash - 为
ht[1]
分配空间,让字典同时持有ht[0]
和ht[1]
两个哈希表 - 将
rehashindex
的值设置为0
,表示rehash工作正式开始 - 在rehash期间,每次对字典执行增删改查操作是,程序除了执行指定的操作以外,还会顺带将
ht[0]
哈希表在rehashindex
索引上的所有键值对rehash到ht[1]
,当rehash工作完成以后,rehashindex
的值+1
- 随着字典操作的不断执行,最终会在某一时间段上
ht[0]
的所有键值对都会被rehash到ht[1]
,这时将rehashindex
的值设置为-1
,表示rehash操作结束
数据结构:
zset类型中的sorted方法是如何实现的
压缩列表和跳越列表
如何保证redis中的数据与数据库中一致
https://blog.csdn.net/weixin_44129618/article/details/122358133
想要保证缓存与数据库的双写一致,一共有4种方式,即4种同步策略:
- 先更新缓存,再更新数据库;
- 先更新数据库,再更新缓存;
- 先删除缓存,再更新数据库;
- 先更新数据库,再删除缓存。
redis如何保证高可用
Redis 高可用的手段主要有以下四种:
(1)数据持久化
(2)主从同步(主从复制)
(3)Redis 哨兵模式(Sentinel)
(4)Redis 集群(Cluster)
你们是用的哪一种
Redis 哨兵模式(Sentinel)
redis两种持久化模式对比
- RDB
Redis DataBase,快照恢复,是将某一个时刻的内存数据,以二进制的方式写入磁盘。RDB 默认的保存文件为 dump.rdb,优点是以二进制存储的,因此占用的空间更小、数据存储更紧凑,并且与 AOF 相比,RDB 具备更快的重启恢复能力,但有数据丢失的风险。
- AOF
Append-Only File,只追加文件,是指将所有的操作命令,以文本的形式追加到文件中。AOF 默认的保存文件为 appendonly.aof,它的优点是存储频率更高,因此丢失数据的风险就越低,并且 AOF 并不是以二进制存储的,所以可读性更高。
缺点是占用空间大,重启之后的数据恢复速度比较慢。
- 混合模式
Redis 混合持久化的存储模式指的是 Redis 可以使用 RDB + AOF 两种格式来进行数据持久化,开始的数据以 RDB 的格式进行存储,因此只会占用少量的空间,之后的命令会以 AOF 的方式进行数据追加,这样就可以减低数据丢失的风险,同时可以提高数据恢复的速度这样就可以做到扬长避短物尽其用了,混合持久化的存储示意图如下图所示:
redis如何实现延迟队列
mysql索引的数据结构有哪些,为什么有些字段加了索引却比没加索引查询要慢
Mysql的索引用的底层数据结构是B+树
他具有这样的几个特点:
1、数据都存储在叶子节点中、非叶子节点只存储索引
2、叶子节点中包含所有的索引
3、每个小节点的范围都在大节点之间
4、叶子节点用指针相连,提高访问性能,比如条件是>或者<的查询就可以直接按指针找(Mysql中的B+树叶子节点中的指针是双向指针)
B+Tree的叶子节点就是一个页,每个页之间是双向指向的,就是双链表结构:
为什么有些字段加了索引却比没加索引查询要慢
可以是查询语句使用不正确导致。
- 检查下查询语句是否使用了join关键字,尽量不要使用join
- 可以使用了查询代替join,或者通过代码补全的方式将数据补齐
- 检查是否使用联合索引,like,in,或者其它非全文匹配关键字
mysql的数据结构,叶子结点存放的是什么
B+tree,
叶子结点存放的是数据
B-Tree数据结构中由哪些部分组成
根节点—主索引
子节点—-次索引
叶子节点 — 存储数据
mysql数据库达到2千万条数据时,会有性能瓶颈,请问有什么依据
简单来讲:
- 一页可以存储约16k数据
- 一棵高度为3的B+树最多可存储约2千万条索引数据
计算一个非叶子节点可存储多少指针:16384/14=1170
高度为3的B+树可以存放:1170 * 1170 * 16=21902400条数据
mysql数据库使用自增ID做主键,有什么优势
B+ 树为了维护索引有序性,在插入新值的时候需要做必要的维护。
如果插入的值比最大值id大,则只需要在最后记录后面插入一个新记录。
如果新插入的ID值在原先的有序中间,就相对麻烦了,需要逻辑上挪动后面的数据,空出位置。如果所在的数据页已经满了,根据 B+ 树的算法,这时候需要申请一个新的数据页,然后挪动部分数据过去。这个过程称为页分裂。页分裂不但影响性能,还影响数据页的利用率,使有些原来在一个数据页上的,因为页分裂成两个页上了
自增主键的插入数据模式,正符合了B+树递增插入的场景。
每次插入一条新记录,都是追加操作,都不涉及到挪动其他记录,也不会触发叶子节点的分裂
如果用整型做主键,则只要 4 个字节,如果是长整型(bigint)则是 8 个字节。
显然,主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小
所以,从性能和存储空间方面考量,自增ID主键往往是更合理的选择
mysql数据库中,用limit做分页查询有什么缺点
limit [m,n]
m: 偏移量
n: 取多少条数据
- 当偏移量m过大的时候,查询效率会很低。因为MySQL是先查出m+n个数据,然后抛弃掉前m个数据。
优化方案:
可以通过子查询查出目标数据集合的第一个数据所在的行,然后用 >= 操作
如:
SELECT * FROM articles WHERE id >= (SELECT id FROM articles WHERE category_id = 123 ORDER BY id LIMIT 10000, 1) LIMIT 10
jvm有哪几个装载器
- 系统类加载器
- 扩展类加载器
- 应用类加载器
springcloud有使用哪些组件
五大核心组件:
- eureka
- discover
- gateway/zuul
- config
- cloud bus
- open feign
- Ribbon
微服务监控用的什么
- Actuator + Spring Boot Admin
- Actuator(Micrometer)+ Prometheus + Grafana
rpc和http restfull优缺点
rpc
实现原理:客户端将要调用的方法,类名通过网络通讯框架,序列化与反序列化进行传输,服务端收到消息后通过解析,将要调用的类和方法通过反射调用
优点:
- rpc主要基于TCP/IP协议,工作在传输层(第四层),传输效率上天生优于应用层上的HTTP协议
- rpc可以实现跨语言调用
- 安全性更高,不暴露接口定义
不足:
- 学习成本较高,不如http易用
- rpc框架实现复杂度高,流程繁琐
- 使用灵活性不如RESTFul,被调用必须使用对应client端
http RESTFul
实现原理:http协议,应用服务器实现,如tomcat,jetty等
优点:
- 数据协议通用(json)
- 学习成本低,简单
- HTTP 相对更规范,更标准,更通用
不足:
- 每次请求建立一个连接都会进行http的三次握手,效率较低
- 工作在应用层上,属于最外层(第一层),天生性能比其它层低
- 缺少一定的安全性,暴露了资源地址与访问方法
对方系统与我方系统采用接口协议不一样,如何设计让对方系统调用我方系统兼容
- rpc方案
- 实现自定义rpc的步骤
七层网络分层与TCP/IP分层对应图
TCP协议和UDP协议,分别处于七层网络结构里的哪一层
- TCP和UDP都在传输层
- HTTP协议在应用层
rabbitmq消息类型
rabbitmq如何保证消息不丢失
- 发送方采取发送者确认模式
- MQ进行队列及消息的持久化
- 消费者消费成功后手动确认消息
- 采用全局唯一标识作为消息id, 防止消费者消费失败后,将消费失败的消息进行存储,以便后续补偿
- 在消费者端实现幂等性,否则重复消费问题(添加一张消费者的message表,看是否有此消息,有则跳过消费逻辑,直接确认消息已消费)
- 采用集群模式,保证mq的高可用
为什么选rabbitmq不选kafka
根据具体场景选型
为什么kafka是亿级消息中间件,性能比rabbitMQ要好
- kafka基于TCP层协议(传输层), 先天性能好
- 数据协议简单,数据占用小,采用稀疏索引的机制将数据保存在各个分区中
- 页缓存技术+磁盘顺序写
- 零拷贝技术
http各状态码意义
http不同协议版本对比
restful协议与标准有哪些
char类型能存中文吗
当然可以。
不过要看所存储的中文是否收集在对应的系统字符编码集中。
在unicode编码中,所以字符固定占用两个字节,所以,无论是中文还是字段都占两个字节。
utf-8字符集编码中,字母占1个字节,中文占3个字节。
gbk字符集中,字母占1个字节,中文占2个字节。
系统开发与设计中,需要遵循哪些规范
spring启动时,如何加载一些自定义类(如配置文件, bean)
使用监听器 : ServletContextListener
具体可以分为两步:
第一步:写自定义类,实现(implements) ServletContextListener接口。然后要实现接口的两个方法 public void contextDestroyed(ServletContextEvent event)和public void contexInitialized(ServletContextEvent event
)。当然我们只需要把我们的业务逻辑写到初始化方法里就可以了。第二步:在web.xml中声明这个自定义监听器。
<listener> <listener-class>com.cn.TKong.RegQiListener</listener-class> </listener>
使用spring的注解@PostConstruct
如果是从第三方api加载配置文件, 实现EnvironmentPostProcessor类,在postProcessEnvironment方法中完成yml配置读取,然后将EnvironmentPostProcessor实现类配置到spring.factories文件中,启动时就会自动加载
spring.factories:
org.springframework.boot.env.EnvironmentPostProcessor=com.hzone.demo.config.MyEnvironmentPostProcessor
spring三级缓存是用来解决什么问题的
先说结论:是为了解决setter方法注入的bean的循环依赖问题
springboot中,如何开发start依赖组件
- 配置启动项顺序,配置初始化的bean
- 将启动配置类写入到
spring.factories·
文件的org.springframework.boot.autoconfigure.EnableAutoConfiguration=xxxx.java
- mvn clean package
- 其它项目引入
springcloud中,是如何做到注册中心的切换的(eureka、consul、nacos等)
springcloudcommons的抽象的结果
springcloud-gateway和zuul网关有什么区别
- 性能
- 实现方式
- 功能
架构的本质是什么
架构的本质就是对系统进行有序化重构,不断减少系统的“熵”,使系统不断进化。