Транспорт бэкенда

Batching, Compression и Zero-Copy

Kafka обрабатывает 1 триллион сообщений в день в LinkedIn. Не через супер-компьютеры - через стандартное железо. Секрет в layer оптимизаций: батчинг сообщений, zstd сжатие, sendfile() для zero-copy отдачи из лога. Каждый уровень умножает throughput. Понимание этих техник отличает 'работает' от 'работает на масштабе'.

  • **Kafka** использует sendfile() (Java NIO transferTo) для consumer replay. Это позволяет отдавать данные из disk log в сеть без аллокаций в JVM heap - ключ к 1M+ messages/sec на одном брокере.
  • **Cloudflare** использует XDP/eBPF для DDoS mitigation: обрабатывает 26 миллионов пакетов в секунду на одном ядре CPU, блокируя атаку до kernel network stack.
  • **AWS** ML training кластеры используют EFA (RDMA) для gradient synchronization между GPU: latency 1-2 мкс вместо 50 мкс TCP - критично при обучении LLM на тысячах GPU.

Batching и Linger

Batching - отправка нескольких сообщений в одном сетевом пакете вместо отдельного вызова на каждое. Overhead на установку соединения и системный вызов amortize через больший батч. Kafka producer по умолчанию батчит с linger.ms=0 (отправить немедленно) - для throughput нужно linger.ms=5-20.

Nagle's algorithm (TCP_NODELAY=false) - это batching на уровне TCP: ждём пока накопится данных или придёт ACK. Для low-latency приложений (игры, финансы) устанавливают TCP_NODELAY=true чтобы отключить Nagle и отправлять немедленно.

Kafka producer с linger.ms=20 vs linger.ms=0. Что изменится?

Compression: алгоритмы и trade-offs

Сжатие данных при передаче уменьшает сетевой трафик за счёт CPU. Trade-off зависит от CPU bound vs network bound ситуации и типа данных. JSON сжимается в 5-10x, бинарные данные - в 2-3x.

Facebook перешёл с zlib на zstd в 2016 году: 2.5x быстрее сжатие при том же ratio. Meta использует zstd для Thrift-сообщений между сервисами. AWS добавил zstd поддержку в S3 и CloudFront в 2023.

Kafka сервис передаёт JSON события (~10KB каждое). Какой алгоритм сжатия предпочтителен для high-throughput?

Zero-Copy и sendfile()

Обычная передача файла копирует данные 4 раза: disk -> kernel buffer -> user buffer -> socket buffer -> NIC. Zero-Copy (sendfile syscall) устраняет копию через user space: disk -> kernel buffer -> NIC напрямую. Kafka использует sendfile для replay из лога - это ключ к его throughput.

Linux splice() - более гибкий вариант sendfile: перемещает данные между pipe file descriptors. mmap() + write() - альтернатива: mapирует файл в адресное пространство процесса, избегая одну из копий. Java NIO MappedByteBuffer использует mmap.

Почему Kafka критически зависит от sendfile() для высокого throughput?

io_uring: асинхронный I/O

io_uring (Linux 5.1, 2019) - новый асинхронный I/O interface, устраняющий overhead системных вызовов через разделяемые кольцевые буферы между ядром и пространством пользователя. Zero system call path для hot paths. Использует submission ring + completion ring.

io_uring поддерживает не только I/O: accept(), connect(), sendmsg(), splice(), fsync() - всё через ту же кольцевую очередь. Это создаёт unified async interface для сетевых и файловых операций. Автор: Jens Axboe (также создатель blktrace, fio).

В чём главное архитектурное преимущество io_uring над epoll?

Kernel Bypass: DPDK и RDMA

Kernel bypass - технологии, позволяющие приложению работать с сетью или памятью напрямую, минуя ядро ОС. DPDK (Data Plane Development Kit) - user-space polling сетевого адаптера. RDMA (Remote Direct Memory Access) - прямой доступ к памяти другой машины без CPU участия.

AWS Elastic Fabric Adapter (EFA) предоставляет RDMA-подобную коммуникацию для HPC и ML workloads. NVIDIA NVLink для GPU-to-GPU: 600 GB/s bandwidth без CPU overhead - используется в A100, H100 кластерах для LLM training.

Compression всегда улучшает производительность - нужно включать везде

Compression - trade-off: CPU vs сеть. Для CPU-bound сервисов или уже сжатых данных (JPEG, MP4) compression ухудшит производительность.

Streaming видео: nginx отдаёт mp4 файлы. Включить gzip? Нет - MP4 уже сжат, gzip потратит CPU без уменьшения size. sendfile без compression в этом случае оптимален.

Для какого типа workload оправдан DPDK (kernel bypass)?

Итоги

  • **Batching** amortizes syscall и network overhead: linger.ms в Kafka, bufferTime в RxJS. Trade-off: latency растёт, throughput растёт.
  • **Compression** выгодна для текстовых данных (JSON, protobuf) на network-bound сервисах. lz4/zstd для real-time, brotli/gzip для HTTP. Не сжимать уже сжатое (JPEG, MP4).
  • **Zero-Copy** через sendfile() устраняет user-space копирование: disk -> kernel -> NIC без JVM heap. io_uring идёт дальше: устраняет syscall overhead через shared rings.

Связанные темы

Batching и zero-copy оптимизации работают на всех уровнях транспортного стека:

  • Kafka: producer и consumer — Kafka батчинг (batch.size, linger.ms) и sendfile для consumer - практические применения этих техник
  • Бенчмаркинг транспорта — Измерить эффект batching и compression можно только через правильный бенчмаркинг с P99 latency и throughput метриками

Вопросы для размышления

  • Как определить оптимальный linger.ms для Kafka producer в конкретном приложении?
  • В каких случаях io_uring не даёт преимущества над epoll?
  • Как batching влияет на latency percentiles (P50 vs P99) по-разному?

Связанные уроки

  • net-67-latency-numbers
Batching, Compression и Zero-Copy

0

1

Войти