Cómo Kronotop combina miles de conexiones y operaciones bloqueantes con Netty y virtual threads

Fuentes: The .join() That Should Be a Bug

Kronotop es una base de datos documental distribuida y transaccional construida sobre FoundationDB. Casi todas sus operaciones implican una llamada de red a FDB o una lectura de disco, por lo que la ruta de comandos está dominada por espera de E/S, no por cómputo en memoria. El artículo explica el problema de gestionar miles de conexiones cuando cada comando debe bloquearse.

Existen dos modelos clásicos. Redis (antes de 6.0) usa un único hilo que escucha todas las conexiones y procesa comandos de forma secuencial; escala bien en conexiones, pero prohíbe cualquier bloqueo porque ralentizaría a todos los clientes. No sirve cuando los comandos deben hablar con un almacén transaccional por red y hacer fsync en disco. Postgres toma el camino opuesto: asigna un proceso del sistema operativo a cada conexión, lo que permite código secuencial y bloqueante a costa de un alto consumo de recursos, por eso sus despliegues suelen ir tras un pooler.

La propuesta de Kronotop es separar la conexión del trabajo. El lado de la conexión se implementa con Netty: unos pocos hilos event loop escuchan muchos sockets sin bloquearse. El trabajo pesado de E/S se ejecuta en virtual threads de Java, que permiten escribir código bloqueante de arriba abajo; cuando la operación espera a FoundationDB o al disco, el runtime desmonta la virtual thread y libera el carrier thread. Miles de virtual threads pueden esperar a la vez mientras solo unos pocos hilos reales hacen algo útil. El reparto se materializa en dos fases: una que se ejecuta en el executor de virtual threads y otra, la escritura de la respuesta, que vuelve al event loop de Netty que posee la conexión. Una transacción queda ligada a la conexión: si esta se cae, se cancela y se limpia.