2026Java面试题汇总---持续更新----

目录

文章说明

由于市面上面试宝典太多了,博主把看到的比较好的以及精简的面试题及相关自我总结的答案进行一个汇总,本篇文章主要为了方便有一定工作经验的java开发人员快速进行面试题突击,所以对应面试题答案应该不会太过于长篇大论,此系列一开始内容较少,会持续更新添加及整理。

此文章一方面方便自己使用,一方面分享给大家,如果大家觉得有的答案不对或者不够简化可以提出意见和建议;本文章会持续更新,也欢迎大家把觉得不错的面试题或者相关系列发到评论区,博主看到后也会进行汇总和整理。

最后补充一句,任何知识点的深入都是需要长期积累和思考的,希望大家保持一个持续学习的心态和状态。

JAVA-CopyOnWriteArrayList底层原理是怎样的

1.CopyOnWriteArrayList是线程安全的,可在需要使用线程安全的List时使用

2.CopyOnWriteArrayList内部使用数组实现,在向CopyOnWriteArrayList添加元素时,会复制一个新数组,写操作在新数组上进行,读操作在原数组上进行,并且写操作会加锁(ReetrantLock),从而防止出现并发写入丢失数据问题,写操作结束后会把原数组指向新数组

3.CopyOnWriteArrayList允许写时读,所以读性能高,适合读多写少的场景,但是CopyOnWriteArrayList比较占用内存,同时读到的可能不是实时的最新数据,所以不适合实时性要就很高的场景

JAVA-HashMap扩缩容机制

1.HashMap底层是通过数组+链表(JDK1.7及之前)或者数组+链表+红黑树(JDK1.8开始)

2.默认情况下HashMap中元素超过12个会扩容,12是因为16*0.75,16是默认数组大小,0.75是默认加载因子。

3.当某个链表长度超过8之后,如果此时数组小于64也会进行扩容,大于等于64才会把链表改成红黑树。

4.扩容为双倍扩容,即原数组大小16会扩大为32
5.缩容时机:HashMap会在扩容时,判断桶内的链表长短(因为扩容后一个桶内的链表数据会被拆分),如果小于等于6,就会退回到链表,普通删除不会触发红黑树转链表。

JAVA-ConcurrentHashMap实现和扩容机制

ConcurrentHashMap是线程安全的Map集合

1.7版本

  1. 1.7版本的ConcurrentHashMap是基于Segment分段实现
  2. 默认情况下,Segment 数量为 16,每个段独立加锁(基于 ReentrantLock),允许不同段的并发操作,从而降低锁竞争
  3. 每个Segment相当于一个小型的HashMap,扩容机制与HashMap类似
  4. 扩容判断也是每个Segment内部单独判断

1.8版本

  1. 1.8版本的ConcurrentHashMap不再基于Segment实现
  2. 采用CAS+synchronized精细化锁对每个数组元素(桶)的首节点作为锁单位
  3. 支持多线程同时扩容,如果某个线程put时发现ConcurrentHashMap正在扩容那么该线程一起扩容
  4. ConcurrentHashMap的存储结构与HashMap基本一致

1.7的实现方式的缺陷是每次通过Hash确认位置时需要2次才能定位到当前key应该落在哪个槽,且从分段锁(JDK 1.7)到单桶锁(JDK 1.8),逐步缩小锁范围,最大化并发度。

JAVA-如何创建线程池

1.不推荐使用Executors创建线程池,因为在Executors方法下创建出的不同的线程池允许的队列或者最大线程池的长度或数量Integer.MAX_VALUE,可能会产生OOM。
2.使用new ThredPoolExecutor创建线程池
3.可使用CompletableFuture对ThredPoolExecutor进行任务编排增强
4.spring生态下可使用ThreadPoolTaskExecutor进行线程池创建,并可通过使用**@Async**进行结合

JAVA-线程池核心参数及参数作用

使用ThredPoolExecutor创建线程池,可以设置7大核心参数为
核心线程数、最大线程数、非核心线程数的空闲存活时间、时间单位、工作队列、线程工厂、拒绝策略
触发流程为:提交任务->判断核心线程数是否已满->如果核心线程数满了则将任务放到队列中->如果队列满了则扩充临时线程,核心线程+临时线程总数量不超过最大线程数->如果超过最大线程数则会触发拒绝策略。
 
当临时线程空闲超过了存活时间,则会将临时线程释放。

JAVA-Synchronized 锁升级过程

无锁→偏向锁(单线程无竞争<支持可重入锁>)→轻量级锁(多线程交替竞争,使用自旋CAS)→重量级锁(多线程重度竞争,阻塞);
 
synchronized锁的是对象,且锁信息记录在对象头中。

JAVA-ArrayList扩容机制

1.jdk1.7以后,new ArrayList () 时,默认容量是 0,第一次add后扩容为10;
2.容量不足时,按1.5 倍扩容,通过 Arrays.copyOf 复制数组。

JAVA-Synchronized和ReentrantLock区别

1.Synchronized是JVM层面关键字,ReentrantLock是JDK层面实现的API类
2.Synchronized是非公平锁,ReentrantLock支持公平锁和非公平锁
3.Synchronized自动获取和释放锁,ReentrantLock手动lock和unlock
4.synchronized 不支持中断、超时;ReentrantLock 支持

Spring-@Autowired和@Resource的区别

1.@Autowired是spring提供的IOC相关注解,与spring框架强绑定,@Resource是JSR-250(JDK层面)提供的,是Java标准

2.@Autowired先根据属性的类型去Spring容器中找Bean对象,如果找到多个,就会根据属性名字去确定其中一个,如果根据名字没找到则会报错

3.@Resource会先根据属性名字去Spring容器中找到Bean对象,如果没找到,则会根据属性类型来找,如果找到多个则会报错。

总和以上信息,推荐使用@Resource,耦合度更低。

Spring-SpringMVC如何处理一个请求

1.tomcat收到请求后,会交给DispatcherServlet处理,DispatcherServlet会根据请求的path找到对应的Handler(即加了@RequestMapping注解的方法),准备执行方法。

2.执行方法前,会解析方法的各个参数,例如@RequestParam、@ResponseBody等注解,进行参数解析、赋值、返回值返回给浏览器等操作。

Spring-Spring中Bean是线程安全的吗

Spring本身并没有针对Bean做线程安全处理;如果Bean是无状态的,则线程安全;如果Bean是有状态的则不是线程安全的。

Spring-Spring的事务是怎么工作的

1.Spring事务是基于AOP实现,使用的注解是@Transactional

2.代理对象执行方法时,如果方法上有@Transactional则开启事务,开启事务即获取一个数据库连接,将autocommit(自动提交)属性改为false,进行方法执行,根据方法执行是否抛出异常来进行对应操作,若未异常则commit(提交),若有异常则执行rollback(回滚)。

Spring-Spring的@Transactional什么时候会失效

存在以下多个场景,其中加粗为重点情况
1.方法不是 public 的,Spring AOP 代理在生成代理类时,只对 public 方法生成事务代理,可修改方法为public。

2.发生自身调用(即this.或直接自调用方法),当一个类中的非事务方法调用本类的事务方法时,调用是通过 this 直接调用,而不是通过 Spring 代理对象调用,因此事务不能生效,可通过将事务方法移到另一个 Service 类中使用 ApplicationContext 获取当前 Bean 的代理对象解决

3.异常被捕获且未重新抛出(即使用try、catch)

4.数据库不支持事务

5.设置了不支持事务

6.事务传播机制配置错误

Spring-Spring的Bean生命周期

  1. 推断构造方法
  2. 实例化
  3. 填充属性(依赖注入)
  4. 处理Aware回调
  5. 初始化前,处理@PostConstruct注解
  6. 初始化,处理InitializingBean接口
  7. 初始化后进行Aop
  8. 容器关闭对Bean进行销毁

Spring-ApplicationContext和BeanFactory区别

BeanFactory是可以生成和维护Bean的工厂,ApplicationContext继承了BeanFactory,所以ApplicationContext具备BeanFactory的所有特点,除此之外ApplicationContext还继承了EnvironmentCapable、MessageSource、ApplicationEventPublisher等接口具备了获取系统环境变量、事件发布、国际化等功能。

Spring-SpringBoot启动原理

1.创建Spring容器
2.加载自动配置类
3.启动内置tomcat

Spring-SpringBoot启动注解@SpringBootApplication

  1. @SpringBootApplication是一个组合注解,其中包含如下三个注解
    1.1 @SpringBootConfiguration:这个注解表示启动类也是一个配置类,类似于@Configuration
    1.2 @EnableAutoConfiguration:启用自动配置机制,根据类路径依赖(如spring-boot-starter-web)自动配置应用组件(如Tomcat、Spring MVC);通过META-INF/spring.factories文件加载预定义的自动配置类(如DataSourceAutoConfiguration)
    1.3 @ComponentScan:自动扫描当前类所在包及其子包中的组件(如@Component、@Service),并注册为Spring Bean。

Spring-SpringBoot自动装配原理

自动装配就是自动将第三方的Bean装载到IOC容器,springboot中通过@SpringBootApplication中的@EnableAutoConfiguration注解实现,核心实现思路是约定大于配置+SPI机制+条件注解,核心流程为:
1.EnableAutoConfiguration开启自动装配
2.利用SPI机制读取所有依赖包里的META-INF/spring.factories的自动装配类xxxAutoConfiguration
3.再通过@Conditional系列条件注解判断装配条件,满足就把Bean注册到Spring容器,从而实现自动装配。

数据库-什么是Mysql的前缀索引

前缀索引是只建立索引时可以只使用某个字段的前面一部分,而不是整个字段,比如邮箱就适合定义前缀索引,这样就比使用整个字段建立索引更省磁盘空间。

数据库-索引覆盖是什么

一个SQL在执行时,可以利用索引快速查找,并且SQL中所要查询的字段在当前索引对应的字段中都包含了,此SQL走完索引就不用回表了,所需的字段都在当前索引的叶子节点上存在。

数据库-最左前缀原则是什么

当你在数据库表上创建了一个复合索引(也叫联合索引,包含多个列)时,这个索引可以被用来加速那些查询条件只使用了该索引最左边一个或连续多个列的查询。它并不要求查询条件必须包含索引中的所有列,但必须从最左边的列开始,并且是连续的(不能跳过中间的列)

数据库-Mysql锁有哪些

按锁粒度分类:

  1. 行锁:锁某行数据,锁粒度最小,并发度高
  2. 表锁:锁整张表,锁粒度最大,并发度低
  3. 间隙锁:锁一个区间

还可以分为:

  1. 共享锁(读锁):一个事物给某行数据加了读锁,其他事物也可以读,但是不能写
  2. 排它锁(写锁):一个事物给某行数据加了写锁,其他事物不能读,也不能写

还可以分为:

  1. 乐观锁:并不会真正的去锁某行记录,而是通过一个版本号来实现
  2. 悲观锁:上面的行锁、表锁等都是悲观锁

数据库-Mysql执行Delete后磁盘空间是否释放

不释放、只是标记此空间可复用,并不会释放磁盘空间,可通过OPTIMIZE TABLE your_table_name 命令释放空间。

数据库-B树和B+树的区别

首先mysql默认使用的是B+树,以下为区别及原因
 
1.B树每个节点都存储数据,B+树只有叶子节点存储数据,B+树这样设计可以使B+树更宽,降低树的高度,从而降低数据的I/O检索次数,提高查询性能
 
2.B+树叶子节点通过双向链表相连,范围查询性能更好

数据库-Mysql聚簇索引、非聚簇索引

InnoDB下,主键索引也叫聚簇索引或聚集索引,聚簇索引或聚集索引为存储数据的一种形式,即数据和索引存在一个文件下(叶子节点存储索引数据+整体行数据),**非主键索引(二级索引)**也叫非聚簇索引或非聚集索引,即数据和索引不存在一个文件下(叶子节点只存储索引数据+主键ID,寻找其他数据需要进行回表去主键索引查询)。

数据库-单表最多数据量多少需要分表

结论:阿里推荐单表超过500W行或者容量超2GB,才推荐进行分库分表。
 
可以主键索引-聚簇索引为例,通过B+树结构、3层树高、每层数据页大小-默认 16KB-16384 字节进行结果反向推导及扩展

1)如果主键为INT主键4字节,指针 6 字节 → 单个 “主键 + 指针” 占 10 字节;16KB 数据页 = 16384 字节,扣除少量页头开销(约 100 字节),实际可用空间≈16284 字节;单个分支节点能存的 “主键 + 指针” 数量 = 16284 ÷ 10 ≈ 1628 个(取整)。
 
2)3 层 B + 树的结构是:1 个根节点 → 若干二级分支节点 → 若干叶子节点
根节点(第 1 层):能存≈1628 个二级分支节点的指针(即第 2 层有 1628 个节点);
二级分支节点(第 2 层):每个节点能存≈1628 个叶子节点的指针 → 总计 1628×1628≈265 万个叶子节点;
叶子节点(第 3 层):每个叶子节点存多少行,取决于行大小(表字段) —— 这是唯一和表结构相关的变量,以中等表500 字节 / 行为例,每个数据页约存16284 ÷ 500 ≈ 32 行,265 万 × 32 ≈ 8480 万行,所以考虑主键大小、表字段每行数据大小及要有一定冗余空间,得出以上结论。

数据库-深分页如何优化

例:
SELECT * FROM table WHERE xxx LIMIT 100000, 20;
MySQL 会先扫描 100020 条,再丢弃前 100000 条,数据越大越慢。

方案一:通用方案:基于主键 / 唯一索引的子查询
SELECT t.*
FROM table t
JOIN (
SELECT id FROM table
WHERE xxx
ORDER BY id
LIMIT 100000, 20
) tmp ON t.id = tmp.id;
 
先只查主键,不走回表
再用主键关联查完整数据

方案二:游标分页(存在业务限制)
 
// 上一页最后一条 id = ?
SELECT * FROM table
WHERE id > ?
AND xxx
ORDER BY id
LIMIT 20;
 
适合滚动加载、小程序、APP 列表,不能跳页需要ID可排序或者存在可排序字段

方案三:结合业务处理
根据实际业务情况,也可进行例如分年查询、或分库分表等方式进行数据拆分避免深分页

JAVA-什么是内存泄漏?有什么影响

即内存被使用过后一直没有释放掉,导致系统可用内存逐渐减少,从而导致程序卡顿,最终程序崩溃,内存溢出。

数据库-Innodb如何实现事务

Innodb通过Buffer pool,LogBuffer,Redo Log,Undo Log来实现事务
1.Innerdb在收到一个update语句后,会先根据条件找到数据所在的页,并将该页缓存在Buffer Pool中
2.执行update语句,修改Buffer Pool中的数据,也就是内存中的数据
3.针对update语句生成一个RedoLog对象,并存入LogBuffer中
4.针对update语句生成undolog日志,用于事务回滚
5.如果事务提交,则把redoLog对象进行持久化
6.如果事务回滚,则利用undoLog日志进行回滚

RedoLog用来提升数据写入性能(将频繁的 “随机写数据页” 转化为 “顺序写 redo log”)和崩溃恢复数据
 
UndoLog用来数据回滚和事务隔离

数据库-如何使用EXPLAIN判断SQL好坏

1.type 是性能等级,从最好到最差 system > const > eq_ref > ref > range > index > ALL
 
ALL:全表扫描 → 最差,必须优化
index:遍历索引树 → 一般,尽量避免
range:索引范围查询 → 合格
ref:普通索引等值匹配 → 良好
eq_ref/const:主键 / 唯一索引 → 优秀
 
2.看 key,key 有值:走了索引,key 为 NULL:没走索引,大概率全表扫描
3.看 rows(扫描了多少行)数字越小越好、接近实际返回行数 = 索引高效、远大于返回行数 = 索引选错 / 索引失效
4.看 Extra(重要警告信息)
Using filesort必须优化,MySQL 无法用索引排序,要额外排序,大表极慢。
Using temporary,必须优化,用到了临时表,group by /order by 没走索引。
Using index,很好,覆盖索引,直接从索引取数据,不用回表。
Using where,正常,使用 where 条件过滤。
Using index condition,索引下推,正常优化。

JAVA-JVM整体结构

JVM中存在三个子系统,类加载子系统、运行时数据区、执行引擎

类加载子系统:负责将字节码(class文件)加载到JVM中,加载->验证->准备->解析->初始化
在这里插入图片描述

运行时数据区:主要用来存储程序运行过程中所产生的对象,包括方法区、堆区、虚拟机栈、程序计数器、本地方法栈
在这里插入图片描述

执行引擎:主要用来解释执行字节码,并且进行垃圾回收,包括解释器、即时编译器、垃圾回收器在这里插入图片描述

JAVA-JVM运行时数据区各区域作用

方法区:方法区的具体实现为永久代或元空间(JDK8),方法区主要用来存储,某个类的信息(比如某个类的名字、父类的名字),某个方法的信息以及常量池,方法区是多个线程共享的区域。

堆区:主要用来存放对象,堆区又可以分为新生代老年代,新生代又可以分为Eden区Survivor区,一个新的对象创建出来后会先存放在Eden区,当Eden区满了后就会触发Minor GC,存活的对象就会转移至Survivor区,默认情况下经过15次GC后,该对象还存活,就会从Survivor区转移到老年代,堆区是多个线程共享的区域。

虚拟机栈:用来记录当前线程正在执行哪个方法,每执行一个方法就会生成一个栈帧入栈,方法执行完之后对应的栈帧就会出栈,虚拟机栈是每个线程独有

本地方法栈:与虚拟机栈类似,本地方法栈是用来记录native方法的执行,本地方法栈是每个线程独有

程序计数器:用来记录当前线程所执行的字节码的某条指令地址,用来保证线程切换后能恢复到正确位置,是每个线程独有的。

JAVA-有哪些垃圾回收算法

垃圾回收分为两个阶段,标记阶段清除阶段

标记阶段:有引用计数法可达性分析法
 
引用计数法
给每个对象保存一个引用计数器,用来记录对象被引用的情况,为0则表示是垃圾对象
 
可达性分析法
可达性分析法可以类比成生活中的 族谱
GC Roots(垃圾回收根节点):相当于族谱里的 “始祖”,是绝对不会被回收的 “根对象”。
引用链:相当于始祖到子孙的血缘关系,只要能通过 “血缘”(引用)连接到始祖,这个子孙就 “有根可循”。
不可达对象:如果一个对象和 GC Roots 之间没有任何引用链连接,就相当于族谱里断了血缘的 “孤魂”,会被判定为可回收对象
简单来说:可达性分析法的核心是从 GC Roots 出发,遍历所有对象的引用关系,能被遍历到的对象是 “存活对象”,遍历不到的就是 “垃圾对象”。
 
一般的GC Roots有栈中的本地变量、方法区中的静态变量、本地方发栈中的变量、正在运行的线程等

清除阶段:有标记-清除算法复制算法标记-整理算法
 
标记-清除算法
这种算法简单但低效,就是线性的找到待回收区域中的垃圾对象,然后清除他们,会产生碎片
 
复制算法
直接把存活的对象复制到另一个区域,性能比较快,不会产生碎片,但是需要两倍的内存空间
 
标记-整理算法
利用GC Root找到存活对象,然后将存活对象压缩到内存的另一端(并非另一个预留区域),之后清除掉边界另一端的所有对象,这样不会产生碎片,并且也不需要额外的空间,缺点是性能不高,三种算法中最慢,当然,不同的垃圾回收器,不同的区域会采用不同的算法。

JAVA-介绍一下三色标记算法

1.三色标记算法是实现可达性分析的具体策略,通过分色管理对象状态。核心目的是在并发标记阶段(GC 线程与用户线程同时运行)避免长时间 STW(Stop-The-World),提升 GC 效率
 
2.颜色分为
白色(未被标记,默认状态;标记结束后仍为白色的对象视为 “垃圾”,会被回收)
灰色(已被标记,但该对象的子对象(引用的对象)尚未全部标记)
黑色(已被标记,且该对象的所有子对象都已完成标记;黑色对象视为 “存活”)
 
3.存在问题:三色标记算法因是异步标记,所以在并发场景下可能出现 “漏标” 问题,因此 G1/ZGC 等垃圾收集器会通过 “写屏障(Write Barrier)” 机制解决该问题。

JAVA-垃圾回收器有哪些

Parallel – jdk8默认使用的是Parallel垃圾回收器,适用于4G以下的TOB的项目(适用于多核处理器的高吞吐应用),其中新生代使用Parallel Scavenge(复制算法)、老年代使用Parallel Old(标记整理算法)
 
ParNew+CMS – 中型的互联网项目,对并发量要求较高的TOC项目,内存4-8G使用ParNew(复制算法)+CMS(标记清除算法)
 
G1 – jdk9默认垃圾回收器,主流回收器,适用于中大型项目,对 应用 响应时间要求高的使用G1垃圾回收器,需要内存8G以上
 
zgc – zgc垃圾收集器适用于需要极低停顿时间的大内存应用,几百G以上用zgc

JAVA-双亲委派机制

Java 类加载的双亲委派机制,是 JVM 加载类时遵循的一种先找父加载器,父加载器如果还有父加载器则会进一步委托,父加载器处理不了再自己处理的层级加载规则,即自上而下委派检查,自下而上实际加载,核心目的是保证类加载的安全性和唯一性。
 
Java 默认有三层类加载器:最顶层的启动类加载器(加载核心类Bootstrap ClassLoader)、扩展类加载器(加载扩展类Extension ClassLoader)、应用类加载器(加载应用类Application ClassLoader)

JAVA-TomCat为什么要重写Java类加载器

突破双亲委派模型的限制,解决多 Web 应用部署的类隔离、版本冲突、热部署问题

Redis-redis有哪些数据结构

1.字符串Map<String,String>:可以用来做最简单的数据,也可以缓存某个json格式的字符串。
 
2.哈希表Map<String,Map<String,String>>:可以用来存储一些key-value对,更适合用来存储对象
 
3.列表Map<String,List>:可以当做栈,也可以当做队列来使用
 
4.集合Map<String,Set<String,String>>:也可以存储多个元素,但是不能重复,集合可以进行交集、并集、差集操作,从而可以实现类似共同关注的人、朋友圈点赞等功能
 
5.有序集合zset(sortset):有序集合可以设置顺序,可以用来实现排行榜功能

Redis-redis如何实现分布式锁

1.要实现最简单的分布式锁效果,可以直接使用redis的SET key value NX PX expire_time,如果key不存在才能获取到锁,如果key存在,则获取不到锁。NX保证线程安全问题,PX防止死锁,该方式实现简单,但是不具备自动续期(看门狗)、可重入锁等功能,且如果PX设置不合理的情况下会产生数据安全问题。
 
2.一般实际项目中可使用Redisson来进行分布式锁的实现,Redisson使用了Hash 操作 + Lua 脚本来保证分布式锁的基本功能,既保留了 “互斥性”,又具备了可重入、自动续期、红锁(RedLock)等高级功能

Redis-缓存雪崩、缓存击穿、缓存穿透分别是什么及如何解决

缓存雪崩: 指大量缓存 key 在同一时间段内集中过期,或缓存服务本身宕机(如 Redis 集群故障),导致所有请求瞬间打到数据库,数据库无法承受而崩溃;解决方式:可在过期时间上增加一点随机值,从而避免集中过期。
 
缓存击穿:指某个热点 key 的缓存突然失效(过期 / 被删除),此时大量并发请求同时访问这个 key,缓存 miss 后全部打到数据库,导致数据库瞬间压力骤增;解决方式:可对该热点key不设置过期时间
 
缓存穿透:指请求的数据在缓存和数据库中都不存在(比如黑客故意伪造一些乱七八糟的key),每次请求都会 “穿透” 缓存直接打到数据库,导致数据库承受大量无效请求;解决方式:提前将所有有效 key 存入布隆过滤器,请求先过过滤器,不存在的 key 直接拦截,然后再将布隆过滤器误判的已存在的key在redis中设置为null,同一 Key 只会穿透一次,后续被空值缓存拦截即可100%防止缓存穿透

Redis-redis和mysql如何保证数据一致

延时双删:先删除redis缓存,再更新mysql,延迟几百毫秒再删除redis缓存数据,这样就算在更新mysql时,有其他线程读了mysql,把老数据读到了redis中,也会被删除,从而把数据保持一致。

Mq-rabbitmq如何保证消息不丢失

1.生产者:开启Publisher Confirm 生产者确认<判断消息有没有到达交换机>(一般生产使用异步,然后用回调+落库+定时器重发兜底)来即保障性能,又保证消息不丢失。)
2.生产者:开启 Return 失败回调,防止未找到路由的消息丢失

spring:
rabbitmq:
# 异步Confirm(生产必用)
publisher-confirm-type: correlated
# 开启Return回调
publisher-returns: true
# 路由失败必须退回消息(必须配!)
template:
mandatory: true
3.交换机、队列、消息设置durable=true持久化
4.消费者通过手动ACK确认保证消息不丢失,并且通过重试+死信队列保证消息被消费不丢失且不会无限重试。

Mq-rabbitmq如何保证消息不被重复消费

首先,为了避免消息不丢失,一定会开启手动ACK,开启手动ACK一定会存在同一消息被重复推送,所以处理消息不被重复消费可以使用全局唯一 msgId(生产者自定义) + Redis 分布式锁处理

Mq-rabbitmq如何保证消费顺序性

1.同一类有序消息只发送到 同一个队列;
2.消费者 单线程消费,关闭并发;
3.按业务 ID 取模路由到不同队列(既要顺序又要性能)

微服务-描述一下分布式系统中的CAP理论

分布式系统里,最多只能同时满足 2 个,永远不可能 3 个同时满足。
三个字母分别代表:
C:Consistency 一致性
A:Availability 可用性
P:Partition tolerance 分区容错性
分布式系统必须保证 P(分区容错),所以只能在 C(一致性)和 A(可用性)之间二选一:
要强一致 → 选 CP(ZooKeeper、HBase等)
要高可用 → 选 AP(Redis、Eureka、大多数微服务注册中心等)

微服务-描述一下BASE理论

BASE 理论是对 CAP 理论中 “放弃强一致性,换取高可用性” 这一选择的补充和落地,它是Basically Available(基本可用)、Soft state(软状态)、Eventually consistent(最终一致性) 的缩写,即保证最终一致。

微服务-分布式事务如何解决

1.在不引用外部三方插件的情况下,可以基于TCC、SAGA两种模式的思想来保证数据的一致性。
2.引入seata可选择XA或AT模式,建议使用AT模式
3.不建议使用2PC(二阶段提交)、3PC(三阶段提交)模式,阻塞、性能较低。

微服务-服务注册到注册中心及调用流程(注册中心原理)

1)服务注册与发现:当一个服务实例启动时,它会向注册中心发送注册请求,将自己的信息注册到注册中心。注册中心会将这些信息保存在内存中,并提供REST接口供其他服务查询。服务消费者可以通过查询服务实例列表来获取可用的服务提供者实例,从而实现服务的发现。
    例:A服务启动调用注册中心接口,注册到注册中心

2)服务健康检查:注册中心通过心跳机制来检测服务实例的健康状态。服务实例会定期向注册中心发送心跳,也就是续约,以表明自己的存活状态。如果注册中心在一定时间内没有收到某个服务实例的心跳,则会将其标记为不可用,并从服务列表中移除,下线实例。
    例:A服务定期与注册中心进行心跳通知,以让注册中心知道A服务在正常运行
3)服务负载均衡:服务实例在调用其他服务时,会从本地缓存中获取服务的注册信息。如果缓存中没有对应的信息,则会向注册中心发送查询请求。注册中心会返回一个可用的服务实例列表给客户端,客户端可以使用负载均衡算法选择其中一个进行调用。
    例:当A服务需要调取其他服务时,会在注册中心获取当前服务列表并缓存到A服务本地,通过本地服务列表进行其他服务调用。

微服务-注册中心心跳机制流程

以nacos默认情况为例
1)默认情况下,A服务启动时,调用nacos服务端接口,进行信息注册,并每隔5秒调用naocs服务端接口通知nacos服务端,已说明服务健康。
2)nacos服务端启动时,自身会启动一个定时任务,每隔5秒查看注册进来的服务最新心跳通知时间,超过15秒未更新则设置为不健康状态,超过30秒未更新则剔除

微服务-本地服务列表保存 & 更新机制

以nacos默认情况为例:
1)A服务启动时会去nacos服务端拉取服务列表至本地,并与Nacos建立推+拉结合机制
2)推:Nacos Server 检测到服务实例变更(上线 / 下线 / 健康状态变化),立刻通过长连接推送变更数据给客户端;客户端收到后更新内存 + 磁盘缓存。
3)拉:客户端启动定时任务,每 15 秒主动向 Server 拉取服务列表;若推送丢失,拉取会兜底补全,确保缓存不滞后。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值