分布式限流与降级与分布式任务调度

共 27 题
📑 题目列表 27 题
#
★★★

1. @Bulkhead(信号量隔离/线程池隔离)

请解释 Resilience4j 的 @Bulkhead(信号量隔离/线程池隔离)机制?

  • Bulkhead 的两种隔离
  • 信号量隔离与线程池隔离
  • 并发控制与失败快速失败

Resilience4j 的 @Bulkhead(舱壁隔离)用于隔离故障,防止一个依赖的故障拖垮整个系统,通过限制对该依赖的并发调用数实现。它有两种实现:信号量隔离(SemaphoreBulkhead)——用 Semaphore 限制同时执行的调用数,不额外创建线程,主线程执行,开销小、适合同步调用;当并发超过限制时,后续调用快速失败或排队。线程池隔离(ThreadPoolBulkhead)——用独立线程池执行调用,每个依赖有独立线程池,通过线程池大小限制并发,超出的调用丢入队列或拒绝,适合异步/阻塞调用,隔离更彻底(线程池耗尽不影响其他依赖),但开销更大。配置参数:maxConcurrentCalls(信号量)或 maxThreadPoolSize(线程池)、maxWaitDuration(等待时间)、queueCapacity(队列容量)等。@Bulkhead 注解应用于方法,配合限流保护依赖。选择:同步、低开销用信号量;异步、需要彻底隔离用线程池。

Bulkhead 的核心是"隔离"——用并发上限把故障限制在单个依赖内。信号量隔离省资源,线程池隔离更彻底,根据调用类型(同步/异步)与隔离需求选择。它是舰船级的"舱壁"思想。

#
★★★

2. RateLimiter(Guava)的本地限流

请介绍 Guava RateLimiter 的本地限流机制?

  • 令牌桶的实现
  • 平滑与突发
  • 本地限流的局限

Guava 的 RateLimiter 是本地限流工具,基于令牌桶(Token Bucket)算法:以固定速率向桶中填充令牌,每次请求消耗一个令牌,令牌耗尽则请求被限流(阻塞等待或拒绝)。RateLimiter 有两种:create(permitsPerSecond) 平滑限流(稳态速率,一次一个令牌,突发时会平滑);create(permitsPerSecond, warmupPeriod) 预热限流(warmup,启动时速率逐渐提升到目标,避免冷启动突发)。RateLimiter 支持 tryAcquire()(非阻塞,获取不到立即返回 false)与 acquire()(阻塞等待令牌)。它实现"秒级平滑限流",把突发流量平滑化。局限:是"本地/单机"限流,每个 JVM 实例各自独立,不共享全局配额,多实例部署时无法做集群级限流(需用 Redis 等分布式限流);且基于 JVM 内存,实例重启后状态丢失。适用单机限流、本地保护;集群限流需结合分布式令牌桶。

Guava RateLimiter 是经典的"单机令牌桶",用平滑速率限流。关键局限是"本地性"——多实例无法共享配额,需分布式限流补充。理解其模型与局限是选型基础。

#
★★★

3. Semaphore 的并发限流

请介绍 Semaphore 的并发限流机制?

  • Semaphore 的许可机制
  • 并发数限制
  • 与限流场景的适用

Semaphore(信号量)是 Java 并发工具,用于限制同时访问某资源的线程数。它维护一个许可计数,acquire() 获取许可(无许可则阻塞等待),release() 释放许可。通过设定许可数(permits),可限制"同时执行的并发数",常用于"并发限流"——限制某个资源/代码段的并发访问量,防止过量并发导致资源耗尽。与 RateLimiter(限 QPS)不同,Semaphore 限制的是"并发数"(同时进行的请求数),而非"单位时间请求数"。Semaphore 是"本地"限流,适用于单 JVM 内的并发控制(如限制连接池使用、限制并发任务数);多实例场景需分布式信号量(如 Redis 分布式锁、ZK 实现)。注意:Semaphore 阻塞等待可能造成线程阻塞,需合理设置超时(tryAcquire(timeout))避免长期阻塞。适用场景:限制数据库连接、限流并发任务、保护临界资源。

Semaphore 限的是"并发数"而非"速率",用许可计数控制同时访问数。它是本地并发控制工具,适合单机资源保护,多实例需分布式信号量。

#
★★★

4. Sentinel 集群限流如何借助 token server 统一分配令牌,token client/server 模式与嵌入模式有何差异与单点风险

Sentinel 集群限流如何借助 token server 统一分配令牌,token client/server 模式与嵌入模式有何差异与单点风险?

  • 集群限流的 token server/client
  • 嵌入模式与独立模式
  • token server 的单点风险

Sentinel 集群限流通过"token server 统一分配令牌"实现跨实例的全局限额:集群中的 token server 持有全局配额,各业务实例(token client)在限流时向 token server 请求令牌,token server 分配/拒绝,从而让多个实例共享同一限额,避免单实例本地限流导致总量超限。token client/server 模式与嵌入模式的差异:token client 模式——业务实例作为 client,向独立的 token server 请求令牌,token server 独立部署或嵌入(可与某个实例同部署);token server 模式——某实例作为 token server 统管配额,其他实例作为 client。嵌入模式:token server 逻辑嵌入到某个业务进程中(不单独部署),省资源但该进程故障影响集群限流;独立模式:token server 独立部署,隔离性好但增加部署复杂度。单点风险:token server 是集群限流的单点——若 token server 故障,所有依赖它的限流都会失败。为防单点,Sentinel 支持 token server 高可用(如通过配置多个、故障转移、或用 Redis 等实现分布式令牌),以及"降级"(token server 不可用时 client 降级为本地限流或放行)。核心是"统一配额 + 防单点降级"。

集群限流把"配额"集中到 token server,client 请求令牌实现全局限额。嵌入/独立模式权衡资源与隔离,单点风险靠"高可用 + 降级"缓解。理解 token server 的职责是掌握集群限流的关键。

#
★★★

5. XXL-JOB 的路由策略(轮询、随机、一致性哈希、分片广播、故障转移)各自适用什么业务场景

XXL-JOB 的路由策略(轮询、随机、一致性哈希、分片广播、故障转移)各自适用什么业务场景?

  • 各路由策略的机制
  • 适用场景
  • 选择依据

XXL-JOB 的调度中心把任务指派给执行器,路由策略决定"选哪个执行器执行"。轮询(Round Robin):按顺序轮流选择执行器,负载均衡,适合"各执行器处理能力相同、任务无状态"的场景。随机(Random):随机选择执行器,负载较分散,适合"执行器无差异、任务随意"的场景。一致性哈希(Consistent Hash):按任务 ID 哈希到固定执行器,同一任务始终落在同一执行器,适合"任务状态需要固定在某节点"(如任务依赖本地缓存、有状态)的场景。分片广播(Sharding Broadcast):任务同时分发给所有执行器,每个执行器按分片参数(shardingIndex/shardingTotalCount)处理自己负责的数据分片,适合"大数据量并行处理"(如按分片处理一批数据)的场景。故障转移(Failover):选择可用的执行器,故障时自动切换,适合"任务需可靠执行、单点失败可转移"的场景。选择依据:看图任务是否有状态、是否需要并行、是否需要可靠执行。轮询/随机适无状态负载均衡,一致性哈希适有状态,分片广播适并行大数据,故障转移适可靠性。

路由策略按"任务状态、负载均衡、并行度、可靠性"选择。无状态用轮询/随机,有状态用一致性哈希,并行大数据用分片广播,可靠执行用故障转移。理解各策略机制是调度选型基础。

#
★★★

6. 分布式限流的常见算法(令牌桶/漏桶/滑动窗口)

请介绍分布式限流的常见算法(令牌桶/漏桶/滑动窗口)?

  • 令牌桶算法
  • 漏桶算法
  • 滑动窗口算法

分布式限流常见算法:令牌桶(Token Bucket)——按固定速率往桶中放令牌,请求消耗令牌,令牌为空则拒绝;允许一定突发(桶中积累的令牌可支持突发),适合"允许突发但总体限速"(如 Guava RateLimiter、Redis 令牌桶)。漏桶(Leaky Bucket)——请求倒入桶中,按固定速率流出,桶满则丢弃;输出恒定速率,平滑突发,适合"要求输出绝对平滑"(如流量整形),但不允许突发(即使桶空也只能按固定速率处理)。滑动窗口(Sliding Window)——把时间划分为窗口,统计窗口内请求数,超过阈值拒绝;滑动窗口比固定窗口更平滑(避免固定窗口边界突刺),用计数器/Redis 实现,适合"精确统计给定时间窗口内的请求量"。分布式实现:令牌桶/漏桶用 Redis(Lua 脚本原子操作),滑动窗口用 Redis ZSET 或计数器。选择:允许突发、平滑限速用令牌桶;要求恒定速率用漏桶;需要精确时间窗口统计用滑动窗口。三者可结合,是分布式限流的基础。

令牌桶"限平均速率 + 允许突发",漏桶"恒定速率平滑输出",滑动窗口"精确统计窗口请求"。分布式实现依托 Redis 原子操作。理解算法差异是选型与实现的基础。

#
★★★

7. 大规模(万级以上)任务的调度性能瓶颈通常出现在哪里,分片治理、批量触发与线程池隔离如何应对

大规模(万级以上)任务的调度性能瓶颈通常出现在哪里,分片治理、批量触发与线程池隔离如何应对?

  • 调度瓶颈的来源
  • 分片治理
  • 批量触发与线程池隔离

大规模(万级以上)任务的调度性能瓶颈通常出现在:调度中心的调度频率与数据库压力(每条任务触发都要查库、更新状态,任务量大时 DB 成为瓶颈)、执行器的注册/心跳与任务分发(大量任务分发导致网络与调度线程压力)、任务指纹与幂等(重复触发)、以及执行器线程池耗尽(任务过多时执行器线程被占满)。应对手段:分片治理——把海量任务按分片拆到多个执行器并行处理,每个执行器处理自己的分片,避免单点;批量触发——把同一时刻的多个任务合并批量触发/批量拉取,减少调度次数与 DB 交互;线程池隔离——执行器用独立线程池处理任务,限制并防止任务间互相影响,避免某个慢任务耗尽线程。此外,调度中心高可用、任务分库、合理调度间隙(cron 粒度)、任务结果异步回写等也能缓解。核心是"把调度压力分摊到分片与执行器、减少调度中心与 DB 的集中交互、用线程池隔离保护执行器"。

大规模调度瓶颈在"调度中心/DB 集中压力"与"执行器线程耗尽"。靠"分片分散 + 批量减少交互 + 线程池隔离"缓解,是调度系统水平扩展的关键。

#
★★★

8. 定时任务在多实例下如何保证幂等与防重入,分布式锁、数据库唯一约束与状态机各如何兜底

定时任务在多实例下如何保证幂等与防重入,分布式锁、数据库唯一约束与状态机各如何兜底?

  • 多实例的重复执行
  • 分布式锁防重入
  • 数据库唯一约束与状态机兜底

多实例部署的定时任务,同一任务可能被多个实例同时触发(重复执行),需保证幂等与防重入。方案分层兜底:分布式锁(如 Redis 锁、ZK 锁)——任务执行前先获取分布式锁,只有拿到锁的实例执行,其他实例跳过,从"入口"防止并发执行;但锁可能过期误判,需配合幂等。数据库唯一约束——任务处理的数据用唯一键(如业务单号、任务批次号)建唯一索引,并发插入时只有一个成功,其余因唯一冲突失败/跳过,从"数据层"兜底;例如"已处理记录表"用唯一键去重。状态机——任务/记录用状态字段(如 PENDING/RUNNING/DONE)管理,执行前先原子地把状态从 PENDING 改为 RUNNING(用条件更新,如 update ... set status='RUNNING' where status='PENDING'),只有成功切状态的实例才执行,执行完置 DONE;状态机保证"同一任务只被一个实例从初始状态推进",从"业务状态"兜底。综合:分布式锁防"入口并发",唯一约束防"数据重复",状态机防"状态重复推进",三者叠加实现多实例下的幂等与防重入。

防重入是"入口 + 数据 + 状态"三层兜底:锁挡并发、唯一键挡重复、状态机挡重复推进。多实例用"条件更新状态"是最可靠的原子防重入手段。

#
★★

9. 热点参数限流(ParamFlow)如何针对特定参数值单独限流,参数例外项与统计窗口如何配置

Sentinel 热点参数限流(ParamFlow)如何针对特定参数值单独限流,参数例外项与统计窗口如何配置?

  • 热点参数限流
  • 参数例外项
  • 统计窗口配置

Sentinel 的热点参数限流(ParamFlow)用于针对"特定参数值"单独限流,而不是对所有请求统一限流。它通过"热点参数规则"指定:对某个资源(方法)的某个参数位置(参数索引),按参数值维度统计 QPS,对每个参数值设置独立的限流阈值——例如对某个接口的"userId"参数,每个用户单独限流,防止单个热点用户耗尽资源。参数例外项(paramFlowItem):针对特定参数值设置单独的限流阈值(可以高于或低于默认),例如默认每个用户限流 100,但 VIP 用户例外项限流 1000,普通用户限流 10。统计窗口:热点参数限流用独立的统计窗口(参数维度),配置窗口时长(如 1 秒)与具体阈值,Sentinel 按参数值在窗口内统计请求数,超过阈值则拒绝。配置项:资源名、参数索引(argIndex)、单机阈值(threshold)、统计窗口时长(statisticDurMs)、以及参数例外项列表(paramFlowItem,含具体参数值与阈值)。热点参数限流适合"按 key 维度防刷、防热点"场景。

热点参数限流把"限流粒度"从"资源"细化到"参数值",用参数例外项定制单值阈值,用统计窗口控制统计时间。它是 Sentinel 精细化限流的核心,适合按用户/商品等维度防热点。

#
★★

10. 熔断的状态机(Closed/Open/Half-Open)

请介绍熔断的状态机(Closed/Open/Half-Open)?

  • 三个状态
  • 状态转换条件
  • 熔断恢复

熔断器(Circuit Breaker)有三种状态:Closed(关闭)——正常状态,请求正常放行,同时统计失败率/失败数;当失败率超过阈值(如 50%)或失败数达到阈值时,熔断器触发切换到 Open。Open(打开)——熔断状态,请求被直接拒绝(快速失败),不调用下游,保护依赖;维持一段时间(如通过等待时长)后,进入 Half-Open。Half-Open(半开)——试探状态,放行少量探针请求测试下游是否恢复;若探针请求成功,则熔断器恢复为 Closed(恢复正常);若失败,则回到 Open(继续熔断)。状态转换由"失败率/失败数阈值"(闭环→开)、"等待时长"(开→半开)、"探针成功率"(半开→闭环/开)驱动。熔断用于隔离故障依赖、快速失败、防止级联故障。工程上(如 Resilience4j、Hystrix)通过配置失败率阈值、熔断等待时间、探针请求数等实现。状态机保证"故障时快速失败,恢复时渐进试探"。

熔断状态机是"Closed 正常 → Open 熔断 → Half-Open 试探 → 恢复/再熔断"。核心是"失败率触发熔断 + 等待后试探 + 成功率恢复",实现故障隔离与自动恢复。

#
★★

11. 网关层限流如何在 Spring Cloud Gateway 的 RequestRateLimiter 中借助 Redis + Lua 实现分布式令牌桶

网关层限流如何在 Spring Cloud Gateway 的 RequestRateLimiter 中借助 Redis + Lua 实现分布式令牌桶?

  • RequestRateLimiter 过滤器
  • Redis 令牌桶 + Lua 原子性
  • 限流配置

Spring Cloud Gateway 的 RequestRateLimiter 过滤器实现网关层限流,可通过 Redis + Lua 实现分布式令牌桶。实现原理:RequestRateLimiter 使用 RedisRateLimiter,它基于 Redis 存储令牌桶状态,用 Lua 脚本原子地执行"取令牌"操作——Lua 脚本在 Redis 中一次性读取令牌、扣减令牌、并更新补充时间,保证分布式环境下的原子性(避免并发扣减)。配置:spring.cloud.gateway.routes[].filters[].name=RequestRateLimiter,参数 redis-rate-limiter.replenishRate(令牌补充速率,每秒补充数)、redis-rate-limiter.burstCapacity(桶容量,允许突发)、redis-rate-limiter.requestedTokens(每次请求消耗令牌数),通过 KeyResolver 决定限流维度(如按 IP、用户、路由)。Redis 存储令牌桶状态(current tokens + last refill time),多实例共享同一 Redis,实现集群级限流。Lua 保证"读-扣-补"操作的原子性,避免并发下超标。这是网关层分布式限流的典型实现。

RequestRateLimiter + RedisRateLimiter 把"令牌桶"状态放 Redis,用 Lua 原子扣减,实现多实例共享的分布式限流。核心是"Redis 存状态 + Lua 保原子 + KeyResolver 定维度"。

#
★★

12. 调度与业务解耦的常见做法是把任务投递到消息队列削峰,这种模式对一致性与时延有何影响

调度与业务解耦的常见做法是把任务投递到消息队列削峰,这种模式对一致性与时延有何影响?

  • 任务投递 MQ 的削峰
  • 对一致性的影响
  • 对时延的影响

把调度任务投递到消息队列(MQ)削峰,是"调度与业务解耦"的常见做法:调度中心只负责把任务"投递"到 MQ(异步入队),业务执行由消费者异步消费,从而把突发的任务量削峰、解耦调度与执行。对一致性的影响:从"同步调用"变为"异步消息",引入最终一致概念——调度中心投递成功即返回,但任务是否执行、执行结果如何由消费者异步保证,可能延迟才可见;需要消费者幂等(消息可能重复)、可靠消费(任务不丢)、以及失败重试/死信处理,保证任务最终被执行。对时延的影响:消息队列引入排队与消费延迟,任务从"投递"到"执行"的时延增加(取决于队列积压与消费速度),不适合对实时性要求极高的任务;但削峰后系统更稳定,牺牲的时延换取的是吞吐与稳定性。因此该模式适合"可容忍异步延迟、突发量大"的任务,需配套幂等、可靠消费与监控。核心权衡是"用异步+最终一致+时延换取削峰与解耦"。

任务投 MQ 削峰的本质是"同步改异步",带来"最终一致 + 时延增加",换取"削峰 + 解耦"。需用幂等与可靠消费保证任务最终执行,适合可容忍延迟的场景。

#
★★

13. 限流指标的 Prometheus 暴露

如何将限流指标暴露给 Prometheus?

  • Prometheus 指标格式
  • Micrometer/Actuator 集成
  • 限流指标与告警

将限流指标暴露给 Prometheus,通常通过 Micrometer + Spring Boot Actuator:在 Spring Boot 应用中引入 micrometer-registry-prometheus,Actuator 会在 /actuator/prometheus 端点暴露 Prometheus 格式的指标(text/plain 格式,Prometheus 可抓取)。限流框架(如 Resilience4j、Sentinel)通过 Micrometer 输出指标:Resilience4j 提供 Resilience4jMetrics(如熔断器的状态、调用次数、成功率,限流器的可用许可),Sentinel 提供 SentinelMetric 或通过 Actuator 端点暴露。指标名称如 resilience4j.bulkhead.available.concurrent.callsresilience4j.ratelimiter.available.permissions 等。部署时配置 Prometheus 抓取 /actuator/prometheus,再接入 Grafana 展示与 Alertmanager 告警(如限流拒绝过多、熔断器打开告警)。核心是"用 Micrometer 把限流指标转成 Prometheus 格式,通过 Actuator 端点暴露,Prometheus 抓取 + Grafana/告警"。限流指标用于观察限流效果与系统负载,指导限流阈值调整。

暴露限流指标的关键是"Micrometer 桥接 Prometheus + Actuator 端点"——限流框架输出指标,Prometheus 抓取,Grafana 展示与告警。这是可观测性建设的一环。

#
★★

14. @CircuitBreaker/@Retry/@RateLimiter 的工程应用

请介绍 Resilience4j 的 @CircuitBreaker/@Retry/@RateLimiter 的工程应用?

  • 三个注解的用途
  • 组合使用
  • 场景与配置

Resilience4j 提供多个容错注解,@CircuitBreaker(熔断)——保护下游依赖,失败率超阈值时熔断,快速失败,防止故障扩散;@Retry(重试)——对临时失败的操作自动重试(配置重试次数、间隔、退避),处理瞬时故障;@RateLimiter(限流)——限制单位时间的调用次数,防止过量请求打爆下游。工程应用:常组合使用,例如对下游调用同时加 @CircuitBreaker + @Retry + @RateLimiter——@Retry 处理瞬时失败(重试),@RateLimiter 控制速率,@CircuitBreaker 在持续失败时熔断。注解可配置参数:@CircuitBreaker 的 failureRateThreshold、waitDurationInOpenState;@Retry 的 maxAttempts、waitDuration、backoff;@RateLimiter 的 limitForPeriod、limitRefreshPeriod。使用分隔符 @CircuitBreaker(name="cb") 等,会自动创建实例。适用场景:依赖外部服务/数据库的调用,用熔断防故障扩散、重试处理瞬时、限流防过载。组合时注意重试与熔断的交互(重试次数过多可能触发熔断),需合理配置。

三个注解分别管"熔断、重试、限流",工程上常组合保护下游调用。配置需权衡重试与熔断的交互,避免重试风暴触发熔断。理解各自职责与组合是容错设计的关键。

#
★★

15. @Fallback 方法的边界

请解释 Resilience4j 的 @Fallback 方法的边界?

  • @Fallback 的用途
  • 方法签名要求
  • 与容错注解的配合

Resilience4j 的 @Fallback 用于在容错机制(熔断、重试、限流等)触发或调用失败时,提供一个降级方法,返回默认值或兜底逻辑。@Fallback 的边界:方法签名必须与原方法匹配或兼容——fallback 方法须与原方法返回类型相同(或可转为父类型),参数可包括原方法参数以及可选的异常参数(fallback 方法可接收触发的异常,如 fallback(Exception e)),但不能与有 @Fallback 的原方法冲突(原方法不能自己也有 @Fallback)。@Fallback 必须在同一类或通过可配置的 fallbackMethod 指定,且 fallback 方法不能是私有的(需可访问)。它只作为"兜底",不参与重试/熔断的次数统计,且不能替代原方法的业务逻辑。边界:fallback 只在"容错触发或异常"时执行,正常成功路径不执行;fallback 方法的异常处理需注意(fallback 自身抛异常会导致整体失败)。工程上 @Fallback 用于提供降级响应,保证调用失败时系统仍可响应。

@Fallback 的边界是"签名匹配 + 兜底触发 + 不参与统计"。它只在容错触发时返回降级值,签名(返回类型/异常参数)需匹配,且不替代原逻辑。理解其边界是正确使用降级的关键。

#
★★

16. @TimeLimiter 的 timeoutDuration 与线程池/信号量隔离组合时,超时后线程如何被中断或释放

Resilience4j 的 @TimeLimiter 的 timeoutDuration 与线程池/信号量隔离组合时,超时后线程如何被中断或释放?

  • @TimeLimiter 的超时控制
  • 超时后线程的取消
  • 与隔离的组合

Resilience4j 的 @TimeLimiter 用于限制调用超时:设置 timeoutDuration(如 3 秒),调用超过该时长则抛 TimeoutException。它与线程池/信号量隔离组合时,超时后的线程处理:@TimeLimiter 通常配合线程池隔离(ThreadPoolBulkhead)使用——调用在独立线程池中执行,@TimeLimiter 在主线程中等待调用结果,超时后主线程抛 TimeoutException 并返回,同时尝试取消(cancel)线程池中的任务线程;若任务无法被中断(如阻塞 IO 不响应中断),线程可能继续运行直到完成,但调用方已超时返回,此时需注意线程是否会泄漏(慢任务后续释放)。信号量隔离时,@TimeLimiter 的取消行为:信号量自身不中断线程,超时取消依赖任务的可中断性(如 Future.cancel(true) 会尝试中断,但中断是否生效取决于任务是否响应中断)。因此超时后的线程释放:由隔离机制(线程池)持有,超时通过 Future 取消尝试中断;若任务不响应中断,线程会被占用至任务结束。工程上需让任务支持中断(响应 InterruptedException),并设置合理超时避免线程长期占用。

@TimeLimiter 超时后调用方返回,但线程的释放取决于"任务是否可中断"与"隔离方式"。线程池隔离用 Future.cancel 尝试中断,信号量隔离不中断线程。核心是让任务响应中断并合理设超时。

#
★★

17. Bucket4j 令牌桶库

请介绍 Bucket4j 令牌桶库?

  • Bucket4j 的令牌桶实现
  • 与 Spring/Redis 集成
  • 限流能力

Bucket4j 是一个 Java 令牌桶限流库,实现令牌桶算法,提供精确的限流能力。它支持两类模型:本地(in-memory)——在 JVM 内的高性能令牌桶;分布式——通过 Redis(Bucket4j 集成 Redis 的 Bucket4j-Redis 模块)把令牌桶状态存在 Redis,实现跨实例的分布式限流,配合 Redisson 的原子操作保证正确性。Bucket4j 的特性:支持平滑限流、突发容量、多维度限流(可按 key 分配独立桶,如按用户、IP)、基于 Bandwidth 配置(容量 + 补充速率)、以及基于消费(consume)API 的阻塞/非阻塞。Bucket4j 可与 Spring(Spring Cloud Gateway 的 RequestRateLimiter 可选实现)、Quarkus 等集成,也常用于业务层限流。相比 Guava RateLimiter,Bucket4j 支持分布式(Redis)与更多扩展;相比 Sentinel,Bucket4j 更专注"令牌桶"本身。工程上用于"精确、可配置、可分布式"的限流场景。

Bucket4j 是"可本地可分布式"的令牌桶库,核心是 Bandwidth 配置 + Redis 分布式支持。它比 Guava 更聚焦分布式限流,比 Sentinel 更专注令牌桶算法本身。

#
★★

18. ElasticJob 如何基于 ZooKeeper 的临时节点实现分片项分配与失效转移,节点宕机后分片如何重平衡

ElasticJob 如何基于 ZooKeeper 的临时节点实现分片项分配与失效转移,节点宕机后分片如何重平衡?

  • ZK 临时节点与分片注册
  • 分片分配与失效转移
  • 宕机后重平衡

ElasticJob 基于 ZooKeeper 实现分布式任务调度与分片。分片项分配:每个任务分成多个分片项(sharding item),ElasticJob 通过 ZK 记录各实例(节点)与分片项的对应关系;实例启动时在 ZK 注册临时节点(/instances/{instanceId}),临时节点与会话绑定,实例宕机时临时节点自动消失。分片分配:ElasticJob 根据存活的实例列表,把分片项均匀分配给各实例(每个实例处理自己的分片),通过 ZK 的选举/协调确定分配。失效转移(failover):当某实例宕机,其临时节点消失,ElasticJob 检测到后,把该实例负责的分片项"转移"给其他存活实例继续执行(failover),保证任务不中断。节点宕机后分片重平衡:宕机实例的临时节点消失触发重新分配,ElasticJob 重新计算存活实例与分片的映射,把失效分片重平衡给正常实例,实现容错。临时节点是"实例存活"的探针,分片分配与重平衡依赖 ZK 的"谁存活"信息。ZooKeeper 提供强一致协调,保证分片分配不冲突。

ElasticJob 用 ZK 临时节点判断"实例存活",分片分配与失效转移基于"存活实例列表"。宕机触发临时节点消失 → 重新协调分片 → 失效分片转移/重平衡,实现高可用。

#
★★

19. Resilience4j 与 Spring Retry 的取舍

请对比 Resilience4j 与 Spring Retry 的取舍?

  • 两者的能力范围
  • 重试机制的差异
  • 选型场景

Resilience4j 与 Spring Retry 都是 Java 失败处理库,但定位不同。Spring Retry:专注于"重试"——提供 @Retryable 注解与 RetryTemplate,支持重试次数、间隔、退避、异常匹配、恢复方法(recover),适合"对调用做简单重试"的场景,与 Spring 深度集成,轻量。Resilience4j:功能更全——提供熔断、限流、重试、超时、舱壁(隔离)等多种容错能力,是一个完整的"容错框架",重试只是其一,支持注解与函数式 API,可组合(如重试+熔断)。取舍:只需重试、场景简单、想在 Spring 中轻量使用 → Spring Retry;需要"熔断+限流+舱壁+超时"等多重容错、或需要组合容错策略 → Resilience4j。Resilience4j 比 Spring Retry 更重但更全面,支持函数式(Decorate)与更细粒度(如按异常、按结果策略)。工程上,简单重试用 Spring Retry,综合容错用 Resilience4j。

Spring Retry 是"重试专用、轻量",Resilience4j 是"综合容错框架、重试只是其一"。选型看"只需要重试"还是"需要多能力组合"。

#
★★

20. Sentinel 与 Resilience4j 在设计理念(统计滑动窗口 vs 函数式装饰)、规则动态化与生态上的选型对比

请对比 Sentinel 与 Resilience4j 在设计理念(统计滑动窗口 vs 函数式装饰)、规则动态化与生态上的选型?

  • 设计理念差异
  • 规则动态化
  • 生态与选型

Sentinel 与 Resilience4j 都是 Java 容错/限流库,但设计理念不同。设计理念:Sentinel 采用"信号量 + 滑动窗口统计"的架构,通过资源抽象(SphU.entry)与责任链(slot chain)统计流量、执行限流/熔断/冷启动等,规则集中管理、支持动态变更;Resilience4j 采用"函数式装饰"(Decorators)——把熔断、限流、超时等封装成可组合的装饰器,用注解或函数式 API 应用于方法,强调函数式组合与不可变。规则动态化:Sentinel 支持规则动态化(通过控制台/配置中心动态下发 FlowRule/DegradeRule 等,实时生效),适合生产动态调整;Resilience4j 规则多为配置驱动(配置文件/代码),动态变更需结合配置中心(如 Spring Cloud Config)实现,相对静态。生态:Sentinel 是阿里开源,与 Spring Cloud Alibaba、Dubbo 生态集成好,控制台丰富(支持热点、系统、授权规则);Resilience4j 是独立库,与 Spring 原生集成,轻量、可深度定制。选型:阿里生态、需要动态规则与可视化控制台选 Sentinel;需要轻量函数式组合、与 Spring 原生集成、可定制选 Resilience4j。

Sentinel="滑动窗口统计 + 动态规则 + 阿里生态",Resilience4j="函数式装饰 + 配置驱动 + 轻量定制"。选型看"动态规则与生态" vs "函数式与轻量"。

#
★★

21. XXL-JOB 的调度中心与执行器分离架构如何工作,任务注册、心跳保活与调度请求的链路是怎样的

XXL-JOB 的调度中心与执行器分离架构如何工作,任务注册、心跳保活与调度请求的链路是怎样的?

  • 调度中心与执行器分离
  • 任务注册与心跳保活
  • 调度请求链路

XXL-JOB 采用"调度中心(Admin)+ 执行器(Executor)"分离架构:调度中心负责任务的注册、调度、监控;执行器负责实际执行任务。工作链路:任务注册——执行器启动时,主动向调度中心注册(上报执行器地址、端口、AppName),调度中心记录可用的执行器;心跳保活——执行器定期(如 30 秒)向调度中心发送心跳(heartbeat),调度中心据此判断执行器是否存活,失联的执行器被标记不可用;调度请求——调度中心根据任务配置(cron、路由策略)与执行器注册信息,选择执行器并发送调度请求(HTTP/RPC),执行器收到后执行任务,并回调返回执行结果(成功/失败/日志)。调度中心维护"执行器注册表 + 任务 + 调度日志",执行器维护"任务执行 + 结果回调"。整个链路是"执行器注册 → 心跳保活 → 调度中心按 cron 触发 → 路由到执行器 → 执行并回调结果"。该架构让调度与执行解耦,支持执行器水平扩展、调度中心高可用。

分离架构让"调度(Admin)"与"执行(Executor)"解耦。核心链路是"注册 + 心跳保活 + 调度触发 + 执行回调"。理解这条链路即理解 XXL-JOB 的运作方式。

#
★★

22. 分片广播与单机执行分别适合什么任务,分片参数(shardingIndex/shardingTotalCount)如何用于数据切分

分片广播与单机执行分别适合什么任务,分片参数(shardingIndex/shardingTotalCount)如何用于数据切分?

  • 分片广播 vs 单机执行
  • 分片参数
  • 数据切分

单机执行:任务只在一个执行器上运行,适合"任务无分割需求、全局执行一次"的场景(如清理过期数据、生成报表、定时全量同步),保证任务只执行一次,避免重复。分片广播:任务分发给所有执行器,每个执行器用分片参数处理自己负责的数据分片,适合"大数据量可并行处理"的任务(如按用户/订单分片批量处理、统计多分片汇总)。分片参数:shardingIndex(当前分片序号,从 0 开始)与 shardingTotalCount(总分片数,等于执行器数量)。数据切分:任务代码根据 shardingTotalCountshardingIndex 计算自己负责的数据范围,例如按"ID 对 shardingTotalCount 取模 == shardingIndex"筛选数据,或按 ID 段划分(如每片负责一段 ID 区间),从而每个执行器只处理自己的分片,汇总后完成整体任务。分片广播让"海量数据"被水平切分到多执行器并行处理,提升吞吐;单机执行保证"全局任务"只跑一次。选择:需要并行处理大数据用分片广播,需全局一次执行用单机。

单机执行"全局一次",分片广播"并行分片"。分片参数(shardingIndex/TotalCount)用于把数据按"取模/区间"切分给各执行器,是并行处理大数据的关键。理解二者择是调度选型基础。

#
★★

23. 调度中心自身的高可用如何保障,主从切换、任务超时判定与 misfire 补偿机制如何设计

调度中心自身的高可用如何保障,主从切换、任务超时判定与 misfire 补偿机制如何设计?

  • 调度中心高可用
  • 主从切换
  • 任务超时与 misfire 补偿

调度中心(如 XXL-JOB Admin)高可用保障:通常部署多个调度中心实例,通过分布式锁/选主保证"同一时刻只有一个实例执行调度"(避免重复触发),或通过注册中心/数据库协调各实例;实例故障时,其他实例接管(主从切换)。主从切换:用分布式锁(Redis/ZK)或数据库 lease 实现主节点选举,主节点负责调度,主节点故障时备节点获取锁成为主节点继续调度,切换需保证"任务不重复、不丢失"(新主节点恢复调度状态)。任务超时判定:调度中心记录任务开始时间与超时时间(如任务配置的超时秒数),定时检查,若任务执行超时(未在超时时间内回调完成),则标记超时并告警/触发补偿(如强制 interrupt 或重试)。misfire 补偿:任务因前一次执行未完成、调度中心故障或堆积而未按 cron 触发时,产生 misfire(错过触发);补偿机制——在错过触发后,根据策略决定是否补跑(如 misfire 策略:"丢弃"、"立即补偿执行一次"、"按照实际触发时间执行"),并记录 misfire 日志供监控。综合"主从切换 + 超时判定 + misfire 补偿 + 任务幂等"保证调度中心高可用与任务可靠。

调度中心高可用核心是"主从切换防重复 + 超时判定 + misfire 补偿"。主从用锁/lease 保证单点调度,超时与 misfire 补偿保证任务不因调度故障而漏跑,配合幂等防重。

#
★★

24. 降级的触发条件(手动/自动/规则)

请介绍降级的触发条件(手动/自动/规则)?

  • 手动降级
  • 自动降级
  • 规则降级

降级(degradation)是在系统过载或依赖故障时,停用非核心功能、提供降级响应,保证核心功能可用。触发条件分三类:手动降级——运维/开发根据业务判断(如大促、预知故障)手动开关降级,通过配置中心/开关人工触发,灵活可控;自动降级——系统根据运行时指标自动触发,如 Sentinel 的降级规则(响应时间超阈值、异常比例超阈值、异常数超阈值)自动开启降级,或熔断器在失败率超阈时自动降级;规则降级——基于"规则"(配置的降级规则/策略)触发,如按某个 key 的流量、按参数、按服务状态,规则定义"什么情况降级、降级到哪"。降级内容通常是返回降级结果(默认值、缓存数据、简化处理)、停用非核心步骤、降级依赖。工程上三类结合:核心业务可配置规则自动降级,特殊场景手动降级,配合监控与告警。降级与熔断相关但不同:熔断是"失败自动开",降级是"降级响应"(可手动可自动)。触发条件的设计原则是"核心保住、非核心可控、降级可恢复"。

降级触发分"手动(人工开关)、自动(指标触发)、规则(配置策略)"。设计原则是"核心可用、非核心降级、可恢复"。理解三类触发是降级设计的基础。

#

25. Hystrix 已弃用的迁移(Resilience4j)

Hystrix 已弃用,如何迁移到 Resilience4j?

  • Hystrix 弃用原因
  • Resilience4j 的对应能力
  • 迁移步骤

Hystrix 是 Netflix 的容错库,但已进入维护模式(不再积极开发),业界推荐迁移到 Resilience4j。Hystrix 的熔断、隔离、降级、请求合并等能力,在 Resilience4j 中有对应实现:熔断(CircuitBreaker)、舱壁隔离(Bulkhead)、限流(RateLimiter)、超时(TimeLimiter)、重试(Retry)、降级(Fallback)。迁移步骤:替换依赖——用 resilience4j-spring-boot2(或相应版本)替代 hystrix;改造注解——把 @HystrixCommand 替换为 @CircuitBreaker/@Retry/@RateLimiter 等,fallbackMethod 替换为 @Fallback;改造配置——把 Hystrix 的配置(线程池、超时、熔断阈值)迁移到 Resilience4j 的配置(properties 或代码);同步功能——Hystrix 的请求合并(RequestCollapse)需自行或改用其他方案,指标暴露迁移到 Micrometer/Prometheus。注意差异:Hystrix 默认线程池隔离,Resilience4j 默认信号量/可配线程池;Hystrix 自动为每个命令开线程池,Resilience4j 需显式配置。迁移后获得更轻量、函数式、可扩展的容错能力。核心是"能力映射 + 注解/配置改写 + 依赖替换"。

迁移本质是"把 Hystrix 的能力映射到 Resilience4j 并改写注解/配置"。Resilience4j 更轻量、函数式、可扩展,是 Hystrix 的现代替代。理解能力映射是迁移关键。

#

26. Sentinel 的规则体系(FlowRule/DegradeRule/SystemRule/AuthorityRule)如何分工,资源调用经过的 slot 责任链如何串联

Sentinel 的规则体系(FlowRule/DegradeRule/SystemRule/AuthorityRule)如何分工,资源调用经过的 slot 责任链如何串联?

  • 各规则的分工
  • slot 责任链
  • 资源处理的串联

Sentinel 的规则体系按职责分工:FlowRule(流量规则)——限流,控制资源的 QPS 并发数,按参数/请求限流;DegradeRule(熔断降级规则)——慢调用/异常比例/异常数超阈值时熔断降级;SystemRule(系统保护规则)——按系统维度(CPU、内存、QPS、线程数、RT)保护,防止系统过载;AuthorityRule(授权规则)——黑白名单,按调用方限制访问。此外还有 ParamFlowRule(热点参数限流)、以及自定义规则。资源调用的处理由"slot 责任链"串联:Sentinel 对每个资源(SphU.entry)按顺序执行一系列 slot(ProcessorSlot),构成责任链:如 NodeSelectorSlot(统计节点)、ClusterBuilderSlotStatisticSlot(统计)、AuthoritySlot(授权)、SystemSlot(系统保护)、FlowSlot(流量)、DegradeSlot(熔断)、ParamFlowSlot(热点)等。每个 slot 负责一类检查,按链式顺序执行,任一 slot 拒绝则资源调用被拦截。规则与 slot 对应:各规则在对应 slot 中校验并生效。整个"规则配置 + slot 责任链"实现了 Sentinel 的流控、熔断、系统保护、授权等能力。

规则体系"分工"(Flow 限流、Degrade 熔断、System 系统保护、Authority 授权),slot 责任链"串联"(按 NodeSelector→Statistic→Authority→System→Flow→Degrade→ParamFlow 顺序执行)。理解规则与 slot 的映射是关键。

#

27. 调度时钟漂移(NTP 同步偏差)对 Cron 触发有何影响,跨时区与夏令时切换应如何规避漏触发或重复触发

调度时钟漂移(NTP 同步偏差)对 Cron 触发有何影响,跨时区与夏令时切换应如何规避漏触发或重复触发?

  • 时钟漂移对 Cron 的影响
  • 跨时区处理
  • 夏令时切换

调度时钟漂移(NTP 同步偏差)会导致 Cron 触发时间不准确:若节点时钟快,可能提前触发(与预期时间偏差);若慢,可能延迟触发甚至漏触发;时钟回拨可能导致重复触发。影响:依赖"墙钟时间"的 Cron 调度在时钟漂移下会偏离真实时间,跨时区/夏令时还会导致本地时间与 UTC 的换算错误。规避方案:统一用 UTC 时间(或服务器统一时区)计算 Cron 触发点,避免依赖本地时区;调度中心用同一时钟源(NTP 同步),并监控时钟漂移;对关键任务增加"幂等 + 防重入"(时钟重复触发不重复执行)与"时间校验"(触发时校验是否在预期窗口)。跨时区:明确 Cron 表达式基于哪个时区(如统一 UTC),避免在不同时区节点上产生不同触发时间;夏令时切换:夏令时会导致"时间跳变"(如春季跳快一小时、秋季回调一小时),可能造成漏触发(跳过的时段)或重复触发(回调的时段);规避——用 UTC 或不受夏令时影响的时区(如 GMT)作为 Cron 基准,或在时间跳变窗口对任务做补偿(如对跳过的时段补跑、对重复时段去重)。核心是"统一时钟基准 + 幂等防重 + 时区/夏令时感知的补偿"。

时钟漂移与夏令时都会使 Cron 触发偏离预期。规避靠"统一 UTC + NTP 同步 + 幂等防重 + 时间窗口校验",对跳变时段做补偿。核心是"基准时间统一 + 触发幂等"。