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注入的 bFeignClient实际是一个动态代理对象

  • 调用方法时,会被 InvocationHandler 拦截(Feign的核心)

② 构造请求模板(RequestTemplate)

  1. 解析方法注解:

    • @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配合时:

 

  1. Feign动态代理拦截方法调用

  2. 调用委托给 HystrixInvocationHandler

  3. 生成 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();
}

检查步骤

    1. 判断队列容量

      • 默认队列长度:maxQueueSize(默认-1,使用SynchronousQueue无缓冲)

      • 动态队列:queueSizeRejectionThreshold(可覆盖maxQueueSize)

    2. 判断线程活跃数

      • 核心线程数:corePoolSize(默认10)

      • 最大线程数:maximumPoolSize(默认10)

    3. 拒绝条件
      当 队列已满 && 活跃线程 >= 最大线程数 时,抛出 RejectedExecutionException

二、信号量隔离模式(SEMAPHORE)

// 源码位置:TryableSemaphore.java
public boolean tryAcquire() {
    int currentCount = count.get();
    return currentCount < numberOfPermits && 
           count.compareAndSet(currentCount, currentCount + 1);
}

检查步骤

    1. 获取当前信号量计数

      • numberOfPermits:最大并发数(默认10)

      • currentCount:当前已用信号量

    2. CAS原子操作
      通过 compareAndSet 尝试占用一个信号量

    3. 拒绝条件
      当 currentCount >= numberOfPermits 时,直接拒绝请求

 

 

面试题:

1.如果openFeign没有设置对应得超时时间,那么将会采用Ribbon的默认超时时间

 

posted @ 2023-05-29 16:23  好记性不如烂笔头=>  阅读(136)  评论(0)    收藏  举报