You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celeborn.apache.org by ni...@apache.org on 2026/04/15 11:10:21 UTC

(celeborn) branch main updated: [CELEBORN-2301] MessageEncoder enables zero-copy sendfile for FileRegion in Netty native transports

This is an automated email from the ASF dual-hosted git repository.

nicholasjiang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/celeborn.git


The following commit(s) were added to refs/heads/main by this push:
     new 95419e14a [CELEBORN-2301] MessageEncoder enables zero-copy sendfile for FileRegion in Netty native transports
95419e14a is described below

commit 95419e14a0d1986a4582a6364057193dce296992
Author: SteNicholas <pr...@163.com>
AuthorDate: Wed Apr 15 19:10:11 2026 +0800

    [CELEBORN-2301] MessageEncoder enables zero-copy sendfile for FileRegion in Netty native transports
    
    ### What changes were proposed in this pull request?
    
    `MessageEncoder` enables zero-copy sendfile for `FileRegion` in Netty native transports, which emits the header `ByteBuf` and `FileRegion` as **separate objects** in the outbound message list when the body is a `FileRegion` backed by `FileSegmentManagedBuffer`, instead of wrapping them together in a `MessageWithHeader`.
    
    Previously, all messages with a body were unconditionally wrapped in `MessageWithHeader`. This caused native transports (EPOLL, KQUEUE) to fall into a generic `FileRegion.transferTo()` fallback path that copies data through user-space, bypassing the optimized `sendfile()` / `splice()` zero-copy path that Netty's native transports provide.
    
    The split is only applied when the `ManagedBuffer` is a `FileSegmentManagedBuffer`, whose `release()` is a no-op, making it safe to emit the `FileRegion` independently of write lifecycle management. Other `ManagedBuffer` types (e.g., `BlockManagerManagedBuffer`) still use the `MessageWithHeader` wrapper because they perform resource cleanup in `release()` that must be tied to `MessageWithHeader.deallocate()`.
    
    Backport: https://github.com/apache/spark/pull/55087.
    
    ### Why are the changes needed?
    
    When using native transports (AUTO/EPOLL on Linux), file-backed shuffle fetch performance was severely degraded compared to NIO mode. The root cause lies in how Netty's native transports dispatch `FileRegion` writes.
    
    In `AbstractEpollStreamChannel.doWriteSingle()` (and the analogous KQueue path), Netty uses an `instanceof` check to choose between two write strategies:
    
    https://github.com/netty/netty/blob/eeb5674526f0b49a142580686a5a9a7147ddadec/transport-classes-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollStreamChannel.java#L474-L493
    
    ```java
    } else if (msg instanceof DefaultFileRegion) {
        return writeDefaultFileRegion(in, (DefaultFileRegion) msg);  // → socket.sendFile() (zero-copy)
    } else if (msg instanceof FileRegion) {
        return writeFileRegion(in, (FileRegion) msg);                // → region.transferTo() (user-space copy)
    }
    ```
    
    - **`writeDefaultFileRegion()`** calls `socket.sendFile()`, which maps directly to the Linux `sendfile()` syscall — a true zero-copy path where data is transferred from the file page cache to the socket buffer entirely within the kernel, with no user-space copy.
    
    https://github.com/netty/netty/blob/eeb5674526f0b49a142580686a5a9a7147ddadec/transport-classes-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollStreamChannel.java#L367-L386
    
    ```java
        private int writeDefaultFileRegion(ChannelOutboundBuffer in, DefaultFileRegion region) throws Exception {
            final long offset = region.transferred();
            final long regionCount = region.count();
            if (offset >= regionCount) {
                in.remove();
                return 0;
            }
    
            final long flushedAmount = socket.sendFile(region, region.position(), offset, regionCount - offset);
            if (flushedAmount > 0) {
                in.progress(flushedAmount);
                if (region.transferred() >= regionCount) {
                    in.remove();
                }
                return 1;
            } else if (flushedAmount == 0) {
                validateFileRegion(region, offset);
            }
            return WRITE_STATUS_SNDBUF_FULL;
        }
    ```
    
    - **`writeFileRegion()`** falls back to `region.transferTo(WritableByteChannel)`, which writes data through a `SocketWritableByteChannel` wrapper — effectively a user-space copy path.
    
    https://github.com/netty/netty/blob/eeb5674526f0b49a142580686a5a9a7147ddadec/transport-classes-epoll/src/main/java/io/netty/channel/epoll/AbstractEpollStreamChannel.java#L402-L420
    
    ```java
    private int writeFileRegion(ChannelOutboundBuffer in, FileRegion region) throws Exception {
            if (region.transferred() >= region.count()) {
                in.remove();
                return 0;
            }
    
            if (byteChannel == null) {
                byteChannel = new EpollSocketWritableByteChannel();
            }
            final long flushedAmount = region.transferTo(byteChannel, region.transferred());
            if (flushedAmount > 0) {
                in.progress(flushedAmount);
                if (region.transferred() >= region.count()) {
                    in.remove();
                }
                return 1;
            }
            return WRITE_STATUS_SNDBUF_FULL;
        }
    ```
    
    Spark's `MessageWithHeader extends AbstractFileRegion` (not `DefaultFileRegion`). When `MessageEncoder` wraps a `DefaultFileRegion` body inside `MessageWithHeader`, the resulting object is a generic `FileRegion` from Netty's perspective. This means Netty dispatches it to the `writeFileRegion()` fallback, which calls `MessageWithHeader.transferTo()`:
    
    ```java
    // MessageWithHeader.java, line 121
    if (body instanceof FileRegion fileRegion) {
        writtenBody = fileRegion.transferTo(target, totalBytesTransferred - headerLength);
    }
    ```
    
    Here, even though the inner body is a `DefaultFileRegion`, its `transferTo()` is invoked with a `WritableByteChannel` (not a file descriptor), so the data is read from the file into a user-space buffer and then written to the socket — **the zero-copy opportunity is lost**.
    
    By emitting the `DefaultFileRegion` directly into Netty's outbound buffer (instead of wrapping it in `MessageWithHeader`), Netty's native transport recognizes it via `instanceof DefaultFileRegion` and routes it to `socket.sendFile()`, restoring the zero-copy `sendfile()` path.
    
    **Benchmark results (File-Backed Shuffle Fetch) show dramatic improvement:**
    
    | Scenario | Before (ms) | After (ms) | Improvement |
    |---|---|---|---|
    | EPOLL, sequential fetch (JDK8) | 524 | 134 | **~3.9x faster** |
    | EPOLL, parallel fetch (JDK8) | 191 | 55 | **~3.4x faster** |
    
    ### Does this PR resolve a correctness bug?
    
    No.
    
    ### Does this PR introduce _any_ user-facing change?
    
    No. This is an internal optimization to the Netty transport layer. Users benefit from improved shuffle fetch performance when using native transports (the default on Linux) without any configuration changes.
    
    ### How was this patch tested?
    
    - Re-ran `NettyTransportBenchmark` with JDK8 to confirm the performance improvement. Updated benchmark result files accordingly.
    
    Closes #3649 from SteNicholas/CELEBORN-2301.
    
    Lead-authored-by: SteNicholas <pr...@163.com>
    Co-authored-by: Cheng Pan <ch...@apache.org>
    Signed-off-by: SteNicholas <pr...@163.com>
---
 .../NettyTransportBenchmark-jdk17-results.txt      | 46 +++++++++++-----------
 .../benchmarks/NettyTransportBenchmark-results.txt | 46 +++++++++++-----------
 .../common/network/protocol/MessageEncoder.java    | 22 +++++++++--
 .../NettyTransportBenchmark-jdk17-results.txt      |  8 ++--
 .../benchmarks/NettyTransportBenchmark-results.txt | 10 +++++
 5 files changed, 79 insertions(+), 53 deletions(-)

diff --git a/common/benchmarks/NettyTransportBenchmark-jdk17-results.txt b/common/benchmarks/NettyTransportBenchmark-jdk17-results.txt
index 01f862bab..4929f77f6 100644
--- a/common/benchmarks/NettyTransportBenchmark-jdk17-results.txt
+++ b/common/benchmarks/NettyTransportBenchmark-jdk17-results.txt
@@ -6,7 +6,7 @@ OpenJDK 64-Bit Server VM 17.0.15+6-LTS on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 RPC Latency (1 KB):                       Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-1 KB payload                                        524            533          16          0.0      104753.3       1.0X
+1 KB payload                                        542            543           2          0.0      108326.3       1.0X
 
 
 ================================================================================================
@@ -17,7 +17,7 @@ OpenJDK 64-Bit Server VM 17.0.15+6-LTS on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 RPC Latency (64 KB):                      Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-64 KB payload                                      2521           2532          10          0.0      504112.3       1.0X
+64 KB payload                                      2523           2532           9          0.0      504581.0       1.0X
 
 
 ================================================================================================
@@ -28,7 +28,7 @@ OpenJDK 64-Bit Server VM 17.0.15+6-LTS on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 RPC Latency (1 MB):                       Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-1 MB payload                                       6438           6451          13          0.0     6438320.7       1.0X
+1 MB payload                                       6319           6346          18          0.0     6319330.2       1.0X
 
 
 ================================================================================================
@@ -39,7 +39,7 @@ OpenJDK 64-Bit Server VM 17.0.15+6-LTS on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 RPC Latency (16 MB):                      Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-16 MB payload                                      9923          10034         103          0.0    99231610.5       1.0X
+16 MB payload                                      9935           9955          17          0.0    99354584.9       1.0X
 
 
 ================================================================================================
@@ -50,10 +50,10 @@ OpenJDK 64-Bit Server VM 17.0.15+6-LTS on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 Concurrent RPC Throughput:                Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-1 client(s)                                        2049           2097          50          0.0      102469.1       1.0X
-4 client(s)                                        1325           1355          30          0.0       66251.5       1.5X
-8 client(s)                                        1121           1142          18          0.0       56046.7       1.8X
-16 client(s)                                       1095           1106          10          0.0       54742.0       1.9X
+1 client(s)                                        2107           2126          19          0.0      105337.8       1.0X
+4 client(s)                                        1298           1311          21          0.0       64893.4       1.6X
+8 client(s)                                        1089           1090           1          0.0       54449.8       1.9X
+16 client(s)                                       1062           1071           8          0.0       53109.7       2.0X
 
 
 ================================================================================================
@@ -64,8 +64,8 @@ OpenJDK 64-Bit Server VM 17.0.15+6-LTS on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 IOMode Comparison:                        Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-NIO (8 clients)                                    5399           5459          83          0.0      269943.5       1.0X
-EPOLL (8 clients)                                  5288           5374          84          0.0      264393.7       1.0X
+NIO (8 clients)                                    5308           5350          37          0.0      265385.4       1.0X
+EPOLL (8 clients)                                  5274           5323          81          0.0      263709.2       1.0X
 
 
 ================================================================================================
@@ -76,11 +76,11 @@ OpenJDK 64-Bit Server VM 17.0.15+6-LTS on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 Server Thread Scaling:                    Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-2 server threads                                   1034           1044           9          0.0       51713.7       1.0X
-4 server threads                                   1059           1062           4          0.0       52962.1       1.0X
-8 server threads                                   1074           1076           3          0.0       53712.2       1.0X
-16 server threads                                  1090           1101          16          0.0       54503.7       0.9X
-32 server threads                                  1069           1145          68          0.0       53447.3       1.0X
+2 server threads                                   1026           1038          18          0.0       51319.9       1.0X
+4 server threads                                   1036           1055          22          0.0       51798.3       1.0X
+8 server threads                                   1055           1070          21          0.0       52728.9       1.0X
+16 server threads                                  1074           1092          16          0.0       53722.5       1.0X
+32 server threads                                  1063           1085          24          0.0       53163.1       1.0X
 
 
 ================================================================================================
@@ -91,9 +91,9 @@ OpenJDK 64-Bit Server VM 17.0.15+6-LTS on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 Multi-Connection Throughput:              Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-1 conn(s), 4 threads                              31793          32359         883          0.0     6358548.8       1.0X
-2 conn(s), 4 threads                              20196          20265          63          0.0     4039234.4       1.6X
-4 conn(s), 4 threads                              17268          17333          81          0.0     3453573.5       1.8X
+1 conn(s), 4 threads                              31614          31678          97          0.0     6322732.4       1.0X
+2 conn(s), 4 threads                              19714          19852         231          0.0     3942701.6       1.6X
+4 conn(s), 4 threads                              17548          17570          37          0.0     3509596.0       1.8X
 
 
 ================================================================================================
@@ -104,9 +104,9 @@ OpenJDK 64-Bit Server VM 17.0.15+6-LTS on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 Async Write Throughput:                   Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-1 KB async burst                                     73             74           1          0.1       14656.2       1.0X
-64 KB async burst                                  2247           2255          10          0.0      449355.7       0.0X
-1 MB async burst                                  31720          31831          98          0.0     6343939.2       0.0X
+1 KB async burst                                     73             73           0          0.1       14565.2       1.0X
+64 KB async burst                                  2236           2248          14          0.0      447104.2       0.0X
+1 MB async burst                                  31238          31611         328          0.0     6247618.2       0.0X
 
 
 ================================================================================================
@@ -117,7 +117,7 @@ OpenJDK 64-Bit Server VM 17.0.15+6-LTS on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 16 MB Block Transfer:                     Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-Sequential sends                                  10197          10222          29          0.0   101965659.2       1.0X
-4-thread parallel sends                            5498           5508          16          0.0    54980188.1       1.9X
+Sequential sends                                  10005          10026          19          0.0   100045679.2       1.0X
+4-thread parallel sends                            5561           5603          42          0.0    55611823.9       1.8X
 
 
diff --git a/common/benchmarks/NettyTransportBenchmark-results.txt b/common/benchmarks/NettyTransportBenchmark-results.txt
index 7fd5ed27b..41e32b0b4 100644
--- a/common/benchmarks/NettyTransportBenchmark-results.txt
+++ b/common/benchmarks/NettyTransportBenchmark-results.txt
@@ -6,7 +6,7 @@ OpenJDK 64-Bit Server VM 1.8.0_432-b06 on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 RPC Latency (1 KB):                       Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-1 KB payload                                        522            537          17          0.0      104306.4       1.0X
+1 KB payload                                        517            532          12          0.0      103490.9       1.0X
 
 
 ================================================================================================
@@ -17,7 +17,7 @@ OpenJDK 64-Bit Server VM 1.8.0_432-b06 on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 RPC Latency (64 KB):                      Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-64 KB payload                                      2484           2516          47          0.0      496880.6       1.0X
+64 KB payload                                      2508           2517           6          0.0      501590.8       1.0X
 
 
 ================================================================================================
@@ -28,7 +28,7 @@ OpenJDK 64-Bit Server VM 1.8.0_432-b06 on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 RPC Latency (1 MB):                       Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-1 MB payload                                       6370           6382          12          0.0     6370193.2       1.0X
+1 MB payload                                       6399           6413          14          0.0     6399139.2       1.0X
 
 
 ================================================================================================
@@ -39,7 +39,7 @@ OpenJDK 64-Bit Server VM 1.8.0_432-b06 on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 RPC Latency (16 MB):                      Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-16 MB payload                                      9727           9768          31          0.0    97271624.0       1.0X
+16 MB payload                                      9819           9850          26          0.0    98189870.3       1.0X
 
 
 ================================================================================================
@@ -50,10 +50,10 @@ OpenJDK 64-Bit Server VM 1.8.0_432-b06 on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 Concurrent RPC Throughput:                Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-1 client(s)                                        2007           2082          70          0.0      100368.0       1.0X
-4 client(s)                                        1241           1257          21          0.0       62035.5       1.6X
-8 client(s)                                        1042           1051          12          0.0       52077.6       1.9X
-16 client(s)                                       1024           1027           4          0.0       51206.5       2.0X
+1 client(s)                                        2065           2125          54          0.0      103235.1       1.0X
+4 client(s)                                        1310           1323          21          0.0       65499.8       1.6X
+8 client(s)                                        1095           1109          18          0.0       54769.4       1.9X
+16 client(s)                                       1076           1091          26          0.0       53780.7       1.9X
 
 
 ================================================================================================
@@ -64,8 +64,8 @@ OpenJDK 64-Bit Server VM 1.8.0_432-b06 on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 IOMode Comparison:                        Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-NIO (8 clients)                                    5146           5173          26          0.0      257286.2       1.0X
-EPOLL (8 clients)                                  5044           5071          26          0.0      252196.6       1.0X
+NIO (8 clients)                                    5318           5406         103          0.0      265893.9       1.0X
+EPOLL (8 clients)                                  5268           5276           9          0.0      263424.9       1.0X
 
 
 ================================================================================================
@@ -76,11 +76,11 @@ OpenJDK 64-Bit Server VM 1.8.0_432-b06 on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 Server Thread Scaling:                    Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-2 server threads                                    983            995          14          0.0       49167.8       1.0X
-4 server threads                                   1001           1014          20          0.0       50042.0       1.0X
-8 server threads                                   1015           1026          19          0.0       50737.9       1.0X
-16 server threads                                  1027           1052          31          0.0       51332.2       1.0X
-32 server threads                                  1032           1035           3          0.0       51618.3       1.0X
+2 server threads                                   1029           1040          12          0.0       51447.7       1.0X
+4 server threads                                   1044           1056          15          0.0       52218.0       1.0X
+8 server threads                                   1069           1073           5          0.0       53426.7       1.0X
+16 server threads                                  1089           1094           8          0.0       54428.8       0.9X
+32 server threads                                  1074           1089          16          0.0       53677.8       1.0X
 
 
 ================================================================================================
@@ -91,9 +91,9 @@ OpenJDK 64-Bit Server VM 1.8.0_432-b06 on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 Multi-Connection Throughput:              Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-1 conn(s), 4 threads                              31726          32399        1076          0.0     6345298.2       1.0X
-2 conn(s), 4 threads                              20641          20946         386          0.0     4128100.8       1.5X
-4 conn(s), 4 threads                              16958          17319         370          0.0     3391650.7       1.9X
+1 conn(s), 4 threads                              31761          31870         150          0.0     6352209.9       1.0X
+2 conn(s), 4 threads                              19727          19948         208          0.0     3945437.8       1.6X
+4 conn(s), 4 threads                              17511          17600         109          0.0     3502141.6       1.8X
 
 
 ================================================================================================
@@ -104,9 +104,9 @@ OpenJDK 64-Bit Server VM 1.8.0_432-b06 on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 Async Write Throughput:                   Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-1 KB async burst                                     70             72           2          0.1       14087.9       1.0X
-64 KB async burst                                  2240           2256          17          0.0      447946.2       0.0X
-1 MB async burst                                  32199          32584         341          0.0     6439790.4       0.0X
+1 KB async burst                                     71             72           1          0.1       14168.1       1.0X
+64 KB async burst                                  2248           2253           5          0.0      449555.6       0.0X
+1 MB async burst                                  31651          31739         148          0.0     6330120.0       0.0X
 
 
 ================================================================================================
@@ -117,7 +117,7 @@ OpenJDK 64-Bit Server VM 1.8.0_432-b06 on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 16 MB Block Transfer:                     Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-Sequential sends                                  10263          10475         187          0.0   102625029.7       1.0X
-4-thread parallel sends                            5428           5509          71          0.0    54275773.9       1.9X
+Sequential sends                                  10199          10223          20          0.0   101991654.7       1.0X
+4-thread parallel sends                            5584           5603          19          0.0    55840049.8       1.8X
 
 
diff --git a/common/src/main/java/org/apache/celeborn/common/network/protocol/MessageEncoder.java b/common/src/main/java/org/apache/celeborn/common/network/protocol/MessageEncoder.java
index 91c695c4f..6f124becc 100644
--- a/common/src/main/java/org/apache/celeborn/common/network/protocol/MessageEncoder.java
+++ b/common/src/main/java/org/apache/celeborn/common/network/protocol/MessageEncoder.java
@@ -22,11 +22,13 @@ import java.util.List;
 import io.netty.buffer.ByteBuf;
 import io.netty.channel.ChannelHandler;
 import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.FileRegion;
 import io.netty.handler.codec.MessageToMessageEncoder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.celeborn.common.metrics.source.AbstractSource;
+import org.apache.celeborn.common.network.buffer.FileSegmentManagedBuffer;
 
 /**
  * Encoder used by the server side to encode server-to-client responses. This encoder is stateless
@@ -87,9 +89,23 @@ public final class MessageEncoder extends MessageToMessageEncoder<Message> {
     assert header.writableBytes() == 0;
 
     if (body != null) {
-      // We transfer ownership of the reference on in.body() to MessageWithHeader.
-      // This reference will be freed when MessageWithHeader.deallocate() is called.
-      out.add(new MessageWithHeader(in.body(), header, body, bodyLength, source));
+      if (body instanceof FileRegion && in.body() instanceof FileSegmentManagedBuffer) {
+        // Emit header and FileRegion as separate objects so that native transports
+        // (EPOLL, KQUEUE) can apply zero-copy sendfile/splice on the FileRegion directly.
+        // When wrapped in MessageWithHeader, native transports fall into a generic
+        // FileRegion.transferTo() fallback that copies data through user-space, bypassing
+        // the optimized sendfile() path.
+        //
+        // This split is only safe when the ManagedBuffer is FileSegmentManagedBuffer,
+        // whose release() is a no-op. Other ManagedBuffer types perform resource cleanup in
+        // release() that must be tied to the write lifecycle via MessageWithHeader.deallocate().
+        out.add(header);
+        out.add(body);
+      } else {
+        // We transfer ownership of the reference on in.body() to MessageWithHeader.
+        // This reference will be freed when MessageWithHeader.deallocate() is called.
+        out.add(new MessageWithHeader(in.body(), header, body, bodyLength, source));
+      }
     } else {
       out.add(header);
     }
diff --git a/worker/benchmarks/NettyTransportBenchmark-jdk17-results.txt b/worker/benchmarks/NettyTransportBenchmark-jdk17-results.txt
index 9f466d3ce..797fd518d 100644
--- a/worker/benchmarks/NettyTransportBenchmark-jdk17-results.txt
+++ b/worker/benchmarks/NettyTransportBenchmark-jdk17-results.txt
@@ -6,9 +6,9 @@ OpenJDK 64-Bit Server VM 17.0.15+6-LTS on Linux 6.18.7-76061807-generic
 Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
 File-Backed Shuffle Fetch:                Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
 ------------------------------------------------------------------------------------------------------------------------
-NIO, sequential fetch                             10207          10316         131          0.0   102070276.3       1.0X
-NIO, parallel fetch (4 clients)                    5310           5320           9          0.0    53099106.5       1.9X
-EPOLL, sequential fetch                           10032          10061          32          0.0   100317608.1       1.0X
-EPOLL, parallel fetch (4 clients)                  5515           5606         115          0.0    55150042.8       1.9X
+NIO, sequential fetch                             10546          10568          25          0.0   105462185.1       1.0X
+NIO, parallel fetch (4 clients)                    5333           5349          15          0.0    53330277.2       2.0X
+EPOLL, sequential fetch                           10457          10526          65          0.0   104571647.3       1.0X
+EPOLL, parallel fetch (4 clients)                  5245           5260          22          0.0    52452328.1       2.0X
 
 
diff --git a/worker/benchmarks/NettyTransportBenchmark-results.txt b/worker/benchmarks/NettyTransportBenchmark-results.txt
index 16488f3f3..485c45dd6 100644
--- a/worker/benchmarks/NettyTransportBenchmark-results.txt
+++ b/worker/benchmarks/NettyTransportBenchmark-results.txt
@@ -2,3 +2,13 @@
 File-Backed Shuffle Block Fetch (NIO vs EPOLL/KQUEUE, 100x16MB)
 ================================================================================================
 
+OpenJDK 64-Bit Server VM 1.8.0_432-b06 on Linux 6.18.7-76061807-generic
+Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
+File-Backed Shuffle Fetch:                Best Time(ms)   Avg Time(ms)   Stdev(ms)    Rate(M/s)   Per Row(ns)   Relative
+------------------------------------------------------------------------------------------------------------------------
+NIO, sequential fetch                             10302          10317          22          0.0   103016261.6       1.0X
+NIO, parallel fetch (4 clients)                    5564           5678         179          0.0    55636186.2       1.9X
+EPOLL, sequential fetch                           10311          10322          10          0.0   103107776.4       1.0X
+EPOLL, parallel fetch (4 clients)                  5550           5563          17          0.0    55499423.4       1.9X
+
+