怎样在Spring Boot WebFlux中使用Reactive Redis流式响应

大强大大_2033

大强大大_2033

2026-09-15

227人浏览

原创

不能直接用 redistemplate 做流式响应,因其为阻塞式 api,会阻塞 netty 事件循环线程,破坏 webflux 非阻塞特性;必须使用 reactiveredistemplate(基于 lettuce),返回 mono/flux,支持背压与异步调度。

怎样在spring boot webflux中使用reactive redis流式响应

为什么不能直接用 RedisTemplate 做流式响应

因为 RedisTemplate 是阻塞式 API,它在调用 opsForValue().get() 或 scan() 时会同步等待 Redis 返回结果,这会卡住 Netty 的事件循环线程。一旦发生,整个 WebFlux 的非阻塞优势就没了,高并发下容易线程耗尽、超时堆积。

必须用响应式客户端——ReactiveRedisTemplate(底层基于 Lettuce),它返回的是 Mono 或 Flux,天然支持背压和异步调度。

  • ReactiveRedisTemplate 的 scan() 方法返回 Flux<string></string>,可直接用于流式分批拉取 key
  • 对大 value(如 JSON 字符串)做流式解析时,不能一次性 get() 再拆,而应结合 scan() + pipeline + 分块订阅
  • 若误配了 spring-boot-starter-data-redis(非 reactive 版),Spring Boot 会自动装配阻塞版,需手动排除

ReactiveRedisTemplate 流式扫描大键空间的写法

比如要从 Redis 扫描 10 万个 key 并逐个返回其 value,不能用 keys *(禁用!会阻塞 Redis),必须用游标式 scan:

@GetMapping(value = "/redis/keys", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<string> streamKeys() {
    return redisTemplate.scan(ScanOptions.scanOptions()
            .match("user:*")
            .count(100)
            .build())
        .flatMap(key -> redisTemplate.opsForValue().get(key)
            .map(value -> String.format("key=%s, value=%s", key, value))
            .defaultIfEmpty(String.format("key=%s, value=null", key)))
        .take(5000); // 防止无限流,加安全上限
}</string>

注意点:

  • count 不是“每次返回多少条”,而是 hint,实际数量可能更少;值太大会增加单次 Redis 负担,建议 50–200
  • flatMap 是关键:把每个 key 的异步 get() 转成并行流,但默认并发度是 256,生产环境建议加 .concurrent(8) 控制连接数
  • 没加 take() 或超时控制时,客户端断连后 Flux 可能不自动 cancel,需配合 doOnCancel 清理资源

流式写入 Redis 时怎么避免 OOM

向 Redis 批量写入大量数据(如导入日志),如果一次性构造百万级 Mono 再 collectList(),会吃光堆内存。正确做法是“边生成边发”,靠背压驱动:

React Flow Implementation
React Flow Implementation

使用 @xyflow/react正确实现 React Flow 节点式用户界面。适用于构建流程图、图表、可视化编辑器或节点式应用程序...

下载
Flux.range(1, 100_000)
    .buffer(100) // 每 100 条打包成 list
    .flatMap(batch -> Mono.fromRunnable(() -> {
        // 构造 pipeline 命令,一次发 100 个 set
        var pipeline = redisTemplate.getConnectionFactory().getConnection().pipelined();
        batch.forEach(i -> pipeline.set(("log:" + i).getBytes(), ("data-" + i).getBytes()));
        pipeline.exec();
    }), 4) // 并发最多 4 个 pipeline
    .then();

要点:

  • 别用 Flux.concatMap —— 它是串行,吞吐低;flatMap 并发可控才是流式写入的核心
  • Redis 的 pipeline 不是原子的,失败需重试逻辑,exec() 返回 List<object></object>,要检查 null 或异常
  • Lettuce 默认连接池最大 8 个连接,flatMap 并发数 > 连接数会导致排队,可通过 ReactiveRedisConnectionFactory 调整 maxIdle/maxAcquire

客户端断连后 Redis 流还在跑?得手动 cancel

WebFlux 的 Flux 默认不会感知 HTTP 连接关闭。用户关掉浏览器或网络中断,服务端仍可能继续 scan / get,浪费 Redis 资源和 CPU。

必须显式监听取消信号:

return redisTemplate.scan(options)
    .doOnCancel(() -> log.info("Client disconnected, scan cancelled"))
    .doOnTerminate(() -> log.info("Stream finished or cancelled"))
    .onErrorResume(e -> {
        log.error("Redis stream error", e);
        return Flux.empty();
    });

更稳妥的做法是:在 Controller 方法里注入 ServerWebExchange,用 exchange.getResponse().isCommitted() 判断是否已写出,但不如 doOnCancel 直接可靠。

真正容易被忽略的是:Lettuce 的 scan 游标本身不带 cancel 支持,所以 cancel 后当前批次可能仍会完成,但后续游标不再发起请求——这是框架层限制,不是 bug。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

react redis spring boot

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
spring框架介绍
spring框架介绍

本专题整合了spring框架相关内容,想了解更多详细内容,请阅读专题下面的文章。

2025.08.06

2151

22

Java Spring Security 与认证授权
Java Spring Security 与认证授权

本专题系统讲解 Java Spring Security 框架在认证与授权中的应用,涵盖用户身份验证、权限控制、JWT与OAuth2实现、跨站请求伪造(CSRF)防护、会话管理与安全漏洞防范。通过实际项目案例,帮助学习者掌握如何 使用 Spring Security 实现高安全性认证与授权机制,提升 Web 应用的安全性与用户数据保护。

2026.01.26

397

25

常用的数据库软件
常用的数据库软件

常用的数据库软件有MySQL、Oracle、SQL Server、PostgreSQL、MongoDB、Redis、Cassandra、Hadoop、Spark和Amazon DynamoDB。更多关于数据库软件的内容详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.02

4069

19

内存数据库有哪些
内存数据库有哪些

内存数据库有Redis、Memcached、Apache Ignite、VoltDB、TimesTen、H2 Database、Aerospike、Oracle TimesTen In-Memory Database、SAP HANA和ache Cassandra。更多关于内存数据库相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.14

3575

11

mongodb和redis哪个读取速度快
mongodb和redis哪个读取速度快

redis 的读取速度比 mongodb 更快。原因包括:1. redis 使用简单的键值存储,而 mongodb 存储 json 格式的数据,需要解析和反序列化。2. redis 使用哈希表快速查找数据,而 mongodb 使用 b-tree 索引。因此,redis 在需要高性能读取操作的应用程序中是一个更好的选择。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.02

6332

6

redis怎么做缓存服务器
redis怎么做缓存服务器

redis 作为缓存服务器的答案:redis 是一款开源、高性能、分布式的键值存储,可作为缓存服务器使用。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

603

6

redis怎么解决数据一致性
redis怎么解决数据一致性

redis 提供了两种一致性模型,以维护副本数据一致性:强一致性 (sync) 确保写操作仅在复制到所有从节点后才完成;最终一致性 (async) 则在主节点上写操作后认为已完成,牺牲一致性换取性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

716

6

mysql和redis怎么保证双写一致性
mysql和redis怎么保证双写一致性

确保 mysql 和 redis 双写一致性的技术包括:1、事务性更新:同时更新 mysql 和 redis,保证一致性;2、主从复制:mysql 主服务器更改同步到 redis 从服务器;3、基于事件的更新:mysql 记录更改并发送到 redis等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

5762

6

redis缓存一般存些什么数据
redis缓存一般存些什么数据

redis缓存中存储的数据类型包括:字符串、哈希、列表、集合、有序集合、位图、地理空间数据和hyperloglog。这些数据类型适用于存储各种数据,从简单信息到复杂对象和地理位置。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.07

1120

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 11.9万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.4万人学习