← Về danh sách
Điện toán & Nhúng
#제로카피#sendfile#DMA#RDMA#io_uring
Cập nhật lần cuối · 2026-10-13

Zero-Copy I/O và Kernel Bypass

1. Tổng quan

Zero-Copy là một kỹ thuật tối ưu hóa I/O mà khi truyền dữ liệu từ một phương tiện lưu trữ này sang phương tiện khác, đặc biệt là giữa không gian nhân (kernel space) và không gian người dùng (user space), nó loại bỏ hoặc giảm thiểu các bản sao dư thừa (redundant copy) trong đó CPU trực tiếp sao chép từng byte, để dữ liệu chảy từ nguồn đến đích mà không cần CPU can thiệp. Thay vì "loại bỏ việc sao chép", nó có nghĩa là "loại bỏ việc sao chép bộ nhớ-tới-bộ nhớ do CPU thực hiện"; các phép truyền DMA của thiết bị đĩa và mạng vẫn được giữ nguyên.

Bối cảnh khiến zero-copy trở nên cần thiết nằm ở sự phát triển bất đối xứng của phần cứng. Mạng đã tăng từ 1GbE lên 100GbE và 400GbE, lưu trữ chuyển từ HDD SATA sang SSD NVMe—băng thông tăng hàng chục đến hàng trăm lần—nhưng tốc độ sao chép bộ nhớ (băng thông bộ nhớ) và xung nhịp CPU lại không tăng tương ứng. Kết quả là "CPU sao chép lại dữ liệu đã đọc bao nhiêu lần" trở thành nút cổ chai của thông lượng, chứ không phải "dữ liệu được đọc từ đâu và gửi tới đâu". Để lấp đầy một đường truyền 100GbE cần truyền khoảng 12.5GB mỗi giây; nếu cùng một dữ liệu bị CPU sao chép hai lần như trong đường truyền truyền thống, bus bộ nhớ phải gánh lưu lượng gấp nhiều lần như vậy, và một lõi CPU bị bão hòa chỉ vì làm việc sao chép.

Thuật ngữ zero-copy có phần gây hiểu lầm, bởi các phép truyền DMA mà đĩa hay card mạng dùng để ra vào bộ nhớ là tất yếu về mặt vật lý và do đó không phải là đối tượng loại bỏ. Thứ mà zero-copy tìm cách loại bỏ chỉ là bản sao CPU phát sinh thuần túy vì không gian địa chỉ bị tách biệt bên trong cùng một máy chủ. Vì vậy cụm từ "không có bản sao" phải được hiểu là "không có bản sao CPU dư thừa" mới chính xác, và việc làm rõ sự phân biệt này cho phép ta hiểu không nhầm lẫn mỗi kỹ thuật thực sự loại bỏ cái gì.

Zero-copy nhắm vào ba chi phí. Thứ nhất là lãng phí chu kỳ CPU, vì sao chép là công việc kém hiệu quả nhất mà CPU làm. Thứ hai là tiêu hao băng thông bộ nhớ, vì một lần sao chép tiêu tốn băng thông gấp đôi với một lần đọc cộng một lần ghi. Thứ ba là ô nhiễm cache CPU (cache pollution), vì sao chép lượng lớn dữ liệu sẽ đẩy ra các dòng cache mà logic ứng dụng thực sự cần, làm giảm hiệu năng tổng thể. Trên hết là chi phí chuyển chế độ người dùng/nhân (context switch). Zero-copy nhắm giảm cả bốn điều này cùng lúc, và đã trở thành nguyên lý cốt lõi chống đỡ hiệu năng của các hệ thống truyền tải khối lượng lớn như Apache Kafka, Nginx và Netflix Open Connect.

2. Cấu trúc chi phí của đường truyền I/O truyền thống

Để hiểu giá trị của zero-copy, trước hết phải thấy vì sao đường truyền truyền thống lại đắt đỏ. Hãy xét đoạn mã đơn giản nhất mà máy chủ đọc một tệp từ đĩa và gửi ra socket (read() rồi write()): như hình dưới cho thấy, dữ liệu bị sao chép bốn lần và chuyển chế độ người dùng/nhân bốn lần.

flowchart TB
  subgraph US["Không gian người dùng(User Space)"]
    APP["Tiến trình ứng dụng"]
    UB["Bộ đệm người dùng(user buffer)"]
  end
  subgraph KS["Không gian nhân(Kernel Space)"]
    PC["Page cache(read buffer)"]
    SB["Bộ đệm socket(socket buffer)"]
  end
  DISK[("Đĩa")]
  NIC["NIC(card mạng)"]
  DISK -->|"①sao chép DMA"| PC
  PC -->|"②sao chép CPU"| UB
  UB -->|"③sao chép CPU"| SB
  SB -->|"④sao chép DMA"| NIC
  APP -.->|"gọi read()"| PC
  APP -.->|"gọi write()"| SB

Bản sao thứ nhất (①) là DMA (Direct Memory Access) của bộ điều khiển đĩa chuyển nội dung tệp vào page cache (read buffer) của nhân, không có CPU can thiệp. Bản sao thứ hai (②) là mấu chốt của vấn đề: khi lời gọi hệ thống read() trả về, dữ liệu trong bộ đệm nhân được CPU trực tiếp sao chép vào bộ đệm không gian người dùng. Dù ứng dụng sẽ gửi dữ liệu mà không xử lý gì cả, bản sao này vẫn bị ép buộc chỉ vì không gian địa chỉ bị tách biệt. Bản sao thứ ba (③) là write() lại thực hiện sao chép CPU dữ liệu trong bộ đệm người dùng vào bộ đệm socket của nhân, và chỉ đến bước cuối (④) thì DMA của NIC mới gửi bộ đệm socket ra mạng.

Rốt cuộc, dữ liệu chỉ cần truyền một lần lại bị sao chép tổng cộng bốn lần (DMA 2 lần, CPU 2 lần), trong đó ② và ③ do CPU thực hiện là lãng phí thuần túy. Việc chuyển chế độ cũng xảy ra tổng cộng bốn lần—hai lần trong read() (vào và ra) và hai lần trong write(). Chi phí của bản thân một lần chuyển chế độ nhỏ hơn một lần sao chép, nhưng mỗi lần chuyển làm nhiễu loạn trạng thái TLB, bộ dự đoán rẽ nhánh và cache, khiến chi phí gián tiếp tích lũy.

Mức độ nghiêm trọng của sự lãng phí này tăng tuyến tính khi dữ liệu càng lớn. Ví dụ, truyền một tệp 1GB thì chỉ riêng hai bản sao CPU đã đọc 2GB và ghi 2GB, thêm 4GB lưu lượng vào bus bộ nhớ, và lõi CPU đó không thể xử lý yêu cầu khác cho đến khi việc sao chép kết thúc. Trên các máy chủ web và streaming với hàng nghìn kết nối đồng thời, chi phí sao chép này tích lũy và tạo ra nút cổ chai điển hình nơi thông lượng chạm giới hạn do CPU bão hòa dù mạng và đĩa vẫn còn dư địa. Zero-copy chính là kỹ thuật loại bỏ "khoản thuế CPU và bộ nhớ vô hình" này. Bảng dưới tóm tắt số lần sao chép và chuyển chế độ để so sánh với các kỹ thuật giải thích sau. Các con số là công cụ hỗ trợ so sánh; "vì sao chúng giảm" phải được hiểu qua các nguyên lý trong phần thân bài.

Phương thức Tổng sao chép Sao chép CPU Chuyển chế độ Ghi chú
read + write 4 2 4 Đường truyền truyền thống
mmap + write 3 1 4 Loại bỏ bản sao bộ đệm người dùng
sendfile (cơ bản) 3 1 2 Hoàn tất bên trong nhân
sendfile + SG-DMA 2 0 2 Loại bỏ hoàn toàn bản sao CPU
splice 2 0 2 Truyền tham chiếu dựa trên pipe

Điều cốt lõi cần đọc từ bảng này là "hướng giảm số lần sao chép" và "hướng số bản sao CPU hội tụ về không" là hai trục cải thiện hiệu năng. Hạ hai bản sao CPU của đường truyền truyền thống xuống còn một, rồi xuống không, là mục tiêu chung của các kỹ thuật zero-copy. Giảm bốn lần chuyển chế độ xuống hai cũng là một cải thiện phụ nhưng quan trọng, được thực hiện nhờ một thiết kế như sendfile ủy thác toàn bộ quá trình cho nhân trong một lời gọi hệ thống duy nhất.

3. Các kỹ thuật hiện thực Zero-Copy

Zero-copy không phải một công nghệ đơn lẻ mà là một tập hợp các kỹ thuật loại bỏ dần dần các bản sao và các lần chuyển chế độ. Dưới đây ta xem xét các phương tiện tiêu biểu mà hệ điều hành cung cấp, lấy nguyên lý làm trọng tâm, theo thứ tự giảm số bản sao từng bước một. Sự khác biệt của mỗi kỹ thuật trở nên rõ ràng khi so sánh từ góc nhìn "nó loại bỏ cái gì, và đánh đổi phải chịu những ràng buộc, chi phí nào".

A. mmap + write

mmap() ánh xạ trực tiếp một tệp vào không gian địa chỉ ảo của tiến trình (memory-map) để page cache của nhân và không gian người dùng chia sẻ cùng các trang vật lý. Do đó bản sao CPU (②) của "bộ đệm nhân → bộ đệm người dùng" biến mất. Chỉ cần đọc địa chỉ đã ánh xạ, ứng dụng xem như thấy dữ liệu của page cache nguyên trạng. Tuy nhiên khi sau đó gửi ra socket bằng write(), bản sao CPU (③) của "vùng ánh xạ → bộ đệm socket" vẫn còn, cho ra tổng cộng ba bản sao (DMA 2 + CPU 1).

Cạm bẫy của phương pháp mmap là sự phức tạp phát sinh như cái giá của việc giảm sao chép. Nếu trong lúc truyền, một tiến trình khác cắt ngắn (truncate) hoặc sửa đổi cùng tệp đó, việc truy cập vùng ánh xạ có thể phát sinh tín hiệu SIGBUS và chấm dứt tiến trình bất thường. Ngoài ra, ánh xạ và hủy ánh xạ (mmap/munmap) phát sinh chi phí cập nhật bảng trang và vô hiệu hóa TLB, nên việc ánh xạ các tệp nhỏ thường xuyên sẽ ăn mòn khoản tiết kiệm từ việc giảm sao chép. Vì vậy zero-copy bằng mmap phải được dùng thận trọng trong các tình huống có thể kiểm soát vòng đời tệp, và nó có lợi khi truyền lặp lại các tệp lớn hơn là cho I/O nhỏ, thường xuyên.

B. sendfile

sendfile() là một lời gọi hệ thống truyền dữ liệu trực tiếp bên trong nhân từ một file descriptor sang một socket descriptor. Vì dữ liệu không đi lên không gian người dùng, các bản sao ② và ③ dường như đều bị loại bỏ, nhưng trong hiện thực cơ bản vẫn còn một bản sao CPU chuyển dữ liệu từ page cache sang bộ đệm socket, cho ra tổng cộng ba bản sao. Tuy nhiên số lần chuyển chế độ giảm xuống còn hai vì nó hoàn tất trong một lời gọi hệ thống duy nhất, và trên hết, vì dữ liệu không đi qua không gian người dùng nên ô nhiễm cache và chuyển không gian địa chỉ biến mất. Chỉ thị sendfile on; của Nginx chính là sử dụng lời gọi hệ thống này.

Ràng buộc của sendfile là nó chỉ dùng được khi dữ liệu được chuyển qua nguyên trạng. Nếu phải xử lý nội dung trước khi truyền, hoặc chỉ gửi một phần tùy điều kiện, thì phải kéo dữ liệu lên không gian người dùng, điều này triệt tiêu lợi ích của sendfile. Ngoài ra, vì nguồn phải là một tệp có thể nạp vào page cache, nó không dùng được cho dữ liệu đến từ một pipe hay một socket khác. Thứ xuất hiện để vượt qua các giới hạn này chính là họ splice dưới đây.

C. sendfile + scatter-gather DMA (zero-copy đích thực)

Để loại bỏ cả bản sao CPU cuối cùng, NIC phải có scatter-gather DMA, tức khả năng gom nhiều mảnh bộ nhớ rải rác thành một gói duy nhất để truyền. Nhân Linux 2.4 đã cải tiến cấu trúc bộ mô tả bộ đệm socket để bộ đệm socket chứa, thay vì dữ liệu thực, chỉ thông tin vị trí (địa chỉ) và độ dài (bộ mô tả) của page cache, cho phép NIC thu thập dữ liệu trực tiếp từ page cache qua DMA. Nhờ đó các bản sao CPU trở nên hoàn toàn bằng không, và các bản sao còn lại chỉ là hai phép truyền DMA (đĩa → page cache, page cache → NIC). Đây là thứ thường được gọi là "zero-copy đích thực".

flowchart LR
  APP["Ứng dụng(gọi sendfile)"]
  subgraph KERNEL["Không gian nhân(Kernel Space)"]
    PC["Page cache"]
    DESC["Bộ mô tả bộ đệm socket(chỉ vị trí và độ dài)"]
  end
  DISK[("Đĩa")]
  NIC["NIC(scatter-gather DMA)"]
  DISK -->|"①sao chép DMA"| PC
  PC -->|"②chỉ truyền bộ mô tả(không sao chép dữ liệu)"| DESC
  DESC -->|"③SG-DMA thu thập trực tiếp từ page cache"| NIC
  PC -.->|"dữ liệu vẫn nằm tại page cache"| NIC
  APP -->|"file fd → socket fd"| KERNEL

D. splice / vmsplice và MSG_ZEROCOPY phía gửi

splice() di chuyển tham chiếu tới dữ liệu (con trỏ trang) giữa hai file descriptor thông qua một bộ đệm pipe trong nhân, cho phép truyền không sao chép qua các tổ hợp fd tùy ý (tệp↔tệp, tệp↔socket, v.v.). Vì bộ đệm pipe chỉ giữ tham chiếu tới trang chứ không phải dữ liệu thực, nó thoát khỏi ràng buộc mà sendfile áp đặt rằng "nguồn phải là một tệp", nên zero-copy có thể áp dụng cả cho các mẫu proxy như chuyển tiếp socket-sang-socket. Về phía gửi, nơi ứng dụng muốn gửi dữ liệu do chính nó tạo ra mà không sao chép, cờ MSG_ZEROCOPY (tùy chọn socket SO_ZEROCOPY) được dùng. Trong trường hợp này nhân ghim (pin) các trang vật lý của bộ đệm người dùng, DMA các trang đó trực tiếp tới NIC, và thông báo bất đồng bộ tới hàng đợi hoàn tất khi truyền xong. Không có bản sao, nhưng chi phí mới phát sinh dưới dạng ghim trang và xử lý thông báo, nên lợi ích chỉ lớn với các phép truyền khối lượng lớn với gói lớn và thực ra có thể là thiệt hại với các phép truyền nhỏ. Luôn phải ghi nhớ sự đánh đổi rằng "một chi phí quản lý khác dọn vào nơi bản sao đã bị loại bỏ".

4. Zero-Copy phía nhận và Kernel Bypass: RDMA, DPDK, io_uring

Các kỹ thuật nêu trên chủ yếu xử lý đường gửi (đĩa → mạng), nhưng ở đường nhận và trong các lĩnh vực siêu hiệu năng, kernel bypass—vốn vòng qua chính ngăn xếp mạng của nhân—được sử dụng. So sánh ba cách tiếp cận tiêu biểu làm rõ sự khác biệt và hàm ý thực tiễn của chúng.

RDMA (Remote Direct Memory Access) là công nghệ mà NIC của một nút thực hiện đọc/ghi trực tiếp vào bộ nhớ ứng dụng của một nút khác qua mạng, được hiện thực bằng InfiniBand, RoCE (RDMA over Converged Ethernet) và iWARP. Vì nhân và CPU nằm ngoài đường dữ liệu ở cả hai đầu, "zero-copy đầu cuối" được thiết lập. Vượt trên việc chỉ loại bỏ sao chép, RDMA đặc trưng ở chỗ cung cấp cả phép toán một phía (one-sided) đọc và ghi trực tiếp bộ nhớ từ xa mà không cần CPU từ xa can thiệp, và truyền vòng qua nhân đưa lệnh trực tiếp lên hàng đợi NIC từ không gian người dùng. Kết quả là độ trễ giảm xuống mức micro giây và mức sử dụng CPU hội tụ về gần không. Chính nhờ zero-copy của RDMA mà các cụm HPC và huấn luyện AI có thể kết nối hàng trăm GPU bằng InfiniBand cấp 400Gb/s và thực hiện truyền thông tập thể (all-reduce). Tuy nhiên, vì NIC chịu trách nhiệm về trạng thái kết nối và kiểm soát luồng trong phần cứng, nó phải trả cái giá là khó gỡ lỗi khi sự cố và giảm tính linh hoạt (ossification) khi việc thay đổi tính năng bị ràng buộc vào phần cứng.

DPDK (Data Plane Development Kit) ánh xạ NIC trực tiếp vào không gian người dùng, lấy gói bằng trình điều khiển chế độ thăm dò (PMD) thay vì ngắt, và giảm lỗi TLB bằng trang khổng lồ (hugepage) để vòng qua toàn bộ ngăn xếp nhân. Nó là chuẩn trên thực tế trong các lĩnh vực phải xử lý hàng chục triệu gói mỗi giây, như thiết bị viễn thông, tường lửa và bộ cân bằng tải L4. Đổi lại, nó dành riêng một lõi CPU vĩnh viễn cho việc thăm dò (busy-poll), hy sinh điện năng và lõi.

Lý do DPDK dùng thăm dò thay vì ngắt cũng là "loại bỏ chi phí đầu" theo cùng mạch với zero-copy. Khi hàng chục triệu gói mỗi giây ập tới, chi phí nhận một ngắt cho mỗi gói (chuyển ngữ cảnh, nhiễu loạn cache) vượt quá chi phí xử lý, tạo ra một cơn bão ngắt (interrupt storm). Bằng cách dành một lõi để liên tục kiểm tra các hàng đợi NIC, DPDK loại bỏ hoàn toàn chi phí này và, kết hợp với việc loại bỏ sao chép, đạt tốc độ gói không thể có với một ngăn xếp nhân đa dụng. Việc nó còn đạt được cả tính xác định (determinism) của độ trễ để đổi lấy việc hy sinh điện năng và lõi là lý do nó được ưa chuộng trong lĩnh vực thiết bị viễn thông.

io_uring là giao diện I/O bất đồng bộ của Linux, giảm mạnh chính số lời gọi hệ thống thông qua các vòng đệm hàng đợi gửi (SQ) và hàng đợi hoàn tất (CQ) được chia sẻ giữa người dùng và nhân. Kết hợp với các bộ đệm đã đăng ký trước (registered buffer), nó có thể kìm hãm cả bản sao lẫn chuyển chế độ, và gần đây một tính năng nhận zero-copy (zero-copy receive, zcrx) đã được thêm vào, mở ra con đường nhận payload TCP trực tiếp vào bộ nhớ người dùng. Trong khi RDMA và DPDK vứt bỏ hoàn toàn ngăn xếp nhân, điều quan trọng về mặt thực tiễn là io_uring zero-copy RX chỉ loại bỏ bản sao trong khi vẫn dùng ngăn xếp TCP của nhân nguyên trạng. Đó là vì ta có thể thu được lợi ích zero-copy mà vẫn giữ tính tương thích TCP chuẩn và sự dễ gỡ lỗi.

Ba cách tiếp cận có điểm chung là loại bỏ bản sao ở phía nhận, nhưng thứ chúng từ bỏ để đánh đổi lại khác nhau. Tổ chức các đặc tính trong bảng dưới làm rõ tiêu chí lựa chọn.

Cách tiếp cận Ngăn xếp nhân Sử dụng chính Chi phí chính
RDMA Vòng qua Fabric HPC và huấn luyện AI Phụ thuộc phần cứng, khó gỡ lỗi
DPDK Vòng qua Thiết bị viễn thông, tường lửa, LB Chiếm lõi vĩnh viễn, điện năng
io_uring zcrx Giữ lại Máy chủ hiệu năng cao đa dụng Tương đối mới, phụ thuộc phiên bản nhân

Lý do căn bản khiến ba cách tiếp cận khác nhau nằm ở lựa chọn "từ bỏ ngăn xếp nhân đến mức nào". RDMA và DPDK từ bỏ tính đa dụng, an toàn và khả năng quan sát của nhân để lấy hiệu năng, trong khi io_uring cố giảm chỉ các bản sao mà vẫn bảo toàn chúng. Do đó, một phán đoán thiết kế thông thường là các ứng dụng máy chủ đa dụng chọn họ sendfile/io_uring, còn các thiết bị mạng chuyên dụng và fabric huấn luyện AI chọn DPDK/RDMA.

Lựa chọn này cũng gắn trực tiếp với năng lực của tổ chức vận hành. DPDK và RDMA đòi hỏi tinh chỉnh cấp thấp như quản lý lõi thăm dò, cấu hình trang khổng lồ, đồng bộ phiên bản firmware/driver NIC và kiểm soát tắc nghẽn (PFC/ECN của RoCE), đòi hỏi nhân sự chuyên trách. Ngược lại, các đường sendfile/io_uring chạy trên ngăn xếp nhân chuẩn và có thể dùng các công cụ vận hành và quan sát hiện có nguyên trạng. Rốt cuộc, việc chọn cách tiếp cận zero-copy không chỉ bao gồm các con số hiệu năng thuần túy mà còn cả một phán đoán tổ chức về "chịu đựng được bao nhiêu độ phức tạp", và điểm này đặc biệt quan trọng trong việc ra quyết định thiết kế ở tầm Kỹ sư chuyên nghiệp.

5. Chuyên sâu: Trường hợp áp dụng thực tế và xu hướng mới nhất

Zero-copy không chỉ dừng ở lý thuyết mà thực sự đã chi phối hiệu năng của các dịch vụ quy mô lớn. Ta tóm tắt các trường hợp tiêu biểu và các xu hướng gần đây.

Thứ nhất, Apache Kafka, khi một broker truyền các phân đoạn log trên đĩa tới consumer, dùng FileChannel.transferTo() của Java (bên trong là sendfile) để truyền trực tiếp các thông điệp từ page cache sang socket mà không kéo chúng lên không gian người dùng. Kết hợp với đặc tính của Kafka rằng thông điệp được tiêu thụ nguyên trạng không qua xử lý, zero-copy đạt thông lượng hàng triệu thông điệp mỗi giây dù CPU ít. Đây là một trường hợp kinh điển minh họa nguyên lý rằng "lợi ích zero-copy được tối đa hóa khi ứng dụng không động vào dữ liệu".

Một chi tiết đáng chú ý ở đây là Kafka đọc và gửi dữ liệu không phải từ đĩa mà từ page cache của hệ điều hành. Các thông điệp vừa được tạo gần đây vẫn còn nóng trong page cache, nên khi một consumer tiêu thụ chúng, chúng chảy thẳng từ cache → NIC mà không cần I/O đĩa. Zero-copy kết hợp với page cache tạo ra "độ trễ gần với một hàng đợi trong bộ nhớ dù là một hàng đợi dựa trên đĩa", minh họa rằng zero-copy phát huy sức mạnh khi được thiết kế cùng với việc quản lý bộ nhớ của hệ điều hành chứ không phải như một kỹ thuật đơn lẻ.

Thứ hai, các máy chủ CDN Netflix Open Connect phục vụ hàng chục đến hàng trăm Gb/s video từ một máy duy nhất bằng sendfile bất đồng bộ của FreeBSD. Vấn đề là mã hóa TLS kéo dữ liệu lên không gian người dùng và phá vỡ zero-copy, điều này được giải quyết bằng kTLS (TLS trong nhân). Bằng cách thực hiện mã hóa trong nhân (hoặc như một offload NIC), zero-copy—trong đó dữ liệu không đi qua không gian người dùng—được duy trì ngay cả với lưu lượng đã mã hóa. Là một thiết kế hòa giải an ninh và zero-copy bằng cách hạ điểm mã hóa xuống nhân khi hai bên xung đột, nó đã trở thành mẫu hình chuẩn để bảo toàn zero-copy trong truyền tải an toàn hiện đại.

Thứ ba, trung tâm dữ liệu AI và GPUDirect. Trong huấn luyện mô hình quy mô lớn, GPUDirect RDMA và GPUDirect Storage, qua đó một NIC hoặc SSD NVMe DMA trực tiếp vào bộ nhớ GPU, là trung tâm; điều này mở rộng khái niệm zero-copy "dữ liệu không đi vòng qua bộ nhớ CPU" sang lĩnh vực GPU. Vì không đi qua CPU và bộ nhớ hệ thống, nó giảm tình trạng đói dữ liệu (starvation) của GPU và làm dịu các nút cổ chai trong đường ống huấn luyện.

Thứ tư, sự trưởng thành của mạng zero-copy io_uring. Nhận zero-copy dựa trên io_uring do Meta dẫn dắt dùng tách tiêu đề (header splitting) và lái luồng (flow steering) để chỉ payload được nhận trực tiếp vào bộ nhớ người dùng, và trong một bài trình bày tại Kernel Recipes 2024 nó đã tiến tới chỗ hiệu quả ngay cả ở các kích thước truyền nhỏ và tương thích với TCP nguyên bản. Nó thu hút chú ý như một nỗ lực thu hẹp sự căng thẳng lâu đời giữa hiệu năng của kernel bypass và tính đa dụng của ngăn xếp nhân.

Xu hướng xuyên suốt bốn trường hợp này là zero-copy, vốn khởi đầu ở lĩnh vực hẹp "gửi và truyền tệp", đang mở rộng sang đường nhận, đoạn mã hóa, bộ nhớ GPU, và I/O bất đồng bộ nói chung. Trong kỷ nguyên AI và streaming khối lượng lớn nơi chi phí di chuyển dữ liệu lấn át chi phí tính toán, zero-copy đang được nâng tầm từ vấn đề của một lời gọi hệ thống cụ thể thành một nguyên tắc thiết kế kiến trúc là "để dữ liệu chảy từ nguồn tới nơi tiêu thụ mà không đi qua CPU".

6. Những điểm cần cân nhắc và hàm ý

Từ góc nhìn của Kỹ sư chuyên nghiệp, khi áp dụng và thiết kế zero-copy, cần phán đoán các điều sau một cách toàn diện.

  • Chiến lược áp dụng — "có động vào dữ liệu hay không" là tiền đề: Lợi ích lớn nhất của zero-copy phát sinh khi ứng dụng chuyển tiếp dữ liệu nguyên trạng mà không biến đổi nó. Các khối lượng công việc dạng chuyển qua (pass-through) như máy chủ tệp, CDN, message broker và proxy là ứng viên hàng đầu. Ngược lại, nếu cần biến đổi dữ liệu như nén, mã hóa hay lọc, trước hết phải xem xét liệu có thể bảo toàn đoạn zero-copy bằng cách hạ điểm xử lý đó xuống nhân (kTLS), offload NIC, hay GPU hay không.

  • Đánh đổi — chi phí phát sinh nơi bản sao đã bị loại bỏ: Zero-copy không miễn phí. Các chi phí quản lý và độ phức tạp mới đi kèm, như ghim trang (pinning), thông báo hoàn tất bất đồng bộ, rủi ro SIGBUS của mmap, việc chiếm lõi vĩnh viễn của DPDK, và độ khó gỡ lỗi cùng sự phụ thuộc phần cứng của RDMA. Đặc biệt với I/O nhỏ, thường xuyên, chi phí quản lý có thể vượt quá khoản tiết kiệm sao chép và thực ra chậm hơn, nên phải kiểm chứng bằng benchmark rằng đơn vị truyền đủ lớn trước khi áp dụng.

  • Triển vọng — sự hội tụ của kernel bypass và tính đa dụng: Trong khi trước đây đó là lựa chọn một-hoặc-khác giữa từ bỏ nhân để lấy hiệu năng cực đại (DPDK/RDMA) hay ở lại trong nhân (sendfile), io_uring zero-copy RX, AF_XDP và kTLS đang hội tụ về "chỉ loại bỏ bản sao trong khi bảo toàn tính an toàn và khả năng quan sát của ngăn xếp nhân". Khi thiết kế một hệ thống mới, ưu tiên một đường zero-copy cùng tồn tại với ngăn xếp chuẩn hơn là bypass toàn phần với sự phụ thuộc phần cứng nặng nề là có lợi về mặt bảo trì và khả năng chuyển dịch.

  • Sự tương thích với các công nghệ liên quan: Zero-copy không phải một công nghệ đơn lẻ và phải được hiểu cùng với DMA, page cache, bộ nhớ ảo (mmap), NUMA, trang khổng lồ, và TLS cùng TCP offload của tầng truyền tải. Đặc biệt trong môi trường NUMA, lợi ích zero-copy chỉ hiện thực hóa đầy đủ khi dữ liệu, NIC và CPU ở trên cùng một nút, nên phải tinh chỉnh cả ái lực ngắt (IRQ affinity) và việc bố trí bộ nhớ. Về mặt khả năng quan sát, vì các bản sao biến mất, các nút cổ chai có thể không lộ ra chỉ từ việc phân tích CPU truyền thống, nên phải giám sát cả các chỉ số như băng thông bộ nhớ, DMA và độ sâu hàng đợi NIC.

  • Cân nhắc về an ninh và ổn định: Một cấu trúc trong đó nhân và NIC truy cập trực tiếp các bộ đệm người dùng nghĩa là bề mặt tấn công mở rộng đánh đổi lấy hiệu năng. Trừ khi việc sửa đổi bộ đệm trong lúc ghim trang, việc kiểm tra ranh giới vùng DMA, và việc kiểm soát quyền truy cập bộ nhớ từ xa trong RDMA được thiết kế nghiêm ngặt, tính toàn vẹn và cô lập dữ liệu có thể bị phá vỡ. Việc tối ưu hiệu năng nên được áp dụng cùng với các cơ chế bảo vệ phần cứng như IOMMU để không làm suy yếu mô hình an ninh.

Tài liệu tham khảo


Tóm tắt một câu: Zero-copy là một tối ưu hóa I/O loại bỏ các bản sao CPU giữa không gian nhân và người dùng để tiết kiệm CPU, băng thông bộ nhớ và cache; nó trải từ mmap, sendfile, SG-DMA và splice cho tới kernel bypass của RDMA, DPDK và io_uring, chống đỡ hiệu năng truyền tải khối lượng lớn của Kafka, Netflix và các trung tâm dữ liệu AI, song là một kỹ thuật dựa trên đánh đổi mang lại hiệu quả lớn nhất "khi không động vào dữ liệu".