记忆方法:
“创建单工建,结构适装代,行为观策模”
(每类取3个常用模式首字,结合场景功能:创建型管对象生成,结构型管类/对象组合,行为型管交互)
记忆方法:
“重写看父子,签名(方法名+参数)必须同;重载看同类,签名必须异”
(核心区别:重写是父子类关系+签名相同,重载是同类关系+签名不同)
记忆方法:
“浅克隆,抄表面;深克隆,抄到底”
(浅克隆仅复制表层结构,深克隆递归复制所有层级,强调是否复制引用对象的内部数据)
Object o = new Object()
)。记忆方法:
“强永不收,软缺才收,弱遇GC收,虚仅跟踪”
(按GC回收的严格程度排序,突出每种引用被回收的条件)
记忆方法:
“Serial单线程,Parallel重吞吐,CMS求低延,G1两边顾,ZGC/Shenandoah超快速”
(按核心特点和适用场景区分,从简单到复杂排序)
记忆方法:
“改写loadClass,跳过父直接加”
(核心是通过重写加载方法,绕过双亲委派的委托流程)
记忆方法:
“计数看数字,为0就回收;可达看链条,断了就能收”
(前者记数字变化,后者记引用链是否可达,突出两种方法的核心判断逻辑)
记忆方法:
“无锁起步,偏向单线程,轻量交替争,重量多线程”
(按竞争程度从小到大,对应锁的升级阶段,突出各阶段适用场景)
记忆方法:
“where在前筛行,having在后筛组;where不用聚合,having可带聚合”
(按执行时机和是否支持聚合函数区分,突出“行”与“组”的过滤对象差异)
记忆方法:
“内连取交集,左连保左全,右连保右全,全连取并集”
(用“交集”“保左/右全”“并集”形象化范围,结合左右表的保留规则记忆)
记忆方法:
“多版本,读写欢;版本号,判可见;不阻塞,并发赞”
(突出多版本特性、版本号作用及无锁并发的优势)
**回答: **
1. 若启用RDB/AOF持久化,重启后可通过备份文件恢复数据;
2. 若主从架构,从库升级为主库继续提供服务,修复主库后再同步;
3. 集群模式下,其他节点会自动接管,保证可用性(哨兵模式集群)。
**记忆法: **
“持久化救数据,主从/集群保服务”——崩溃后先靠持久化恢复数据,再通过主从或集群架构保障服务不中断。
**回答: **
哨兵模式是Redis主从架构的高可用方案,机制为:
1. 监控:哨兵进程持续检查主从节点健康状态;
2. 自动故障转移:主库故障时,哨兵选举新主库(从库晋升),并让其他从库同步新主库;
3. 通知:将故障转移结果通知客户端。
理解:
- 哨兵是一个独立的进程
- 每个哨兵监控一个服务器
- 哨兵实现消息通知和执行选举
**记忆法: **
“监(监控)选(选新主)同(同步)告(通知)”——哨兵核心动作就是这四步,按顺序记住即可。
**回答: **
Redis分布式集群通过哈希槽(共16384个)存储数据:
1. 每个键经哈希计算映射到一个槽;
2. 集群节点分管不同槽(可配置分配);
3. 客户端请求时,节点会根据槽归属,转发请求到对应节点。
**记忆法: **
“键哈希找槽,槽归节点管,请求按槽转”——核心是哈希槽作为数据与节点的中间映射桥梁。
**区别: **
1. 一级缓存:默认开启,作用于SqlSession级别,同一会话内重复查询同SQL会命中缓存;
2. 二级缓存:需手动开启,作用于Mapper namespace级别,跨SqlSession共享,可自定义存储介质。
**开启方式: **
- 一级缓存:无需额外配置,默认生效;
- 二级缓存:在Mapper.xml中加<cache/>
标签,或在接口类/方法加@CacheNamespace
注解。
**记忆法: **
“一级会话内,二级跨会话;一级默认开,二级XML/注解来”——按作用范围和开启方式区分,口诀串联核心特点。
**回答: **
- #{}:会预编译SQL,将参数作为占位符处理,自动添加引号,能防止SQL注入,比较安全;
- ${}:直接拼接参数到SQL中,不预编译,有SQL的注入风险,不安全,但可用于动态表名、排序字段等场景。
**记忆法: **
“#安全带引号,$直接拼有风险”——#{}更安全带参数处理,${}直接拼接需谨慎。
**回答: **
常用动态标签:
1. <if>
:条件判断,满足条件才拼接 SQL;
2. <where>
:自动处理AND/OR前缀,配合<if>
使用;
3. <set>
:用于UPDATE,自动处理逗号,适配字段动态更新;
4. <foreach>
:遍历集合,生成IN、批量插入等语句;
5. <choose><when><otherwise>
:多条件分支,类似if-else if-else。
**记忆法: **
“if判条件,where管拼接,set改字段,foreach遍历忙,choose分支强”——按功能场景串联记,关联使用场景更易记。
回答:
反射是指程序在运行时可获取类的信息(属性、方法、构造器等),并动态操作类或对象的机制。核心是通过Class对象访问类元数据,实现动态创建实例、调用方法、修改属性等。
记忆法:
“运行时获类信息,动态操作靠反射;Class对象是核心,元数据访问全靠它”——抓住“运行时”“动态操作”和核心载体Class对象这两个关键点。
**回答: **
1. 类名.class:通过类的静态属性获取,如 User.class
;
2. 对象.getClass():通过实例对象调用方法获取,如 new User().getClass()
;
3. Class.forName(“全类名”):通过全类名字符串加载类获取,如 Class.forName("com.example.User")
。
**记忆法: **
“类名点class,对象调getClass,字符串用forName”——按获取方式的主体(类、对象、字符串)对应记忆,简洁好记。
**回答: **
1. new关键字:最常用,如new User()
;
2. 反射:通过Class的newInstance()
或Constructor的newInstance()
;
3. 克隆:实现Cloneable接口,调用clone()
方法;
4. 反序列化:从IO流中恢复对象,如ObjectInputStream的readObject()
。
**记忆法: **
“new最直接,反射动态建,克隆复一份,反序列化读”——按创建逻辑(直接创建、动态创建、复制、读取)对应记忆。
**回答: **
IOC(控制反转)是Spring核心思想,指将对象创建、依赖管理的控制权从代码转移到容器(Spring容器),由容器统一管理对象生命周期和依赖注入。
核心是“反转”:传统是代码主动new对象,IOC是容器被动注入,降低耦合。
**记忆法: **
“对象不由自己new,交给容器来伺候;依赖注入解耦合,控制反转是核心”——抓住“容器管理”“被动注入”“解耦”三个关键点。
回答:
AOP(面向切面编程)**是一种编程思想**,通过分离通用功能(如日志、事务、权限)与业务逻辑,实现代码复用和解耦。
核心是将分散在各处的横切逻辑(切面)抽离,在不修改原有代码的情况下,通过动态代理等技术在指定切点(如方法执行前/后)织入增强逻辑。
**记忆法: **
“横切逻辑抽成面,不改代码织进去;代理帮忙做增强,解耦复用效率提”——抓住“抽离切面”“动态织入”“解耦复用”三个核心点。
**回答: **
AOP底层通过动态代理实现,Spring会根据目标类是否实现接口选择不同方式:
1. 若实现接口:使用 /JDK动态代理/ ,生成接口的代理类,通过反射调用目标方法并织入增强逻辑;
2. 若未实现接口:使用 /CGLIB动态代理/ ,通过继承目标类生成子类代理,重写方法实现增强。
**记忆法: **
“有接口用JDK,无接口靠CGLIB;代理类来做增强,反射/继承是根基”——按是否有接口区分实现方式,核心是动态生成代理类并织入逻辑。
**回答: **
常用AOP注解(基于Spring):
1. @Aspect
:标识类为切面类;
2. @Pointcut
:定义切点(指定增强位置,如execution(* com..*Service.*(..))
);
3. @Before
:前置增强(目标方法执行前);
4. @After
:后置增强(目标方法执行后,无论是否异常);
5. @AfterReturning
:返回后增强(目标方法正常返回后);
6. @AfterThrowing
:异常增强(目标方法抛出异常后);
7. @Around
:环绕增强(包裹目标方法,可控制执行时机)。
**记忆法: **
“@Aspect标切面,@Pointcut定切点;前Before后After,返回Returning异常Throwing,Around环绕全包含”——按切面定义、切点声明、增强类型分类记忆,关联执行时机更易记。
**回答: **
AOP有5种通知方式(增强类型):
1. 前置通知(Before):目标方法执行前执行;
2. 后置通知(After):目标方法执行后执行,无论是否异常;
3. 返回后通知(AfterReturning):目标方法正常返回后执行;
4. 异常通知(AfterThrowing):目标方法抛出异常后执行;
5. 环绕通知(Around):包裹目标方法,可在执行前后自定义逻辑,甚至控制是否执行目标方法。
**记忆法: **
“前Before、后After,正常返回Returning,抛异常Throwing,环绕Around全包揽”——按执行时机和范围区分,环绕通知覆盖最全面。
**回答: **
同一切面内通知执行顺序:
1. 环绕通知(Around)的前半部分 →
2. 前置通知(Before) →
3. 目标方法执行 →
4. 环绕通知(Around)的后半部分 →
5. 返回后通知(AfterReturning)/异常通知(AfterThrowing) →
6. 后置通知(After)。
不同切面间:默认按类名排序(字母序),可通过@Order
指定优先级(值越小越先执行)。
**记忆法: **
“环绕前→前置→目标→环绕后→返回/异常→后置”,联想“环绕包裹目标,前后置和返回/异常按执行阶段递进,后置收尾”。
**回答: **
Spring常用的依赖注入(DI)方式有3种:
1. 构造器注入:通过构造方法参数注入依赖,如@Autowired
标注构造器;
2. Setter方法注入:通过Setter方法注入,如@Autowired
标注setter方法;
3. 字段注入:直接在字段上标注@Autowired
,无需setter或构造器。
**记忆法: **
“构造器传参,setter方法设,字段直接标”——按注入位置(构造器、setter方法、字段)对应记忆,关联各自的实现方式。
面试回答建议:
1. 首先明确指出:Spring 常用的注入方式主要有三种:**构造器注入**、**Setter 注入**和**字段注入**。
2. 重点强调:**构造器注入是官方推荐的方式**,并解释其优点(不可变、完全初始化、易于测试、避免循环依赖)。
3. 提到其他方式:也可以提一下 @Resource
和基于 Java/XM L配置的方式,展示你的知识广度。
4. 表达个人见解:可以说在现代 Spring Boot 开发中,你通常会使用构造器注入来编写更健壮、更易于测试的代码。
**回答: **
- 来源:@Autowired
是Spring注解;@Resource
是JDK自带注解(javax.annotation包)。
- 匹配方式:@Autowired
默认按类型(byType)匹配,需配合@Qualifier
指定名称;@Resource
默认按名称(byName)匹配,名称不符再按类型。
- 适用场景:@Autowired
可用于构造器、方法、字段;@Resource
不支持构造器注入。
**记忆法: **
“Autowired是Spring的,按类型配;Resource是JDK的,先名后类型”——从来源和匹配逻辑区分,核心差异在匹配方式和所属框架。
**回答: **
Spring Bean的常用作用域有5种:
1. singleton(单例):默认,容器中只有一个实例,全局共享;
2. prototype(原型):每次请求创建新实例,每次获取都是新对象;
3. request:web环境中,每个HTTP请求对应一个实例;
4. session:web环境中,每个会话对应一个实例;
5. application:web环境中,整个应用生命周期一个实例。
**记忆法: **
“单例(singleton)默认全局用,原型(prototype)每次新;request随请求,session随会话,application全应用”——按适用范围从小到大(实例→请求→会话→应用)记忆,区分单例与原型的核心差异。
**回答: **
Spring Bean生命周期可概括为8步:
1. 实例化(通过构造器创建对象);
2. 属性注入(依赖注入,如@Autowired赋值);
3. 调用BeanNameAware的setBeanName()(获取Bean名称);
4. 调用BeanFactoryAware的setBeanFactory()(获取BeanFactory);
5. 调用ApplicationContextAware的setApplicationContext()(获取应用上下文,若实现);
6. 调用BeanPostProcessor的postProcessBeforeInitialization()(初始化前增强);
7. 调用初始化方法(如@PostConstruct、afterPropertiesSet());
8. 调用BeanPostProcessor的postProcessAfterInitialization()(初始化后增强);
(容器关闭时)
9. 调用销毁方法(如@PreDestroy、destroy())。
**记忆法: **
“实例化→注值→Aware回调→前后处理→初始化→后处理→销毁”,按对象创建到销毁的时间线串联记,关键节点是注入、回调、初始化、销毁。
Spring Bean生命周期主要包括:
1. 实例化(Instantiation)
2. 属性赋值(Populate)
3. 初始化(Initialization):包括各种Aware接口回调、BeanPostProcessor前置处理、自定义初始化方法、BeanPostProcessor后置处理
4. 使用(In Use)
5. 销毁(Destruction):包括自定义销毁方法、各种销毁回调
记忆方法:可记为“实赋初用毁”(实例化、赋值、初始化、使用、销毁),再细化初始化阶段的关键步骤,结合“先Aware后处理器,自定义方法中间插”辅助记忆。
Spring通过三级缓存解决Bean循环依赖:
1. 一级缓存(singletonObjects):存储完全初始化的Bean
2. 二级缓存(earlySingletonObjects):存储提前暴露的原始Bean(未完成属性注入)
3. 三级缓存(singletonFactories):存储Bean工厂,用于生成原始Bean的代理对象
流程:当A依赖B、B依赖A时,A实例化后提前暴露到三级缓存,B实例化时从三级缓存获取A的原始对象并完成注入,B初始化后存入一级缓存,A再从一级缓存获取B完成注入。
记忆方法:“三缓存,先暴露,原始对象解循环”,三级缓存依次为“成品、半成品、生产厂”。
SpringMVC常用注解:
1. @Controller:标识控制器类
2. @RequestMapping:映射请求路径和方法
3. @GetMapping/@PostMapping等:简化特定HTTP方法的@RequestMapping
4. @RequestParam:绑定请求参数
5. @PathVariable:绑定URL路径变量
6. @RequestBody:接收请求体数据
7. @ResponseBody:将返回值直接作为响应体
8. @ModelAttribute:绑定请求参数到模型
9. @SessionAttributes:将模型数据存入会话
记忆方法:“控(Controller)制请求(RequestMapping)方式(Get/Post),参数(RequestParam)路径(PathVariable)体(RequestBody),响应(ResponseBody)模型(ModelAttribute)会话(SessionAttributes)存”。按“控制器标识-请求处理-参数绑定-响应处理-数据存储”逻辑串联。
SpringMVC主要组件:
1. DispatcherServlet:前端控制器,统一处理请求分发
2. HandlerMapping:映射请求到对应的处理器
3. HandlerAdapter:适配处理器执行具体方法
4. Handler:处理器(Controller),业务逻辑处理
5. ViewResolver:解析视图名到具体视图
6. View:渲染数据并返回响应
7. Interceptor:拦截器,处理请求前后逻辑
记忆方法:“前控(DispatcherServlet)找映射(HandlerMapping),适配(HandlerAdapter)处理器(Handler),视图解析(ViewResolver)加渲染(View),拦截(Interceptor)前后做处理”。按请求流转顺序串联:请求进入→查找映射→执行处理→视图渲染,拦截器贯穿全程。
SpringMVC运行流程:
1. 客户端发送请求至DispatcherServlet
2. DispatcherServlet调用HandlerMapping获取Handler
3. 再调用HandlerAdapter执行Handler(Controller)
4. Handler返回ModelAndView给DispatcherServlet
5. DispatcherServlet请求ViewResolver解析视图
6. ViewResolver返回具体View
7. DispatcherServlet渲染View并响应客户端
记忆方法:“请求到 /前端控制器/ (DispatcherServlet),映射(HandlerMapping)找处理器, /适配器/ (HandlerAdapter)来执行,返回 /数据视图/ (ModelAndView), /视图解析器/ (ViewResolver)渲染(View)后响应”。按“请求进入→处理匹配→执行逻辑→视图处理→响应返回”的顺序记忆。
Spring Bean自动装配方式:
1. byName:按属性名匹配Bean(属性名与Bean的id一致)
2. byType:按属性类型匹配Bean(需保证同类型Bean唯一)
3. constructor:构造器注入,按构造器参数类型匹配
4. autodetect:先尝试constructor,再尝试byType(已废弃)
记忆方法:“名(byName)型(byType)构造(constructor)”,按“名称匹配-类型匹配-构造器注入”逻辑记忆,重点区分byName(依赖id)和byType(依赖类型)的核心差异。
Spring框架中常用的设计模式:
1. 工厂模式:BeanFactory、ApplicationContext(创建Bean实例)
2. 单例模式:默认的Bean实例(scope=“singleton”)
3. 代理模式:AOP中的JDK动态代理和CGLIB代理
4. 模板方法模式:JdbcTemplate、RestTemplate等(固定流程+钩子方法)
5. 观察者模式:事件监听机制(ApplicationEvent、ApplicationListener)
6. 适配器模式:HandlerAdapter(适配不同处理器)
7. 装饰器模式:BeanWrapper(包装Bean增强功能)
记忆方法:“工(工厂)单(单例)代(代理)模(模板),观(观察者)适(适配器)装(装饰器)”,结合各模式在Spring中的典型应用场景辅助记忆。
不是。
单例bean在Spring中是全局共享的,但线程安全与否取决于bean自身实现:若bean是无状态的(无成员变量或成员变量不可变),则线程安全;若有可修改的成员变量,则线程不安全。
记忆方法:“单例共享,安全看状态”——单例是共享实例,线程安全与否由bean是否有可变状态决定。
Spring 事务实现方式主要有两种:
TransactionTemplate
或 PlatformTransactionManager
)@Transactional
注解或 XML 配置声明事务记忆方法:“编程手动控,声明注解通”——编程式需手动控制事务,声明式通过注解等方式更便捷通用。
Spring定义了7种事务传播行为:
记忆方法:“需(REQUIRED)支(SUPPORTS)强(MANDATORY),新(REQUIRES_NEW)不(NOT_SUPPORTED)绝(NEVER)套(NESTED)”——取每种行为首字/核心含义串联,辅助记忆7种类型。
Spring事务失效的常见情况:
@Transactional
仅对public方法生效RuntimeException
和Error
NOT_SUPPORTED
等会使事务失效记忆方法:“非公自捕错类型,未配传播有问题”——浓缩关键失效场景,便于记忆。
Spring拦截器(Interceptor)和过滤器(Filter)的区别主要有:
记忆方法:“过Servlet拦Spring,时机前后范围清”——过滤器属于Servlet,拦截器属于Spring;执行时机和处理范围有明确区分。
CAP理论是分布式系统设计中的基础理论,它指出分布式系统无法同时满足以下三个特性:
- 一致性(Consistency):所有节点数据实时保持一致
- 可用性(Availability):任何请求都能收到非错误响应
- 分区容错性(Partition tolerance):网络分区时系统仍能运行
实际设计中需根据场景三选二:
- 记忆法:“一分区,两选一”。只要存在网络分区(P必选),就只能在一致性和可用性之间做选择。比如银行系统优先保证一致性,社交软件优先保证可用性。
SpringCloud常用组件:
- Eureka/Consul/Nacos:服务注册与发现
- Ribbon~~/LoadBalance~~:负载均衡
- Feign/OpenFeign:服务调用
- Hystrix~~/Resilience4j~~:熔断降级
- Gateway~~/Zuul~~:API网关
- Config/Nacos:配置中心
- Bus:消息总线
记忆法:“注调均断,网关配总”
注(注册发现)、调(服务调用)、均(负载均衡)、断(熔断降级)、网关(API网关)、配(配置中心)、总(消息总线)。
SpringBoot常用注解:
- @SpringBootApplication:主启动类注解(组合了@Configuration、@EnableAutoConfiguration、@ComponentScan)
- @RestController:标识REST接口控制器(组合了@Controller和@ResponseBody)
- @RequestMapping/@GetMapping/@PostMapping等:映射请求路径和方法
- @Autowired:自动注入依赖
- @Service/@Repository/@Component:标识服务层、数据访问层、通用组件
- @Value:注入配置属性
- @Configuration:标识配置类
- @Bean:定义Bean对象
记忆法:“主启控,请求注,分层配”
主启(@SpringBootApplication)、控(@RestController等控制器注解)、请求(@RequestMapping等)、注(@Autowired依赖注入)、分层(@Service等分层注解)、配(@Configuration等配置相关)。
SpringBoot自动装配原理核心是:通过注解(注解)+ SPI(服务发现机制)实现自动配置。
过程:
1. @SpringBootApplication包含@EnableAutoConfiguration,触发自动配置
2. 扫描classpath下META-INF/spring.factories文件,加载自动配置类(XXXAutoConfiguration)
3. 自动配置类通过@Conditional条件注解(如@ConditionalOnClass)判断是否生效
4. 生效的配置类通过@Bean向容器注入组件
记忆法:“注解启,文件找,条件判,Bean注入”
(注解启动 -> 扫描配置文件 -> 条件判断生效 -> 注入Bean)
考察点: 对 Nacos 底层一致性协议的深入理解。
回答要点:
* 支持原理:
* 默认模式(AP): 用于**服务发现**场景,采用自研的 Distro 协议,保证高可用和分区容错性,性能更高。
* CP 模式: 用于**配置管理**或需要强一致性的场景(如领导者选举),采用 Raft 协议,保证数据一致性。
* 如何切换: 可以通过 Nacos 的 API 或控制台,修改特定服务的**元数据**:
curl -X PUT '$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP'
RabbitMQ的Topic模式中,#和*都是用于匹配RoutingKey的通配符:
- #:匹配0个或多个单词(单词间用.分隔),例如“a.#”可匹配“a.b”、“a.b.c”、“a”
- *:仅匹配1个单词,例如“a.*”只能匹配“a.b”,不能匹配“a”或“a.b.c”
记忆法:“#多*单”
(#能匹配多个单词,*只能匹配单个单词)
RabbitMQ保障消息不丢失需从**生产者、 broker(服务器)、消费者**三个环节入手,核心是通过持久化和确认机制避免各环节丢失:
channel.confirmSelect()
开启确认模式,Broker收到消息后会返回确认(ack)或失败(nack)通知,生产者根据结果重试未成功发送的消息。durable=true
,确保队列元数据(名称、属性)在Broker重启后不丢失。deliveryMode=2
(持久化标志),确保消息内容被写入磁盘(而非仅存内存),Broker重启后可恢复。channel.basicAck()
),Broker收到后才删除消息。若消费者崩溃未确认,Broker会重新投递消息。记忆法:生确存,服久群,消手幂
(生产者确认发送,Broker持久化+集群;消费者手动确认+幂等处理)
RabbitMQ确保消息不被重复消费的核心是实现**消费幂等性**,即同一条消息多次消费的结果与一次消费一致。常用方案:
记忆法:“唯一标,库约束,状态控”
(唯一标识校验、数据库约束、状态机控制)
考察点: 对顺序性这一难题的解决方案。
回答要点:
* 问题根源: 多个消费者并发消费一个队列,自然会导致顺序错乱。
* 解决方案:
1. 单一队列,单一消费者: 保证绝对顺序,但严重牺牲性能,不实用。
2. 分组: 将需要保证顺序的消息**通过路由键确保它们始终被发送到同一个队列**。例如,将同一订单 ID 的所有消息路由到同一个队列,然后为这个队列分配**唯一的一个消费者**来处理(可以在消费者内部用内存队列做二次排序)。这是最常用的方案。
Kafka保障消息不丢失需从**生产者、Broker、消费者**三个环节防控:
acks=all
:确保消息被所有ISR副本确认后才返回成功retries>0
):失败时自动重试发送replication.factor≥3
:避免单点故障min.insync.replicas≥2
:确保消息写入足够副本retention.ms
):防止消息提前过期enable.auto.commit=false
):处理完成后手动提交offset记忆法:“生确重,服多副,消手提”
(生产者确认+重试,服务器多副本,消费者手动提交offset)
考察点: 对顺序性这一常见需求的解决方案。
回答要点:
* 全局顺序: 性能代价极大,**几乎不用**。只能通过 1个Topic + 1个Partition + 1个Consumer 来实现。
* 分区顺序(**常用方案**): Kafka 只能保证在单个分区内消息是有序的。因此,要实现业务层面的顺序性,必须确保需要保序的一类消息(例如同一个订单ID的所有操作)都被发送到**同一个分区**。方法是在发送消息时**指定同一个 Key**。
考察点: 线上问题处理能力。
回答要点:
1. 临时紧急扩容:
* 扩容消费者: 增加 Consumer 实例数量,提升消费能力。
* 扩容队列: 如果队列容量已满,可以临时增加队列的 max-length
(如果业务可接受丢弃头部消息)或扩容集群。
2. 排查原因:
* 检查消费者: 是否是消费者出了 bug 导致消费过慢或卡死?查看日志和监控。
* 检查消息: 是否是消息量突然激增(如促销活动)?是否是生产者出了问题在疯狂发消息?
3. 后续优化:
* 修复消费者 Bug。
* 优化消费逻辑,提升单条消息的处理速度(如批量处理)。
* 做好监控和预警,在积压初期就发现问题。
考察点: 对消息可靠性级别的控制。
回答要点:
* acks=0: 生产者发送后**不等任何确认**就认为成功。**吞吐最高,但可能丢失消息**。
* acks=1(默认): 生产者等待 Leader 副本成功写入本地日志就认为成功。**折中方案**。如果 Leader 刚写入就宕机且数据未同步到 Follower,则可能丢失消息。
* acks=all(或 acks=-1
): 生产者等待 Leader 和所有 ISR(In-Sync Replicas) 副本都成功写入才认为成功。**最可靠,但延迟最高,吞吐最低**。
考察点: 对生产者分区策略的了解。
回答要点:
1. 指定 Partition: 直接发送到指定分区。
2. 指定 Key(**最常用**): 提供 key
,对 key
进行哈希(默认),根据哈希值决定分配到哪个分区。**保证同一个 Key 的消息总是进入同一个分区,从而实现顺序性**。
3. 轮询(Round-Robin): 如果未提供 key
,则默认以轮询方式均匀分布到所有分区。
ElasticSearch的倒排索引是其快速检索的核心机制,本质是“从词到文档的映射”:
记忆法:“分词建映射,查词找文档”
(先分词建立词条到文档的映射,查询时通过词条快速找到对应文档)
text
和 keyword
数据类型的区别是什么?考察点: 对 ES 字符串处理方式的理解。这是**必问**题。
回答要点:
* keyword
类型:
* 不分词: 将整个字符串作为一个完整的 term 存入倒排索引。
* 用于: 精确匹配(term
查询)、**排序**(sorting)、**聚合**(aggregations)、**过滤**(filtering)。
* 例如: 邮箱地址、用户ID、标签、状态码。
* text
类型:
* 分词: 字符串会被**分析器(Analyzer)** 拆分成一个个词条(term)后再存入倒排索引。
* 用于: 全文搜索(match
查询),支持模糊查询、相关性评分。
* 通常包含多值字段: 一个 text
字段通常会有一个内置的 keyword
子字段(fieldname.keyword
),用于上述精确匹配等操作。
* 例如: 邮件正文、商品描述、日志内容。
考察点: 对数据分布、高可用和性能之间权衡的理解。
回答要点:
* 分片的作用:
1. 水平拆分数据: 允许索引的大小超过单台机器的硬件限制。
2. 分布式操作: 允许将操作(读写、搜索)分发到所有分片上,并行执行,提升吞吐和性能。
* 副本的作用:
1. 高可用: 在主分片宕机时,其副本可以提升为主分片,防止数据丢失和服务中断。
2. 提升读取吞吐量: 搜索请求可以在所有副本之间进行负载均衡。
* 分片数设置:
* 这是一个**预先规划**的重要决策,因为**主分片数在索引创建后无法修改**(除非重建索引 Reindex)。
* 原则:
1. 考虑数据总量: 每个分片大小建议在 20GB - 40GB 之间,最大不建议超过 50GB。
2. 考虑集群节点数: 确保分片数能被节点数整除,以便分片在节点间均匀分布。
3. 避免过多分片: 每个分片都有开销(内存、CPU、文件句柄)。过多的分片会导致集群性能下降,恢复变慢。
ElasticSearch深度分页(如查询第10000页以后的数据)因默认from+size方式存在性能问题(需加载前N条数据排序),推荐方案:
scroll滚动查询:
初次查询生成scroll_id,后续通过scroll_id分批获取数据(类似游标),适合批量导出场景。
缺点:非实时,占用服务器资源较久。
search_after:
以上一页最后一条数据的排序字段值作为条件,查询下一页,支持实时数据。
需指定唯一排序字段(如_id),适合实时分页场景。
避免过深分页:
业务上限制最大分页深度(如最多查100页),或用游标、滚动替代传统分页。
记忆法:“滚批导,后实时,限深度”
(scroll适合批量导出,search_after适合实时场景,业务限制深度)