DuckDB y httpfs detrás de un proxy: el secreto que nadie te cuenta
4 min de lectura

DuckDB y httpfs detrás de un proxy: el secreto que nadie te cuenta

796 palabras

El problema: httpfs ignora tus variables de entorno

Si trabajas con DuckDB y la extensión httpfs para leer Parquet remotos, CSVs desde S3 o cualquier recurso HTTP, probablemente asumes que las variables de entorno HTTP_PROXY y HTTPS_PROXY funcionan igual que en cualquier otra herramienta. Curl las respeta. wget las respeta. Python requests las respeta. Node.js las respeta.

DuckDB no.

Me he encontrado con esto trabajando en un entorno corporativo con proxy obligatorio. Tenía un script que leía ficheros Parquet desde Google Cloud Storage usando httpfs, y simplemente no funcionaba. Sin error claro, sin timeout descriptivo, solo silencio. Mientras tanto, un curl al mismo recurso con las mismas variables de entorno devolvía los datos sin problema.

Por qué ocurre esto

La extensión httpfs de DuckDB utiliza internamente cpp-httplib para las conexiones HTTP. A diferencia de curl o libcurl, esta librería no lee automáticamente las variables de entorno del sistema para configurar proxies. Es una decisión de diseño (o una carencia, según cómo lo mires).

Esto ha sido reportado en múltiples issues de GitHub:

  • Issue #3836: Las variables http_proxy y https_proxy se ignoran al instalar extensiones
  • Issue #6064: Petición de soporte de proxy y certificados SSL custom en httpfs
  • Discussion #5944: Discusión comunitaria sobre el mismo tema

La situación ha mejorado parcialmente. Desde la versión 0.10.x, DuckDB soporta configurar el proxy de forma explícita. Pero la clave es esa: de forma explícita. No lo hace automáticamente leyendo el entorno.

La solución: CREATE SECRET o SET

DuckDB ofrece dos mecanismos para configurar el proxy manualmente.

Opción 1: CREATE SECRET (recomendada)

CREATE SECRET http_proxy (
    TYPE http,
    HTTP_PROXY 'http://proxy.empresa.com:8080'
);

Si tu proxy requiere autenticación:

CREATE SECRET http_proxy (
    TYPE http,
    HTTP_PROXY 'http://proxy.empresa.com:8080',
    HTTP_PROXY_USERNAME 'usuario',
    HTTP_PROXY_PASSWORD 'contraseña'
);

Opción 2: SET (pragmas)

SET http_proxy = 'http://proxy.empresa.com:8080';
SET http_proxy_username = 'usuario';
SET http_proxy_password = 'contraseña';

Ambas opciones funcionan, pero CREATE SECRET es más limpia porque agrupa toda la configuración en una sola sentencia y es consistente con cómo DuckDB gestiona las credenciales de S3 y GCS.

Automatizarlo: leer las variables de entorno

Lo que realmente necesitas en un entorno de producción es que tu aplicación lea las variables de entorno y configure DuckDB automáticamente. Aquí va un ejemplo en Node.js con @duckdb/node-api:

const proxy = process.env.HTTPS_PROXY
  || process.env.https_proxy
  || process.env.HTTP_PROXY
  || process.env.http_proxy;

if (proxy) {
  const proxyUrl = new URL(proxy);
  const proxyBase = `${proxyUrl.protocol}//${proxyUrl.hostname}:${proxyUrl.port || 3128}`;

  let secretSQL = `CREATE SECRET http_proxy (TYPE http, HTTP_PROXY '${proxyBase}'`;

  if (proxyUrl.username && proxyUrl.password) {
    secretSQL += `, HTTP_PROXY_USERNAME '${decodeURIComponent(proxyUrl.username)}'`;
    secretSQL += `, HTTP_PROXY_PASSWORD '${decodeURIComponent(proxyUrl.password)}'`;
  }
  secretSQL += ');';

  await connection.run(secretSQL);
}

Y en Python:

import os
import duckdb

con = duckdb.connect()
con.install_extension("httpfs")
con.load_extension("httpfs")

proxy = os.environ.get('HTTPS_PROXY') or os.environ.get('HTTP_PROXY')
if proxy:
    con.execute(f"SET http_proxy = '{proxy}'")

# Ahora sí funciona
con.execute("SELECT * FROM read_parquet('https://ejemplo.com/datos.parquet')")

Cuidado con los caracteres especiales

Hay un gotcha adicional documentado en el Issue #14279: si la contraseña de tu proxy contiene caracteres especiales que están URL-encoded en la variable de entorno (por ejemplo @ como %40), DuckDB los pasa tal cual sin decodificar, y la autenticación falla.

La solución es decodificar antes de pasarlos a DuckDB (como hago en el ejemplo de Node.js con decodeURIComponent) o usar contraseñas sin caracteres especiales.

También afecta a la instalación de extensiones

Este problema no solo afecta a las consultas HTTP. También afecta a INSTALL httpfs y al resto de extensiones. Si estás detrás de un proxy y no puedes instalar extensiones, la solución es la misma: configurar el proxy antes de intentar la instalación.

SET http_proxy = 'http://proxy.empresa.com:8080';
INSTALL httpfs;
LOAD httpfs;

O alternativamente, descargar las extensiones manualmente y cargarlas desde disco local.

Entornos Kubernetes y Docker

En despliegues corporativos con Kubernetes, es habitual que los pods hereden variables HTTP_PROXY y HTTPS_PROXY desde la configuración del cluster. Todas las aplicaciones dentro del pod las respetan… excepto DuckDB.

En mi caso, la solución fue añadir la detección automática de proxy en el cliente DuckDB del servicio, justo después de cargar las extensiones y antes de ejecutar cualquier consulta que acceda a recursos remotos. Es un patrón sencillo pero necesario que deberías implementar si usas DuckDB en entornos con proxy.

Reflexión

DuckDB es una herramienta extraordinaria. La velocidad con la que puedes analizar Parquet, CSV o incluso bases de datos PostgreSQL remotas es impresionante. Pero este detalle del proxy es de esos que te hacen perder horas hasta que das con la causa.

Lo frustrante no es que no soporte proxy – lo soporta. Es que no sigue la convención universal de leer las variables de entorno que todo el ecosistema Unix respeta desde hace décadas. Es un problema resuelto en prácticamente todas las librerías HTTP del planeta, y DuckDB ha decidido ir por su camino.

Dicho esto, una vez que sabes dónde está el problema, la solución es directa. Un CREATE SECRET y a seguir trabajando.

Comentarios

Últimas Entradas

4 min

767 palabras

The problem: httpfs ignores your environment variables

If you work with DuckDB and the httpfs extension to read remote Parquet files, CSVs from S3, or any HTTP resource, you probably assume that the HTTP_PROXY and HTTPS_PROXY environment variables work just like every other tool. Curl respects them. wget respects them. Python requests respects them. Node.js respects them.

DuckDB does not.

I ran into this while working in a corporate environment with a mandatory proxy. I had a script reading Parquet files from Google Cloud Storage using httpfs, and it simply would not work. No clear error, no descriptive timeout, just silence. Meanwhile, a curl to the same resource with the same environment variables returned data without issue.

11 min

2298 palabras

Toda consulta empieza con un plan. Toda consulta lenta probablemente empieza con uno malo. Y más a menudo de lo que crees, las estadísticas son las culpables.

Pero ¿cómo funciona realmente? PostgreSQL no ejecuta la consulta para averiguarlo — estima el coste. Lee datos precalculados de pg_class y pg_statistic y hace los cálculos para encontrar la ruta más barata hacia tus datos.

En el escenario ideal, los números que lee son precisos y obtienes el plan que esperas. Pero cuando están desactualizados, la situación se descontrola. El planificador estima 500 filas, planifica un nested loop, y se encuentra con 25,000. Lo que parecía un plan óptimo se convierte en una falla en cascada.

6 min

1162 palabras

Últimamente estoy trabajando bastante con DuckDB, y una de las cosas que más me interesan es entender cómo optimizar el rendimiento según el formato de archivo que estemos usando.

No es lo mismo trabajar con Parquet, con CSV comprimido, o con CSV descomprimido. Y las diferencias de rendimiento pueden ser dramáticas.

Vamos a revisar las optimizaciones clave que hay que tener en cuenta cuando trabajamos con diferentes formatos de archivo en DuckDB.