Springboot + WebFlux + Disruptor 实现数据转发

1. 背景

利用Springboot 、WebFlux 、 Disruptor开发一套高性能、低延迟、高安全的通用数据转发平台,实现数据接收、基于配置的第三方服务转发,并通过控制台实现第三方服务的统一管控与转发规则配置。

技术框架及组件说明

WebFlux Disruptor
描述 是 Spring Framework 5 引入的 响应式(Reactive)Web 框架,用于构建非阻塞、异步、高并发的 Web 应用程序。它是 Spring MVC 的响应式替代方案,适用于需要高吞吐量和低资源消耗的场景(如微服务、实时数据流、IoT 后端等) 通常指 LMAX Disruptor,这是一个由英国金融技术公司 LMAX 开发的高性能并发框架,用于在 Java 中实现低延迟、高吞吐量的消息传递和事件处理。
核心优势 - 在 I/O 密集型场景下,吞吐量显著高于 Spring MVC(尤其在连接数 > 1000 时)。
  • 内存占用更低(无需为每个请求分配线程栈)。
  • 更适合现代云原生、容器化部署(资源受限环境)。 | - 无锁设计:利用 CAS操作和内存屏障实现线程安全,避免锁竞争和线程上下文切换;
  • 极致低延迟:延迟可低至 纳秒级;
  • 接近零 GC:预分配内存,避免运行时创建对象;
  • 灵活的消费模式:支持单 / 多生产者、单 / 多消费者,以及消费者依赖编排。 | | 核心原理 | WebFlux 基于 Reactor 框架 (实现 Reactive Streams 规范),底层依赖非阻塞 IO 容器(默认 Netty,也支持 Tomcat/Jetty 9.0+)实现。 | Disruptor 的核心是环形缓冲区(Ring Buffer) + 序列号(Sequence) ,替代传统队列的 "入队 / 出队" 操作 |

2.系统架构

2.1 整体架构

2.2 核心流程设计

2.2.1 第三方服务配置流程

  1. 管理员通过控制台提交数据提供方信息,并生成服务唯一key;
  2. 管理员通过控制台提交第三方服务信息(接口地址、请求方式、超时时间),并关联数据提供方信息;
  3. 配置信息先持久化到 MySQL,再同步缓存到 Redis(设置过期时间,定时刷新;
  4. 管理员可通过控制台启停服务(修改 Redis/MySQL 中服务状态字段,转发模块实时读取状态过滤无效服务)。

2.2.2 数据转发流程

  1. 数据发送端提交数据(https)到数据接收模块,通过网关进行身份和白名单认证;
  2. 数据接收模块采用WebFlux+Netty,对数据进行预处理(格式校验、补全数据)、数据转发(异步执行);
  3. 数据下发到转发模块(通过Disruptor队列进行处理)后,数据接收模块直接返回处理结果;
  4. 在数据转发模块中,加载配置信息(第三方服务配置、转发策略配置等);
  5. 获取配置信息,构建webClient需要的请求信息(服务url,,请求方法,body信息)、重试机制和异常处理;
  6. 记录webClient执行日志,并定时批量持久化到数据库中;

2.3 高性能设计要点

  1. 响应式编程:数据接收模块基于 Spring WebFlux+Netty,非阻塞 IO 模型,支持 10w + 并发连接,相比传统 Servlet 模型大幅提升吞吐量;
  2. 异步转发:数据转发采用 "生产者 - 消费者" 模型,接收数据后放入内存队列(Disruptor 高性能队列,避免 ArrayBlockingQueue 的锁竞争),消费者线程池异步转发,解耦接收与转发流程,降低延迟;
  3. 配置缓存:第三方服务配置、转发规则全部缓存到 Redis,避免频繁查询数据库,配置读取延迟控制在毫秒级;
  4. 连接池复用:使用 WebClient连接池复用第三方服务连接,避免频繁创建 TCP 连接,提升转发效率;

3. 核心模块详细设计(代码片段)

3.1 数据接收模块

less 复制代码
@RequestMapping("/data/receive")
public class DataReceiveController {
    @PostMapping("/json")
    public Mono<DataReceiveResult<Boolean>> receiveData(
            @RequestHeader("Send-Service-Key") String sendServiceKey,
            @RequestBody String bodyDate){
        if (!configManager.isServiceKeyValid(sendServiceKey)) {
            return Mono.just(DataReceiveResult.error("无效的服务Key"));
        }
        dataForwardService.forwardDataAsync(sendServiceKey, bodyDate, DataFormat.JSON);
        return Mono.just(DataReceiveResult.ok(true));
    }
}

@Override
public void forwardDataAsync(String sendServiceKey, String bodyDate, DataFormat dataFormat) {
    log.info("数据转发服务-异步转发数据-开始, sendServiceKey: {}, bodyDate: {}", sendServiceKey, bodyDate);
    // 获取Disruptor发布者
    RingBuffer<ForwardEvent> ringBuffer = disruptor.getRingBuffer();
    long sequence = ringBuffer.next();
    try {
        ForwardEvent event = ringBuffer.get(sequence);
        event.setSendServiceKey(sendServiceKey);
        event.setData(bodyDate);
        event.setDataFormat(dataFormat);
        event.setStartCreateTime(System.currentTimeMillis());
    } finally {
        ringBuffer.publish(sequence);
    }
}

3.2 数据转发模块

vbnet 复制代码
@Component
public class ForwardEventHandler implements EventHandler<ForwardEvent> {
    @Override
    public void onEvent(ForwardEvent event, long sequence, boolean endOfBatch) throws Exception {
        String serviceKey = event.getSendServiceKey();
        String rawData = event.getData();
        long startTime = System.currentTimeMillis();
        AtomicBoolean success = new AtomicBoolean(false);
        AtomicReference<String> errorMsg = new AtomicReference<>();
        
        // 执行转发(带重试,使用WebClient进行异步调用)
        Mono<String> stringMono = executeByWebClient(serviceConfig, rawData, event.getDataFormat());
        stringMono.subscribe(
            result -> {
                success.set(true);
                logService.recordForwardLog(serviceKey, rawData, rawData, success.get(), System.currentTimeMillis() - startTime, errorMsg.get());
            },
            error -> {
                errorMsg.set("转发失败:" + error.getMessage());
                logService.recordForwardLog(serviceKey, rawData, rawData, success.get(), System.currentTimeMillis() - startTime, errorMsg.get());
            }
        );
    }
    
    private Mono<String> executeByWebClient(ServiceInfo serviceConfig, String data, DataFormat dataFormat) {
        return webClient.method(getHttpMethod(serviceConfig))
                .uri(serviceConfig.getApiUrl())
                .headers(headers -> {
                    headers.setAll(getHttpHeaders(dataFormat));
                })
                .bodyValue(data)
                .retrieve()
                .bodyToMono(Result.class)
                .flatMap(result -> {
                    if (result.getSuccess()) {
                        return Mono.just(result.getData() != null ? result.getData().toString() : "");
                    } else {
                        return Mono.error(new RuntimeException("转发失败:" + result.getMessage()));
                    }
                })
                .retryWhen(
                        Retry.backoff(serviceConfig.getRetryCount(), Duration.ofMillis(100))
                                .maxBackoff(Duration.ofMillis(500))
                                .jitter(0.2d)
                                .filter(throwable -> {
                                    return shouldRetry(throwable);
                                })
                )
    }
}

团队介绍

「智慧家技术平台-应用软件框架开发」主要负责设计工具的研发,包括营销设计工具、家电VR设计和展示、水电暖通前置设计能力,研发并沉淀素材库,构建家居家装素材库,集成户型库、全品类产品库、设计方案库、生产工艺模型,打造基于户型和风格的AI设计能力,快速生成算量和报价;同时研发了门店设计师中心和项目中心,包括设计师管理能力和项目经理管理能力。实现了场景全生命周期管理,同时为水,空气,厨房等产业提供商机管理工具,从而实现了以场景贯穿的B端C端全流程系统。

相关推荐
silvamux_1 小时前
Spring Boot 调用大模型 api 最小可跑教程
java·spring boot·后端
今年下半年1 小时前
【Spring Boot 】通过 OpenFeign 请求第三方接口
java·spring boot·后端·openfeign
范什么特西1 小时前
亲和路由(inspect)
java
她说可以呀1 小时前
Docker 镜像的两种创建方式
java·分布式·docker
霸道流氓气质2 小时前
AgentFlow 入门与实战:Task-Based 并发、EWMA 动态调度与四道门禁的 Java 生产级编排
java·开发语言
愿得一猪蹄2 小时前
# Java线程池实战,别再new Thread了
java
ee又momo2 小时前
# 深入理解Java注解,从使用到自定义
java
霸道流氓气质2 小时前
AI智能博客平台实战:RAG增强写作、多Agent协作与语义检索的Vue3 + Spring AI全栈实现
java·人工智能·spring
打工仔折腾 AI2 小时前
LangChain 工具调用实战:从 Tool 定义到 Agent 执行链路拆解
java·前端·人工智能·后端·python·langchain·ai agent 实战