OpenFeign精选Hystrix精选
https://www.bilibili.com/read/cv11238006/ 掌握 OpenFeign 核心原理
https://blog.csdn.net/weixin_70730532/article/details/126875028 OpenFeign 夺命连环 9问
OpenFeign主要用于微服务项目中的服务远程调,Feign 不做任何请求处理,通过处理注解相关信息生成 Request,并对调用返回的数据进行解码,从而实现 简化 HTTP API 的开发 。
Feign 的启动原理
A 服务要调用B服务的接口。 B服务在自己服务中暴漏自己的 @FeignClient,A服务引入B服务调用对应的bFeignClient 的接口方法。
1.Feign Starter 在项目启动过程中注册全局配置,扫描包下所有的 @FeignClient 接口类(A服务引入了B服务,所以B服务下的@FeignClient 他也会读取到),并进行注册 IOC 容器@FeignClient 接口类被注入时,通过动态代理 (FactoryBean#getObject )返回动态代理类。接口被调用时被动态代理类逻辑拦截
2. 当A服务执行 bFeignClient.getUser(123L)
时:
① 动态代理拦截
-
Spring注入的 b
FeignClient
实际是一个动态代理对象 -
调用方法时,会被
InvocationHandler
拦截(Feign的核心)
② 构造请求模板(RequestTemplate)
-
解析方法注解:
-
@FeignClient(name="user-service")
→ 确定服务名称 -
@GetMapping("/getUser")
→ 确定HTTP方法和路径 -
@RequestParam("userId")
→ 确定参数位置
-
2. 生成请求模板:
GET http://user-service/getUser?userId=123
③ 服务发现与负载均衡(如有)
-
通过服务注册中心(如Nacos)查询
user-service
的实例列表 -
用负载均衡策略(如Ribbon)选择一个实例(如
192.168.1.100:8080
)
④ HTTP请求发送
-
底层HTTP客户端(如OkHttp)发送请求:
-
GET http://192.168.1.100:8080/getUser?userId=123
⑤ 处理响应
-
收到响应后:
-
成功:解码JSON →
UserDTO
对象 -
失败:根据配置重试或抛异常
-
Ribbon通过ILoadBalancer接口提供负载均衡服务,其实现原理为:
- ILoadBalancer依赖ServerList通过DiscoveryClient从nacos Client处获取Server列表并缓存这些Server列表。
- IPing接口定时对ILoadBalancer缓存的Server列表进行检测,判断其是否可用。
- IRule接口是负载均衡策略的抽象,ILoadBalancer通过IRule选出一个Server。(就是通过算法怎么对已经获取到的服务精选选取)
Hystrix如何实现:
Hystrix 的核心思想是快速失败 + 优雅降级,适用于高并发、高可用的微服务架构。
与Feign的整合流程
当Hystrix与Feign配合时:
-
Feign动态代理拦截方法调用
-
调用委托给
HystrixInvocationHandler
-
生成
HystrixCommand
执行上述完整流程
Hystrix 完整工作流程分解
1. 命令封装阶段
// 用户代码 @HystrixCommand(fallbackMethod = "fallback") public String doSomething() { return remoteService.call(); }
-
HystrixCommand 将方法调用封装为
HystrixInvokable
命令对象 -
关键类:
HystrixCommand
/HystrixObservableCommand
2. 请求缓存检查(可选)
if (cacheEnabled) { ValueFromCache v = cache.get(cacheKey); if (v != null) return v; // 直接返回缓存 }
-
使用
HystrixRequestCache
检查是否已有缓存结果 -
需提前定义
cacheKeyMethod
3. 熔断器状态检查
// CircuitBreaker 实现类 if (circuitBreaker.allowRequest()) { // 检查熔断状态 // 允许执行 } else { return fallback(); // 直接降级 }
-
熔断器三态转换:
-
OPEN
:直接触发降级 -
HALF-OPEN
:放行少量探测请求 -
CLOSED
:正常执行
-
4. 线程池/信号量资源检查
// 线程池隔离模式 if (!threadPool.isQueueSpaceAvailable()) { throw new RejectedExecutionException("Rejected command"); // 触发降级 }
-
隔离策略:
-
THREAD:检查线程池队列(
HystrixThreadPool
) -
SEMAPHORE:检查信号量计数(
TryableSemaphore
)
-
5. 执行目标方法
// HystrixCommand 核心执行 try { result = executeCommand(); // 实际业务调用 circuitBreaker.markSuccess(); // 记录成功 } catch (Exception e) { circuitBreaker.markFailure(); // 记录失败 throw e; }
-
通过
HystrixCommand#run()
执行真实逻辑 -
同步调用使用
execute()
,异步使用queue()
6. 超时监控(Timeout Monitoring)
// HystrixTimer 监控超时 Future<R> future = threadPool.submit(command); try { return future.get(timeout, TimeUnit.MILLISECONDS); } catch (TimeoutException e) { future.cancel(true); // 中断执行 throw e; }
-
独立计时线程监控超时(默认 1s)
-
超时触发线程中断(
Thread.interrupt()
)
7. 指标统计(Metrics Collection)
// HystrixCommandMetrics 记录指标 metrics.addExecutionTime(duration); metrics.incrementExecutionCount(); if (failed) metrics.incrementFailureCount();
-
滑动窗口统计(默认 10s 窗口)
-
计算错误率决定是否熔断
8. 降级逻辑触发
if (shouldFallback(failure)) { return getFallback(); // 执行降级方法 }
-
触发条件:
-
熔断打开
-
线程池拒绝
-
执行超时
-
执行异常
-
线程池/信号量资源检查 这个怎么检查啊
在Hystrix中,线程池/信号量资源检查是资源隔离的核心环节,其检查机制根据不同的隔离策略(线程池隔离 vs. 信号量隔离)有不同的实现方式。下面用底层源码+流程图的方式详细说明:
一、线程池隔离模式(THREAD)
检查流程
// 源码位置:HystrixThreadPool.java public boolean isQueueSpaceAvailable() { // 1. 检查线程池队列是否已满 if (threadPool.getQueue().size() < queueSizeRejectionThreshold) { return true; } // 2. 检查线程池活跃线程数 return threadPool.getActiveCount() < threadPool.getMaximumPoolSize(); }
检查步骤:
-
判断队列容量
-
默认队列长度:
maxQueueSize
(默认-1,使用SynchronousQueue无缓冲) -
动态队列:
queueSizeRejectionThreshold
(可覆盖maxQueueSize)
-
-
判断线程活跃数
-
核心线程数:
corePoolSize
(默认10) -
最大线程数:
maximumPoolSize
(默认10)
-
-
拒绝条件
当队列已满 && 活跃线程 >= 最大线程数
时,抛出RejectedExecutionException
二、信号量隔离模式(SEMAPHORE)
// 源码位置:TryableSemaphore.java public boolean tryAcquire() { int currentCount = count.get(); return currentCount < numberOfPermits && count.compareAndSet(currentCount, currentCount + 1); }
检查步骤:
-
获取当前信号量计数
-
numberOfPermits
:最大并发数(默认10) -
currentCount
:当前已用信号量
-
-
CAS原子操作
通过compareAndSet
尝试占用一个信号量 -
拒绝条件
当currentCount >= numberOfPermits
时,直接拒绝请求
面试题:
1.如果openFeign没有设置对应得超时时间,那么将会采用Ribbon的默认超时时间