Commit 3c9c40f
[fix](fe) Fix broken pipe risk on stream load redirect with unconsumed request body (#63332)
### What problem does this PR solve?
Issue Number: close #63325
Problem Summary:
**Problem**
- Starting from Doris `3.1.3`, FE uses `Jetty 12`, and this introduced a
compatibility change in the Stream Load redirect path.
- When a Stream Load request is sent to FE, FE may return `307 Temporary
Redirect` before the request body is fully consumed. Under `Jetty 12`,
this behavior is more likely to cause early connection close or reset
while the client is still writing the request body.
- As a result, some `HTTP/1.1` streaming clients may observe errors such
as `BrokenPipeError` or `ConnectionResetError` when sending Stream Load
requests through FE.
- The problem is more visible with chunked uploads, higher network
latency, and clients that continue sending request body data before
fully processing the redirect response.
- In short, this is a compatibility regression introduced by the `Jetty
12` upgrade in Doris `3.1.3` and later.
**Fix**
- We keep the existing FE-to-BE redirect architecture unchanged, so FE
still redirects Stream Load requests to BE instead of proxying the full
request body.
- We add a bounded request-body drain step on the FE Stream Load
redirect path:
- FE first writes the `307 Temporary Redirect` response.
- FE then drains and discards only a bounded amount of the remaining
request body.
- This provides a small compatibility window for in-flight client writes
and reduces the chance of early connection reset.
- We also apply the same handling to token-authenticated Stream Load
requests, so both password-authenticated and token-authenticated paths
behave consistently.
- In addition, we expose Jetty's unconsumed request content read setting
through FE configuration and apply it to HTTP connectors, so operators
can tune Jetty behavior for redirect scenarios where the request body is
not fully consumed.
- To make the compatibility path effective out of the box, this PR also
enables the bounded drain path by default with a `1GB` drain limit and a
`1000ms` idle wait window.
**New Configurations**
- `jetty_server_max_unconsumed_request_content_reads`
- Controls how many extra reads Jetty performs for unconsumed request
content.
- `-1` means unlimited, `0` disables extra reads, and a positive value
sets the maximum number of read attempts.
- Default value in this PR: `-1`.
- This helps tune Jetty behavior after the `Jetty 12` upgrade when FE
returns a response before the request body is fully consumed.
- `stream_load_redirect_bounded_drain_max_bytes`
- Controls the maximum number of request body bytes FE drains after
returning `307` for a Stream Load redirect.
- `0` disables this compatibility logic.
- A positive value enables bounded draining and limits how much data FE
will discard.
- Default value in this PR: `1GB`.
- `stream_load_redirect_bounded_drain_max_idle_time_ms`
- Controls how long FE waits for more readable request body data during
the bounded drain process.
- `0` disables the extra idle wait.
- A positive value provides a small grace window for slow clients or
delayed body chunks, helping absorb in-flight writes without keeping the
connection open indefinitely.
- Default value in this PR: `1000ms`.
**Test Result / Validation**
- Verified the behavior with the same Python `HTTP/1.1` chunked Stream
Load reproduction used during issue analysis.
- Reproduced requests were sent to FE with `Expect: 100-continue`,
`Transfer-Encoding: chunked`, and paced body streaming to maximize the
redirect race window.
- Baseline validation on Doris `3.0` (`9030` / FE `8030`):
- `payload_mb=1`, `chunk_kb=1`, `sleep_ms=0`
- `payload_mb=8`, `chunk_kb=16`, `sleep_ms=10`
- Both requests returned normal `307 Temporary Redirect`.
- Validation on the fixed Doris `3.1.4` instance (`9034` / FE `8034`):
- Before enabling the bounded drain config, the same reproduction still
triggered `BrokenPipeError`.
- After enabling the FE configs below:
- `jetty_server_max_unconsumed_request_content_reads = -1`
- `stream_load_redirect_bounded_drain_max_bytes = 16777216`
- `stream_load_redirect_bounded_drain_max_idle_time_ms = 1000`
- The same two reproduction requests both returned normal `307 Temporary
Redirect`.
- No `BrokenPipeError` or `ConnectionResetError` was observed after the
config took effect.
- The PR now further updates the default bounded drain byte limit from
`16MB` to `1GB`, while keeping the default idle wait at `1000ms`, so the
compatibility path is enabled by default with a more generous drain
window.
**Performance Validation**
- I compared FE redirect response time between the Doris `3.0` baseline
instance (`9030`) and the fixed Doris `3.1.4` instance (`9034`).
- The goal was to check whether the additional bounded drain logic on FE
introduces a noticeable regression compared with the original Jetty 9
behavior.
**Test Setup**
- Reproduction tool: `tools/stream_load_redirect_repro.py`
- Target: FE endpoint on both instances
- Client mode: `httpclient`
- Common parameters:
- `chunk_kb = 16`
- `sleep_ms = 0`
- Payload sizes:
- `32MB`
- `128MB`
- `512MB`
- Each case was executed `3` times on each instance, and the average
`elapsed_seconds` was used for comparison.
**Results**
- `32MB`
- `9030`: `9.515s / 12.032s / 9.727s`
- Average: `10.425s`
- `9034`: `10.695s / 10.847s / 8.763s`
- Average: `10.102s`
- Difference: `9034` was `0.323s` faster, about `3.1%`
- `128MB`
- `9030`: `37.174s / 34.111s / 37.090s`
- Average: `36.125s`
- `9034`: `38.910s / 36.423s / 38.337s`
- Average: `37.890s`
- Difference: `9034` was `1.765s` slower, about `4.9%`
- `512MB`
- `9030`: `157.181s / 161.148s / 174.421s`
- Average: `164.250s`
- `9034`: `172.310s / 176.692s / 160.068s`
- Average: `169.690s`
- Difference: `9034` was `5.440s` slower, about `3.3%`
**Conclusion**
- Across all tested payload sizes, the difference between `9030` and
`9034` stayed within a small range, roughly `-3%` to `+5%`.
- Based on these measurements, the FE bounded drain logic does not show
a significant performance regression compared with the baseline FE
redirect behavior.
- In other words, the fix improves redirect compatibility while keeping
FE redirect response time at a similar level in normal request sizes.
---------
Co-authored-by: yaoxiao <yx136264032@163.com>1 parent 477cb0c commit 3c9c40f
10 files changed
Lines changed: 1459 additions & 85 deletions
File tree
- fe
- fe-common/src/main/java/org/apache/doris/common
- fe-core/src
- main/java/org/apache/doris/httpv2
- config
- rest
- util
- test/java/org/apache/doris/httpv2
- rest
- util
- regression-test/suites/load_p0/stream_load
- scripts
Lines changed: 24 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
380 | 380 | | |
381 | 381 | | |
382 | 382 | | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
383 | 390 | | |
384 | 391 | | |
385 | 392 | | |
| |||
3328 | 3335 | | |
3329 | 3336 | | |
3330 | 3337 | | |
| 3338 | + | |
| 3339 | + | |
| 3340 | + | |
| 3341 | + | |
| 3342 | + | |
| 3343 | + | |
| 3344 | + | |
| 3345 | + | |
| 3346 | + | |
| 3347 | + | |
| 3348 | + | |
| 3349 | + | |
| 3350 | + | |
| 3351 | + | |
| 3352 | + | |
| 3353 | + | |
| 3354 | + | |
3331 | 3355 | | |
3332 | 3356 | | |
3333 | 3357 | | |
| |||
Lines changed: 3 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
53 | 56 | | |
54 | 57 | | |
55 | 58 | | |
| |||
Lines changed: 95 additions & 57 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
| 35 | + | |
35 | 36 | | |
36 | 37 | | |
37 | 38 | | |
| |||
59 | 60 | | |
60 | 61 | | |
61 | 62 | | |
| 63 | + | |
62 | 64 | | |
63 | | - | |
64 | 65 | | |
65 | 66 | | |
66 | 67 | | |
| |||
131 | 132 | | |
132 | 133 | | |
133 | 134 | | |
134 | | - | |
| 135 | + | |
135 | 136 | | |
136 | 137 | | |
137 | 138 | | |
| |||
190 | 191 | | |
191 | 192 | | |
192 | 193 | | |
193 | | - | |
194 | | - | |
| 194 | + | |
195 | 195 | | |
196 | 196 | | |
197 | 197 | | |
| |||
311 | 311 | | |
312 | 312 | | |
313 | 313 | | |
314 | | - | |
315 | | - | |
| 314 | + | |
316 | 315 | | |
317 | | - | |
318 | | - | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
319 | 325 | | |
320 | 326 | | |
321 | 327 | | |
| |||
592 | 598 | | |
593 | 599 | | |
594 | 600 | | |
595 | | - | |
| 601 | + | |
596 | 602 | | |
597 | 603 | | |
598 | 604 | | |
| |||
635 | 641 | | |
636 | 642 | | |
637 | 643 | | |
638 | | - | |
639 | | - | |
640 | | - | |
641 | | - | |
642 | | - | |
643 | | - | |
644 | | - | |
645 | | - | |
646 | | - | |
647 | | - | |
648 | | - | |
649 | | - | |
650 | | - | |
651 | | - | |
652 | | - | |
653 | | - | |
654 | | - | |
655 | | - | |
656 | | - | |
657 | | - | |
658 | | - | |
659 | | - | |
660 | | - | |
| 644 | + | |
661 | 645 | | |
662 | 646 | | |
663 | 647 | | |
| |||
677 | 661 | | |
678 | 662 | | |
679 | 663 | | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
| 672 | + | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
| 694 | + | |
| 695 | + | |
| 696 | + | |
| 697 | + | |
| 698 | + | |
| 699 | + | |
| 700 | + | |
| 701 | + | |
| 702 | + | |
| 703 | + | |
| 704 | + | |
| 705 | + | |
| 706 | + | |
| 707 | + | |
| 708 | + | |
| 709 | + | |
| 710 | + | |
| 711 | + | |
| 712 | + | |
| 713 | + | |
| 714 | + | |
| 715 | + | |
| 716 | + | |
| 717 | + | |
| 718 | + | |
| 719 | + | |
| 720 | + | |
| 721 | + | |
| 722 | + | |
| 723 | + | |
| 724 | + | |
| 725 | + | |
| 726 | + | |
| 727 | + | |
| 728 | + | |
| 729 | + | |
| 730 | + | |
| 731 | + | |
| 732 | + | |
| 733 | + | |
| 734 | + | |
| 735 | + | |
| 736 | + | |
| 737 | + | |
680 | 738 | | |
681 | 739 | | |
682 | 740 | | |
| |||
738 | 796 | | |
739 | 797 | | |
740 | 798 | | |
741 | | - | |
742 | | - | |
743 | | - | |
744 | | - | |
745 | | - | |
746 | | - | |
747 | | - | |
748 | | - | |
749 | | - | |
750 | | - | |
751 | | - | |
752 | | - | |
753 | | - | |
754 | | - | |
755 | | - | |
756 | | - | |
757 | | - | |
758 | | - | |
759 | | - | |
760 | | - | |
761 | | - | |
762 | | - | |
| 799 | + | |
| 800 | + | |
763 | 801 | | |
| 802 | + | |
764 | 803 | | |
765 | | - | |
766 | | - | |
767 | | - | |
| 804 | + | |
768 | 805 | | |
| 806 | + | |
769 | 807 | | |
770 | 808 | | |
771 | 809 | | |
| |||
Lines changed: 32 additions & 19 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
88 | 88 | | |
89 | 89 | | |
90 | 90 | | |
91 | | - | |
92 | | - | |
93 | | - | |
94 | | - | |
95 | | - | |
| 91 | + | |
| 92 | + | |
96 | 93 | | |
97 | 94 | | |
98 | | - | |
99 | | - | |
100 | | - | |
101 | | - | |
| 95 | + | |
| 96 | + | |
102 | 97 | | |
103 | 98 | | |
104 | 99 | | |
105 | 100 | | |
106 | 101 | | |
107 | 102 | | |
108 | | - | |
109 | | - | |
110 | | - | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
111 | 113 | | |
112 | 114 | | |
113 | 115 | | |
114 | | - | |
115 | | - | |
116 | | - | |
117 | | - | |
118 | | - | |
119 | | - | |
120 | | - | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
121 | 134 | | |
122 | 135 | | |
123 | 136 | | |
| |||
0 commit comments