1 基础概念类面试题
1.1 缓存穿透、击穿、雪崩的区别与解决方案
▶ 缓存穿透
- 定义:大量请求的Key在缓存和数据库中均不存在,导致请求直接击穿缓存层直达数据库,引发性能崩溃。
- 示例:恶意攻击携带不存在的用户ID查询数据。
- 解决方案 :
- 布隆过滤器:提前拦截无效Key,避免数据库查询。
- 空值缓存:对查询结果为空的Key设置短时效缓存(如5分钟),防止重复穿透。
▶ 缓存击穿
- 定义:热点数据(如秒杀商品)的缓存突然失效,大量请求同时涌入数据库,导致瞬时压力激增。
- 示例:秒杀活动中商品库存缓存过期,大量用户同时查询库存。
- 解决方案 :
- 缓存预热:提前将热点数据加载至缓存。
- 互斥锁(Redisson):在缓存失效时,通过分布式锁保证只有一个线程重建缓存。
▶ 缓存雪崩
- 定义:大量缓存节点同时失效或服务不可用,导致请求集中流向数据库,引发级联故障。
- 示例:Redis集群因内存不足大面积宕机,所有请求 fallback 到数据库。
- 解决方案 :
- 缓存高可用: 采用分布式缓存架构(如Redis Cluster)来提高缓存系统的高可用性,避免单点故障。
- 分散缓存过期时间: 设置缓存的过期时间时,使用随机值分散过期时间,避免大量缓存同时失效。
- 限流与降级: 在缓存失效或宕机时,通过限流、降级策略控制流量,保证系统在高负载情况下的可用性。限流可以保护数据库不被压垮,而降级可以提供部分服务或返回预设的默认值。
1.2 服务雪崩、降级、熔断、限流、隔离、超时的定义
▶ 服务雪崩
-
定义 :服务雪崩是指在分布式系统中,当某个服务出现故障或响应变慢 时,由于它是其他服务的依赖,导致调用它的上游服务也受影响,进而影响到更多的服务,最终可能导致整个系统的服务不可用或性能大幅下降。这种连锁反应类似于雪崩效应,因此被称为"服务雪崩"。
-
核心原因:
- 服务依赖性强: 一个服务通常依赖于多个其他服务或组件,如果下游服务出现问题,上游服务的请求可能堆积或超时,导致整个系统的响应速度变慢。
- 流量激增: 突然的流量激增可能使某个服务的负载大幅增加,超过其承受能力,导致服务崩溃,并进而影响其他依赖它的服务。
- 服务故障: 下游服务或其所依赖的资源(如数据库、缓存)故障,导致上游服务无法正常工作。
-
解决方案 :
- 服务降级: 据预设的策略返回默认值或执行简化逻辑,以保证基本功能的可用性。
- 服务熔断: 暂时停止对该服务的调用,避免进一步增加其负载。
- 限流: 通过限制请求的速率,防止流量激增对服务造成过大压力。
- 隔离: 通过将不同的服务隔离在不同的资源池中,确保一个服务的故障不会直接影响其他服务。
▶ 服务降级
- 定义 :当服务不可用时,返回预定义的托底数据(如缓存数据、友好提示),保证核心功能可用。 服务降级的目的是在资源紧张或服务出现问题时,保持系统的可用性,避免影响用户体验。
- 示例:商品详情页服务故障时,返回静态缓存的商品简介。
- 服务降级的场景 :
- 下游服务不可用或响应过慢
- 系统负载过高
- 部分功能异常
▶ 服务熔断
- 定义:类比电路保险丝,当下游服务故障率超过阈值时,主动断开调用,避免故障扩散。
- 状态机 :
- 闭合(正常):允许调用,监控健康状态。
- 开启(熔断):拒绝调用,返回降级结果。
- 半开(试探恢复):允许少量请求试探,根据成功率决定是否恢复调用。
▶ 服务限流
- 定义:通过限制单位时间内的请求量(QPS/线程数),保护服务不被瞬时流量压垮。
- 算法:令牌桶(允许突发流量)、漏桶(匀速处理请求)。
▶ 服务隔离
- 定义:将系统拆分为独立模块,通过线程池/信号量隔离故障域,避免影响全局。
- 实现方式 :
- 线程池隔离:为每个服务分配独立线程池,故障时仅影响当前线程池。
- 信号量隔离:通过信号量控制并发请求数,适用于低延迟场景。
▶ 服务超时
- 定义:上游服务调用下游服务时设置最大响应时间,超时则中断请求并释放资源。
- 作用:防止因下游服务延迟导致上游线程阻塞堆积。
2 Sentinel核心原理与集成面试题
2.1 Sentinel是什么?解决了什么问题?
▶ 定义
- Sentinel 是阿里巴巴开源的分布式系统流量管理组件,通过实时监控、熔断降级、限流、系统负载保护 等手段,防止突发流量或不稳定外部依赖导致的服务不可用,确保系统的高可用性和稳定性。
- 替代Netflix Hystrix,支持动态规则配置、多维度监控和扩展插件机制。
▶ 解决的问题
- 流量控制:防止突发流量击垮服务(如网关限流)。
- 熔断降级:对不稳定依赖服务自动熔断,避免雪崩。
- 系统保护:根据CPU、内存等系统指标动态调整流量,防止过载。
2.2 如何集成OpenFeign与Sentinel?
▶ 核心步骤
-
开启Feign对Sentinel的支持
在
application.yml
中配置:yamlfeign: sentinel: enabled: true # 启用Sentinel适配
-
定义Feign接口并配置FallbackFactory
java
@FeignClient(contextId = "userFeignService", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = UserFeginFallbackFactory.class)
public interface UserFeignService {
/**
* 根据用户名获取当前用户信息
*/
@GetMapping("/system/user/info/{username}")
R<LoginUser> info(@PathVariable("username") String username, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
/**
* 根据 userId 获取用户信息
*/
@GetMapping("/system/user/getInfoByUserId/{userId}")
R<LoginUser> getInfoByUserId(@PathVariable("userId") Long userId, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
/**
* 根据条件获取用户列表
*/
@PostMapping("/system/user/listOfInner")
R<List<SysUserVO>> listOfInner(@RequestBody SysUserDTO sysUserDTO, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
/**
* 注册用户信息
*
* @param sysUser 用户信息
* @param source 请求来源
* @return 结果
*/
@PostMapping("/system/user/register")
R<Boolean> registerUserInfo(@RequestBody SysUser sysUser, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
}
- 实现降级逻辑
java
@Component
public class UserFeginFallbackFactory implements FallbackFactory<UserFeignService>
{
private static final Logger log = LoggerFactory.getLogger(UserFeginFallbackFactory.class);
@Override
public UserFeignService create(Throwable throwable)
{
log.error("用户服务调用失败:{}", throwable.getMessage());
return new UserFeignService()
{
@Override
public R<LoginUser> info(String username, String source) {
return R.fail("根据用户名获取用户失败:" + throwable.getMessage());
}
@Override
public R<LoginUser> getInfoByUserId(Long userId, String source) {
return R.fail("根据userId获取用户失败:" + throwable.getMessage());
}
@Override
public R<List<SysUserVO>> listOfInner(SysUserDTO sysUserDTO, String source) {
return R.fail("根据调教获取用户列表失败:" + throwable.getMessage());
}
@Override
public R<Boolean> registerUserInfo(SysUser sysUser, String source) {
return R.fail("注册用户失败:" + throwable.getMessage());
}
};
}
}
▶ 关键点
- @SentinelResource 注解:可直接在Feign接口方法上添加,实现细粒度限流/降级。
- 集中式降级 :通过公共模块(如
pmhub-api
)统一管理Feign接口的降级逻辑,避免代码冗余。
2.3 如何在项目中实现自定义Fallback服务降级?
▶ 两种实现方式
-
基于@SentinelResource 注解
在目标方法上直接配置
fallback
参数:java@GetMapping("/user/info") @SentinelResource( value = "getUserInfo", fallback = "handleFallback" // 降级方法名 ) public UserInfo getUserInfo(String userId) { // 正常逻辑 } public UserInfo handleFallback(String userId, Throwable ex) { // 处理异常,返回降级结果 }
-
基于OpenFeign的FallbackFactory
(见上题步骤)通过工厂类统一处理Feign调用的异常,适合微服务间调用场景。
2.4 集成Sentinel时遇到过哪些挑战?如何解决?
▶ 常见挑战与解决方案
-
依赖冲突
- 问题:Sentinel与Spring Cloud版本不兼容,导致启动报错。
- 解决:参考官方文档匹配版本(如Spring Cloud Alibaba 2021.0.1.0对应Sentinel 1.8.0),使用Maven Helper排查冲突。
-
降级逻辑设计
- 问题:降级返回的数据格式与正常响应不一致,导致前端展示异常。
- 解决 :定义统一的响应格式(如
R<T>
),降级方法返回与正常逻辑一致的结构(包含错误码和提示信息)。
-
限流规则误判
- 问题:设置的QPS阈值过低,导致正常请求被拦截。
- 解决:通过Sentinel控制台实时监控流量曲线,结合压测结果动态调整阈值(如逐步从500提升至1000)。
3 架构设计与场景题
3.1 为什么选择Sentinel而非Hystrix?
▶ 对比分析
特性 | Sentinel | Hystrix |
---|---|---|
维护状态 | 活跃(阿里巴巴持续更新) | 停止维护(2018年废弃) |
功能丰富度 | 流量控制、熔断、系统保护、热点防护 | 仅熔断降级、线程池隔离 |
规则配置 | 支持动态配置(Nacos/Apollo) | 静态配置或通过Dashboard修改 |
性能损耗 | 低(基于插槽链轻量级设计) | 较高(线程池隔离开销) |
社区生态 | 完善(中文文档、示例丰富) | 社区停滞,资料陈旧 |
▶ 结论
- Sentinel 更适合现代微服务架构的复杂流量治理需求,尤其在网关限流、动态规则管理和性能优化方面优势显著。
3.2 网关限流为什么选择Route ID维度?如何配置?
▶ 选择原因
- 粗粒度控制 :Route ID对应微服务名称(如
pmhub-system
),可对整个服务进行全局流量限制,适合保护核心服务。 - 配置简单:无需解析URI路径,直接关联Gateway路由配置,降低维护成本。
▶ 配置步骤
-
引入依赖
xml<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId> </dependency>
-
YAML配置
yamlspring: cloud: sentinel: transport: dashboard: localhost:8081 # Sentinel控制台地址 gateway: rules: - resource: pmhub-system # 路由ID(与Gateway配置的routeId一致) grade: QPS count: 1000 # 每秒最大请求数 interval: 1 controlBehavior: FAST_FAIL # 快速失败策略
-
持久化到Nacos
通过Nacos配置中心管理限流规则,避免服务重启后丢失配置。
4 扩展问题:结合PmHub项目的实战场景
4.1 登录流程中如何结合计数器限流与Sentinel降级?
▶ 场景描述
- 计数器限流:通过Redis+Lua脚本对登录接口进行IP级限流(如每分钟5次),防止暴力破解。
- Sentinel降级 :当用户服务(
pmhub-system
)因流量激增触发熔断时,登录流程自动 fallback 至降级逻辑(如返回"系统繁忙"提示)。
▶ 执行流程
- 用户发起登录请求,先经过网关层的计数器限流校验。
- 校验通过后,请求转发至认证服务(
pmhub-auth
),通过OpenFeign调用用户服务获取用户信息。 - 若用户服务QPS超过Sentinel配置的阈值(如1000),触发熔断,认证服务返回自定义降级结果,避免雪崩。
5 面试加分项:原理与源码理解
5.1 简述Sentinel的插槽链(Slot Chain)原理
- 核心机制:Sentinel通过责任链模式串联多个功能插槽(Slot),每个插槽负责特定流量治理逻辑(如流量控制、熔断、监控)。
- 默认插槽顺序 :
NodeSelectorSlot
(资源节点选择) →ClusterBuilderSlot
(集群统计) →LogSlot
(日志记录) →AuthoritySlot
(黑白名单) →SystemSlot
(系统保护) →FlowSlot
(流量控制) →DegradeSlot
(熔断降级)。 - 扩展能力:可通过SPI机制自定义插槽,调整执行顺序(如添加自定义鉴权插槽)。