Cero copia en Go: sendfile, splice y el costo de io.Copy

Fuentes: Zero-copy in Go: sendfile, splice, and the cost of io.Copy

La biblioteca estándar de Go ofrece un camino rápido para transferir archivos a través de TCP mediante la llamada al sistema sendfile, que evita copias innecesarias entre el espacio de usuario y el kernel. Sin embargo, este mecanismo se pierde fácilmente si el descriptor de archivo se envuelve en una interfaz io.Reader, como ocurrió en un servicio real donde un middleware de logging redujo el rendimiento a la mitad. El artículo analiza cómo io.Copy detecta automáticamente si el origen es un *os.File y activa sendfile, pero cualquier envoltura que oculte ese tipo concreto (incluso una simple estructura que implemente io.Reader) fuerza una copia manual con buffers de 32 KiB, multiplicando las llamadas al sistema por un factor de 44. Las pruebas con strace muestran que el modo raw realiza ~2.900 llamadas sendfile para transferir 2,5 GiB, mientras que el modo envuelto ejecuta ~131.000 lecturas y escrituras. El tiempo de CPU del servidor se triplica (de 54 ms a 184 ms por GiB). La excepción es io.LimitedReader, que el runtime desenvuelve explícitamente, preservando la optimización. Para transferencias socket a socket, Go emplea splice de forma análoga. El artículo incluye perfiles de CPU y tablas comparativas, y advierte que incluso cambios mínimos en el código pueden eliminar la transferencia cero-copia, un detalle crítico para servicios de alto rendimiento.