Socket TCP dapat menahan write kecil alih-alih langsung mengirimkannya ketika data sebelumnya belum menerima acknowledgment. Perilaku ini berasal dari penggabungan Nagle: aliran segmen TCP kecil dibatasi dengan membiarkan data yang masih outstanding memengaruhi pengiriman byte yang baru masuk antrean.
Di Linux, pengaturan TCP_NODELAY menonaktifkan aturan penggabungan tersebut untuk socket. Write kecil menjadi memenuhi syarat untuk segera dikirim, dengan tetap tunduk pada bagian lain dari stack TCP, congestion control, flow control, keadaan antrean, dan penjadwalan perangkat.
Opsi ini mengubah keputusan batching di sisi pengirim. TCP tidak berubah menjadi protokol berbasis pesan, buffering tidak hilang, satu write() tidak dipaksa menjadi satu packet, dan batas latensi tetap tidak dijamin.
Penggabungan Nagle bereaksi terhadap data yang masih outstanding
TCP menyediakan byte stream yang berurutan. Batas write aplikasi tidak menentukan batas segmen di jaringan.
Tanpa TCP_NODELAY, pengirim dapat menggabungkan sedikit data yang mengantre ketika data yang dikirim sebelumnya masih belum menerima acknowledgment. Tujuannya mencegah rangkaian segmen kecil yang terus-menerus saat aplikasi menghasilkan write kecil lebih cepat daripada acknowledgment yang kembali.
Perilaku ini bergantung pada keadaan koneksi. Write kecil saat tidak ada data relevan yang outstanding mungkin segera dikirim. Write serupa ketika data masih menunggu acknowledgment dapat tetap berada di antrean sampai acknowledgment tiba atau data yang terkumpul cukup untuk membentuk segmen yang lebih besar.
Jadi, penundaan yang terjadi bukan sleep umum setelah setiap write kecil. Penundaan mengikuti keadaan TCP dan jumlah data yang sedang in flight.
TCP_NODELAY menghapus kondisi penggabungan tersebut
Linux menyediakan TCP_NODELAY melalui level opsi socket TCP:
int enabled = 1;
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
&enabled, sizeof(enabled)) == -1) {
return -1;
}Setelah diaktifkan, socket tidak lagi menerapkan aturan Nagle untuk menunda data kecil yang mengantre hanya karena data sebelumnya belum menerima acknowledgment.
Perbedaan ini penting bagi protokol request-response yang menghasilkan write pendek dan saling bergantung. Jika write berikutnya baru dapat dibuat setelah peer merespons write sebelumnya, penggabungan di sisi pengirim dapat terlihat sebagai latensi aplikasi. Menghapus kondisi tersebut dapat memperpendek jeda antara aplikasi memasukkan byte ke antrean dan TCP membuatnya memenuhi syarat untuk dikirim.
Opsi ini berlaku per socket. Opsi ini bukan mode seluruh host dan tidak mengubah koneksi TCP lain.
Pemanggilan write tetap tidak memiliki identitas packet
TCP_NODELAY kadang dijelaskan secara berlebihan seolah-olah membuat setiap write() langsung terkirim. TCP tidak mempertahankan pemetaan seperti itu.
Beberapa mekanisme dapat memisahkan pemanggilan aplikasi dari packet yang terlihat:
- beberapa write dapat digabung sebelum packet dibentuk;
- satu write besar dapat dipecah menjadi beberapa segmen;
- segmentation offload dapat menyerahkan buffer yang lebih besar ke perangkat jaringan untuk dipecah kemudian;
- congestion control dapat mencegah pengiriman langsung;
- flow control penerima dapat membatasi pengiriman;
- antrean di kernel atau perangkat jaringan dapat menambah penundaan.
Karena alasan yang sama, packet capture bukan catatan langsung dari pemanggilan write aplikasi. Lokasi offload dan capture juga dapat memengaruhi bentuk segmen yang terlihat oleh tool tracing.
TCP_NODELAY menghapus satu alasan spesifik di sisi pengirim untuk menahan data kecil. Opsi ini tidak melewati pipeline pengiriman lainnya.
Delayed acknowledgment adalah mekanisme yang berbeda
Kebijakan acknowledgment di penerima berbeda dari penggabungan Nagle. Penerima dapat menunda acknowledgment sebentar karena mengantisipasi data yang akan dikirim ke arah sebaliknya atau segmen lain yang perlu diakui.
Ketika pengirim menggunakan penggabungan Nagle dan penerima menggunakan delayed acknowledgment, pola request-response kecil tertentu dapat memperlihatkan interaksi kedua kebijakan tersebut. Pengirim mungkin menunggu acknowledgment sebelum melepas write kecil yang mengantre, sementara penerima menunggu sebentar sebelum membuat acknowledgment itu.
TCP_NODELAY memutus sisi pengirim dari interaksi tersebut dengan menghapus penundaan berbasis Nagle. Opsi ini tidak menonaktifkan delayed acknowledgment di peer.
Pemisahan ini penting saat menganalisis sumber latensi. Koneksi dapat mengaktifkan TCP_NODELAY tetapi tetap mengalami penundaan karena kebijakan acknowledgment, penjadwalan, congestion, pemrosesan penerima, atau perilaku aplikasi.
Write kecil dapat meningkatkan overhead packet
Menonaktifkan penggabungan dapat menukar efisiensi batching dengan penundaan yang lebih rendah di sisi pengirim. Aplikasi yang menghasilkan banyak write kecil dapat membuat lebih banyak segmen kecil memenuhi syarat untuk dikirim.
Setiap segmen tambahan membawa header protokol dan membutuhkan pemrosesan di pengirim, penerima, serta jaringan. Biayanya dapat berupa tekanan pada packet rate, pekerjaan interrupt atau polling, operasi antrean, dan efisiensi payload yang lebih rendah.
Dampaknya bergantung pada bentuk trafik. Layanan yang menulis respons lengkap berukuran beberapa kilobyte hanya mendapat sedikit manfaat dari menonaktifkan aturan yang terutama memengaruhi write kecil dengan data outstanding. Protokol yang sensitif terhadap latensi dan menghasilkan record pendek yang saling bergantung dapat memiliki profil yang sangat berbeda.
Ini adalah batasan berbasis workload, bukan pengaturan socket yang cocok untuk semua kasus.
TCP_CORK menerapkan kebijakan batching yang berbeda
Linux juga menyediakan TCP_CORK, yang ditujukan untuk menahan frame parsial agar pengirim dapat menyusun segmen yang lebih penuh. Opsi ini menyatakan niat batching yang lebih kuat daripada membiarkan penggabungan Nagle tetap aktif.
Kedua opsi tersebut menghadapi tekanan yang berlawanan: TCP_NODELAY menghapus penantian berbasis Nagle untuk data kecil yang mengantre, sedangkan TCP_CORK dapat sengaja menahan output parsial untuk batching.
Linux mengizinkan kedua opsi diatur, tetapi menganggapnya dapat saling menggantikan akan mengaburkan perannya. Kode yang mengelola salah satunya sebaiknya menyatakan kebijakan transmisi yang diinginkan secara eksplisit ketika fase output aplikasi berubah.
Opsi ini mengubah kelayakan pengiriman, bukan semantik delivery
Mengaktifkan TCP_NODELAY tidak mengubah kontrak TCP sebagai byte stream yang andal dan berurutan. Opsi ini tidak membuat batas record, menambahkan acknowledgment di level aplikasi, atau membuat write() yang berhasil berarti peer sudah menerima byte tersebut.
Write yang berhasil biasanya hanya melaporkan bahwa data telah diterima oleh jalur pengiriman socket lokal. Transmisi dan penerimaan oleh peer terjadi kemudian melalui mekanisme TCP normal.
Batasnya jelas: TCP_NODELAY menonaktifkan penggabungan Nagle pada socket tersebut. Dampak latensi muncul karena satu kondisi itu dihapus dari pipeline transport yang lebih besar.