Spring WebFlux + MongoDB 查询300条Ticket数据耗时25秒求助
优化思路与解决方案
1. 优化对象转换性能
你当前在getAllTickets中使用ObjectMapper逐个反射转换TicketData到Ticket,这是高频性能损耗点:
- 启用Jackson的快速解析/写入优化:
ObjectMapper mapper = new ObjectMapper() .enable(MapperFeature.USE_FAST_JSONPARSER) .enable(MapperFeature.USE_FAST_BEAN_PROPERTY_WRITER); - 替换为MapStruct(编译期生成转换代码,性能远高于反射):
先定义映射接口:
之后在适配器中注入@Mapper(componentModel = "spring") public interface TicketMapper { Ticket map(TicketData ticketData); List<Ticket> map(List<TicketData> ticketDataList); }TicketMapper,替换原有的ObjectMapper转换逻辑:@Override public Flux<Ticket> getAllTickets() { return this.ticketRepository .findAll() .buffer(50) // 批量减少转换次数 .flatMap(buffer -> Flux.fromIterable(ticketMapper.map(buffer))); }
2. 排查MongoDB事件监听器开销
日志显示onAfterLoad和onAfterConvert执行缓慢,需检查:
- 项目中是否存在自定义
MongoEventListener?如果有,移除监听器中不必要的耗时操作(如额外DB查询、复杂计算),或直接删除无用监听器。 - 禁用Spring Data MongoDB默认事件处理(若无需监听):
在application.yml中添加配置:spring: data: mongodb: event: enabled: false
3. 优化响应式流处理逻辑
- 用
buffer()批量处理文档,减少单条数据转换的上下文切换开销,示例代码见上述MapStruct部分。 - 避免在
map操作中执行阻塞逻辑,确保所有转换操作都是非阻塞的。
4. 检查MongoDB序列化配置
- 自定义
LocalDateTime的序列化/反序列化逻辑,替换默认的日期转换(默认实现可能存在额外性能损耗):@Configuration public class MongoConfig { @Bean public MongoCustomConversions mongoCustomConversions() { List<Converter<?, ?>> converters = new ArrayList<>(); converters.add(new LocalDateTimeToDateConverter()); converters.add(new DateToLocalDateTimeConverter()); return new MongoCustomConversions(converters); } @WritingConverter static class LocalDateTimeToDateConverter implements Converter<LocalDateTime, Date> { @Override public Date convert(LocalDateTime source) { return source == null ? null : Date.from(source.atZone(ZoneId.systemDefault()).toInstant()); } } @ReadingConverter static class DateToLocalDateTimeConverter implements Converter<Date, LocalDateTime> { @Override public LocalDateTime convert(Date source) { return source == null ? null : LocalDateTime.ofInstant(source.toInstant(), ZoneId.systemDefault()); } } }
5. 验证查询阶段耗时
用MongoDB的执行计划确认是否是查询本身的问题:
在Repository中添加方法:
@Query(value = "{}") Flux<TicketData> findAllWithExplain();
执行后查看执行计划,确认查询阶段的实际耗时,排除数据库查询本身的性能问题。
内容的提问来源于stack exchange,提问作者Julián Rojas
相关产品推荐
相关产品推荐

