Obvious pitfalls of spring Webflux- Ł ukaszKy ć

Jiedao jdon 2021-05-04 14:01:05
obvious pitfalls spring webflux- webflux

A few months ago , We started a new project . Our goal is to design a microservice that can handle many concurrent connections . We predict that the application will spend a lot of time waiting for multiple parallel I / O operation . The ideal architecture solution seems to use a non blocking approach . After a brief investigation , We decided to use Spring WebFlux As the main framework . That's because it's based on a non blocking stack , Excellent scalability and flexibility . flow stream The excellent abstraction of form seems really easy to use , Far more than based on Java NIO or Netty Of Traditional non blocking code is much better . That's why we try to be based on Spring WebFlux The reasons for implementing the service . however , Once our development work starts , Trouble comes with it .

New thinking

If you're used to writing code in traditional order , You may feel a little confused . That's our impression when we started the project . occasionally , Simple things seem difficult . The most surprising thing is , Even experienced Java Developers also have to reinvent the wheel . For them , This is a new programming paradigm , After years of different programming, it's not easy to switch to it . The fact is that , Reaction flow can greatly simplify some tasks , But other tasks seem to be much more complex . Besides , Code in the form of a sequence of operators , for example map or flatMap, It's not as easy to understand as traditional line by line blocking method calls . You can't simply extract any piece of code into a private method to make it more readable . You have to use a sequence of operators on the stream .

My observation is , Responsive flow stream It's less painful for open-minded developers . Although the learning curve is absolutely steep , But I think it's worth the time .

Record context information

One of our technical requirements is a dialogue between traceable Services . relevant ID Pattern It's exactly what we need . In short : Each incoming message is appended with a unique text value , It's a conversation identifier generated somewhere outside our service . In our case , We have two types of incoming messages :

  • HTTP request .
  • from SQS(Amazon Simple queue service ) Messages used by queues .

To provide traceability , We have to include correlation next to each log line ID, The ID Printed by code execution in the context of a given conversation . If each service participating in the conversation prints one “ The correlation ID”, It's easy to find all the logs related to it . Log aggregators are helpful , Because it collects all the logs in one place , Provides a convenient search function .

The most commonly used logging library implements “  Mapping diagnostic context ”(MDC) function , This function fully meets our needs .

stay Servlet In the world of , We will write a filter to handle each incoming HTTP request . The filter will be in the request handler ( namely Spring controller ) Before starting Correlation ID Put in MDC, And clean up the mapping after the request is processed . It will work perfectly , But remember ,MDC Use thread similarity pattern ( Implemented as a ThreadLocalJava class ) in , Save context information associated with a single thread . This means that it can only be used by a single thread from the beginning of accepting the request to the end of processing the request .

Unfortunately ,Spring WebFlux You can't work like that . A thread is likely to have multiple threads involved in a single request processing . So what should we do ?

Fortunately, ,Reactor The author of the library implements another mechanism for storing context information -Context. It can be used to transfer correlation between stream operators ID. To connect it with a well-known logging library MDC link , We use the solution described here : https://www.novatec-gmbh.de/en/blog/how-can-the-mdc-context-be-used-in-the-reactive-spring-applications/.   If you don't like it Kotlin Language , Please check out Java A similar implementation in : https://github.com/archie-swif/webflux-mdc

We realized the idea , And it works well ! We just need to create a custom WebFilter, Can from HTTP Read from request Correlation ID And set it in the context of the response flow . We found a weakness - Because of the implicit call MdcContextLifter, The stack trace is getting longer .

Long stack traces

The advantage of reaction flows is that they form declaration chains , Tell the publisher what happened to each element emitted . This abstraction allows complex logic to be implemented clearly . If the code works as expected , Then everything looks brilliant . You solved an extraordinary problem with just a few lines of code , You are proud of it .

This joy continues until someone sends you stack traces from production . Most of the lines you see are in Reactor.core.publisher( And include MdcContextLifter class Other lines in the package ) start , If you implement the context logging workaround mentioned in the previous section . It won't tell you anything , Because it's a package that has nothing to do with your code . I would say it doesn't work .

Besides , I remember a very serious problem we had . Users complain that the application occasionally returns errors , But we can't figure out why . There's nothing interesting in the log , Although we know that the application will catch all possible errors and use stacktrace Record the error level .

What's the problem ? We use Papertrail As a log aggregator . Push the application log to Papertrail The forwarder of limits the maximum size of log entries to 100,000 byte . That sounds more than enough , But it doesn't look like that to us .Stacktrace Bigger , And full of irrelevant information , For example, package reacte.code.publisher The above method call in . If Papertrail The transponder sees a long message , Just skip it . That's why the most important log entries are ignored . So what did we do ? We have only achieved the goal of Logback An extension of , The extension removes the program line that contains the package , These packages come from react.core.publisher Start , And will stacktrace Trim to 90,000 Characters .

My conclusion is this , Further efforts are needed to achieve similar functions , Especially if you don't want to see irrelevant information and seriously consider reducing the risk of the problem .


We want to provide discovery to our service users RESTful API The ability of .Swagger Is the most famous and mature tool . Unfortunately , When we see Spring WebFlux Without an integration Library , We were surprised again . After some investigation , It finds that the development of integration is still in progress , Open Swagger UI The only way to do that is to use io.springfox:springfox-spring-webflux Snapshot version of . Using unstable libraries in production ready applications sounds terrible , however , On the other hand ,Swagger Not a key component of our services , Enabled only in non production deployment . We've been using the snapshot version for more than six months , There is no stable version yet . It's pathetic .


If you're lucky , And have MongoDB, Then you don't have to worry about . There is an official reactive driver available . because JDBC The blocking property of , So there's no reactive support for relational databases . That's the problem we're facing . The customer told us , We have to MySQL Use in flavor Aurora DB. The worst part is , When we solve all these problems , It's late in the project , So it's too late to go back to non reactors . What we decided to do was to use the official MySQL The driver , Because we're familiar with it , And we can publish the service very quickly . We are aware of all the limitations , Including the lack of ready-made support for transactional Spring The annotations in , For return Mono / Flux Methods . at present , Our services don't use transaction mechanism at all . But we know the potential consequences .

Fortunately, ,R2DBC The project is under active development . One of the goals is to make SQL Database and reaction API In combination with . It's not an official standard , So we suspect that there will be problems when integrating with other libraries , because JDBC It's been known for many years API. Recently released Spring 5.2 Support to use in the background R2DBC stay Reactive Streams Publishers Reactive transaction management on the Internet . It does sound promising , It's definitely worth a try , But we don't have any experience yet .


  • Your team has to change the way they think , And often reinvent the wheel , To implement patterns that may be well known in sequential blocking methods . If you work with people who don't want to learn , You will soon fail .
  • Many well-known libraries work in a blocking way . A lot of times , Servers that use non blocking paths are not mature enough . Hopefully that will change soon .
  • Based on Spring WebFlux Before starting the project , Please double check what you need and make sure it's available . If you start using reactive flow , You have to use it everywhere . If you want to step back , There's no easy way . You have to change most files , Including testing .


本文为[Jiedao jdon]所创,转载请带上原文链接,感谢

  1. ASP调用SDK微信分享好友、朋友圈
  2. ASP calls SDK wechat to share friends and circle of friends
  3. SpringCloud(六)Bus消息总线
  4. 详解JavaScript中的正则表达式
  5. Springcloud (6) bus message bus
  6. Explain regular expressions in JavaScript
  7. Java 响应式关系数据库连接了解一下
  8. Java14它真的来了, 真是尾气都吃不到了
  9. 视频:使用Docker搭建RabbitMQ环境
  10. Java responsive relational database connection
  11. Java14 it's really coming. I can't eat the exhaust
  12. Video: building rabbitmq environment with docker
  13. SpringCloud(六)Bus消息总线
  14. 详解JavaScript中的正则表达式
  15. Springcloud (6) bus message bus
  16. Explain regular expressions in JavaScript
  17. Docker实战:用docker-compose搭建Laravel开发环境
  18. Docker: building laravel development environment with docker compose
  19. 求助,JAVA如何获取系统当前所有进程
  20. 有人用过JMeter或用HttpUnit写过测试吗????
  21. Help, Java how to get all the current processes of the system
  22. Has anyone ever used JMeter or written tests in httpUnit????
  23. Living in a mountain village in late spring
  24. Partridge day, spring of HKUST
  25. JavaScript异步编程4——Promise错误处理
  26. 海康摄像SDK开发笔记(一):海康威视网络摄像头SDK介绍与模块功能
  27. JavaScript asynchronous programming 4 -- promise error handling
  28. Haikang video SDK development notes (1): introduction and module functions of Hikvision webcam SDK
  29. JOP:用于FPGA的嵌入式实时系统中的Java优化处理器内核
  30. Spring Boot源码:使用MongoDB MongoTemplate公开REST在几分钟内实现CRUD功能
  31. Spring Boot应用程序事件教程 - reflectoring
  32. 带有Resilience4j断路器的Spring云网关 - rome
  33. 经验分享:Apache Kafka的缺点与陷阱 - Emil Koutanov
  34. 通过Spring Boot Webflux实现Reactor Kafka
  35. 从Java 8升级到Java 11应该注意的问题
  36. Jop: Java optimized processor core for FPGA embedded real time system
  37. Spring boot source code: use mongodb mongotemplate to open rest to realize crud function in a few minutes
  38. Spring boot application event tutorial - reflecting
  39. Spring cloud gateway with resilience4j circuit breaker - ROM
  40. Experience sharing: shortcomings and pitfalls of Apache Kafka - Emil koutanov
  41. Realization of reactor Kafka through spring boot Webflux
  42. RPC框架设计----Socket与I/0模型
  43. Problems in upgrading from Java 8 to Java 11
  44. RPC framework design -- socket and I / 0 model
  45. RPC框架设计----I/0模型
  46. RPC framework design: I / 0 model
  47. RPC框架设计----NIO编程缓冲区Buffer
  48. RPC框架设计----NIO编程缓冲区Buffer
  49. RPC framework design -- NiO programming buffer
  50. RPC framework design -- NiO programming buffer
  51. Java多线程基础
  52. Java multithreading Foundation
  53. 码农飞升记-00-Java发展历程
  54. Development history of coder-00-java
  55. 码农飞升记-00-Java发展历程
  56. Development history of coder-00-java
  57. Spring and Autumn Moon
  58. Node.js与Spring Boot比较? - Ryan Gleason
  59. Spring WebFlux的明显陷阱 - ŁukaszKyć
  60. Spring创始人Rod大叔对YAML的真实想法