MySQL vs OpenSearch para búsqueda autohospedada: ¿vale la pena o es autolesión en un VPS?

¿Te fue útil?

Tienes un VPS. Tienes usuarios que escriben “invoice 2021 acme” y esperan magia. También tienes un presupuesto de operaciones que sospechosamente se parece a “tú, después de cenar”. La pregunta no es si OpenSearch puede buscar mejor que MySQL. Puede. La pregunta es si ejecutarlo tú mismo en una máquina pequeña es una restricción inteligente… o un incidente en cámara lenta.

Esta es la diferencia práctica entre “búsqueda como una característica” y “búsqueda como un sistema distribuido siempre activo que se ofende personalmente por poca RAM”. Elige la herramienta equivocada y tu VPS te dará una lección de humildad, una tormenta de swaps a la vez.

El marco de decisión: qué estás realmente eligiendo

Si reduces la decisión a “cuál es más rápido”, obtendrás una respuesta cara y un sistema poco fiable. Lo que realmente eliges es:

  • Calidad de búsqueda vs complejidad operativa. MySQL puede hacer búsqueda por palabras clave decente. OpenSearch permite ajustar relevancia, tolerancia a errores tipográficos, analizadores por idioma, sinónimos, facetas, resaltado y más. También exige memoria, IO de disco y atención continua.
  • Un sistema vs dos sistemas de registro. Si añades OpenSearch, MySQL sigue siendo tu sistema de registro. Ahora también tienes un índice que es “eventualmente correcto”. Debes construir y operar la sincronización.
  • Modos de fallo. Cuando MySQL va lento, suele ser por consultas, bloqueos o IO. Cuando OpenSearch va lento, puede deberse a presión de heap, merges de segmentos, rotación de caches, pausas de GC, disposición de shards, comportamiento de refresh/flush o un disco que miente sobre su rendimiento.
  • Sobre qué puedes equivocarte. En un VPS pequeño, una suposición equivocada puede convertirse en “todo está bien” hasta que el kernel mata a Java por OOM.

Aquí la guía directa:

  • Si tu búsqueda es simple (palabras clave en título/cuerpo, filtros por pocas columnas, corpus relativamente pequeño), empieza con MySQL y no te disculpes. Usa índices adecuados, quizá FULLTEXT, y acepta que la relevancia es “suficientemente buena”.
  • Si la búsqueda es valor central del producto (relevancia, tolerancia a errores tipográficos, facetas, ponderación multi-campo, sinónimos, idiomas), usa OpenSearch, pero considera ofertas gestionadas antes de autohospedarlo en un VPS diminuto.
  • Si aún quieres autohospedar OpenSearch en un VPS, hazlo como si estuvieras ejecutando un servicio de producción: monitorización, snapshots, ajuste de heap, comprobaciones de disco y un plan de recuperación probado. De lo contrario no estás autohospedando; estás improvisando.

Una cita que debería colgarse en la pared de cualquiera que autoalbergue búsqueda: “Todo falla todo el tiempo.” — Werner Vogels.

Hechos e historia que explican el dolor actual

Un poco de contexto hace que las compensaciones parezcan menos arbitrarias. Estos son hechos concretos y útiles que se mapean directamente a la realidad operativa:

  1. Lucene es el motor central bajo Elasticsearch y OpenSearch. Está en uso desde finales de los 90, y su modelo de segmentos/merges explica por qué el IO de disco importa tanto.
  2. FULLTEXT de MySQL precede a las plataformas modernas de búsqueda. Fue creado para añadir búsqueda por palabras clave a cargas relacionales, no para ser un laboratorio de relevancia.
  3. Elasticsearch comenzó en 2010 como un servidor de búsqueda distribuido sobre Lucene, diseñado para hacer accesibles los “clusters de búsqueda”—hasta que hay que operarlos.
  4. OpenSearch se bifurcó de Elasticsearch 7.10 tras cambios de licencia. Operacionalmente, hereda la mayoría de fortalezas y trampas de Elasticsearch.
  5. Los índices invertidos son la razón por la que OpenSearch es rápido en búsqueda de texto. No es una “base de datos haciendo LIKE”; es una estructura de datos diferente optimizada para recuperación.
  6. El patrón MySQL LIKE ‘%term%’ no puede usar un índice B-tree normal para comodines iniciales, por eso la gente termina haciendo escaneos de tabla y luego culpa a “la búsqueda de MySQL”.
  7. Refresh vs commit es un concepto real en sistemas basados en Lucene. Un documento puede ser “buscable” rápidamente (refresh) pero no necesariamente durable hasta después (semántica de commit/snapshot).
  8. Los discos de VPS pequeños a menudo tienen créditos de ráfaga. Tu benchmark puede verse genial hasta que se agotan los créditos, y entonces los merges de segmentos se convierten en alquitrán.

Relevancia, analizadores y “¿por qué no lo encuentra?”

Relevancia en MySQL: perillas gruesas

El scoring de FULLTEXT en MySQL existe, pero no está diseñado para el tipo de ajuste iterativo de relevancia que los equipos de producto suelen hacer. Puedes hacer:

  • Consultas en lenguaje natural y modo booleano.
  • Ponderación entre columnas combinando y dividiendo puntuaciones (torpe, pero posible).
  • Listas de stopwords y comportamiento de longitud mínima de palabra (varía según motor/versión).

La mayor trampa: esperar que FULLTEXT de MySQL se comporte como búsqueda web moderna. No lo hará, y desperdiciarás tiempo intentando que finja.

Relevancia en OpenSearch: más poder, más responsabilidad

OpenSearch te da analizadores (tokenización, minúsculas, stemming), mappings por campo, multi-fields (keyword + text) y flexibilidad del DSL de consultas. Puedes hacer que la búsqueda se sienta “inteligente”. También puedes romperla de modo que no encuentre nada porque el analizador no tokeniza como asumiste.

Implicación operativa: errores de mapping son outages

Un error de mapping en OpenSearch suele ser “reindexar el mundo”. En un VPS, reindexar puede ser lo que tumbe el nodo. Planifica:

  • Índices versionados y aliases.
  • Trabajos de reindex controlados con limitación de velocidad.
  • Snapshots antes de cambios grandes.

Almacenamiento e IO: el asesino silencioso en búsquedas en VPS

En papel, tanto MySQL como OpenSearch son “sistemas basados en disco”. En la práctica:

  • MySQL tiende a ser sensible a patrones de IO aleatorio (la tasa de aciertos del buffer pool importa), comportamiento de fsync del log y la contención por otras cargas.
  • OpenSearch es sensible al throughput de escritura sostenido durante indexado y merges, y a la latencia de lectura durante carga de consultas—además usa intensamente la caché de páginas del SO.

En un VPS, el disco frecuentemente es el componente menos honesto. “NVMe” en la descripción del plan puede aún significar IO compartido, créditos de ráfaga, vecinos ruidosos y estrangulamiento. Los merges de segmento no respetan tu copia de marketing.

Segundo chiste: La nube dice que tu disco es “hasta 3.000 IOPS”. Mi experiencia dice que es “hasta 3.000 IOPS, brevemente, si la luna lo aprueba”.

Tres micro-historias corporativas desde las trincheras

Incidente causado por una suposición errónea: “la búsqueda es solo lectura, así que no dañará producción”

Un equipo SaaS mediano añadió OpenSearch para búsqueda visible al cliente. Fueron cuidadosos con el rendimiento de consultas en staging, y estaban orgullosos. La suposición equivocada: el tráfico de búsqueda es “solo lectura”, por lo tanto seguro de colocalizar en la misma instancia tipo VPS que la base de datos de la aplicación durante el lanzamiento temprano.

La primera semana fue bien. Luego un cliente importó un dataset grande y el equipo habilitó indexado casi en tiempo real: los refreshs se mantuvieron frecuentes, el indexado corrió continuamente y los merges empezaron a apilarse. La latencia subió, pero no apareció primero en el endpoint de búsqueda. Se manifestó en todo lo demás: timeouts de API, lentitud en logins y retraso en jobs en segundo plano.

El culpable no fue la CPU. Fue la contención de disco. El nodo OpenSearch hacía escrituras sostenidas más merges; la instancia MySQL (mismo host) intentaba fsync su redo log. Ambos eran “correctos”. Juntos fueron catastróficos.

La solución fue dolorosamente simple: separar las cargas de trabajo y añadir monitorización de disco explícita. También aumentaron los intervalos de refresh durante indexado masivo y añadieron un mecanismo de backpressure en el pipeline de ingestión.

La lección: los sistemas “solo lectura” también escriben, a veces agresivamente. Especialmente la búsqueda.

Una optimización que salió mal: el número de shards como placebo de rendimiento

Un grupo de ingeniería migró de FULLTEXT de MySQL a OpenSearch porque querían mejor relevancia y facetas. Los benchmarks iniciales fueron mixtos. Alguien sugirió aumentar el número de shards para “paralelizar” consultas en un solo nodo. Sonaba plausible. Fue erróneo para su caso.

Tomaron un índice modesto y lo dividieron en muchos shards. El rendimiento de consultas no mejoró. En su lugar, la presión de heap subió: más estructuras a nivel shard, más metadata de segmentos, más caches compitiendo. Las pausas de GC se hicieron notables bajo picos de tráfico. El throughput de indexado cayó porque los merges ocurrían sobre más shards pequeños en lugar de unos pocos eficientes.

Intentaron “arreglarlo” con heap más grande. Eso redujo la frecuencia de GC pero aumentó los tiempos de pausa cuando GC ocurría, y despojó a la caché de página del SO. Las consultas volvieron a empeorar porque aumentaron las lecturas de disco.

Se recuperaron reindexando en menos shards (y usando un alias para cambiar), manteniendo el heap moderado y dejando memoria para la caché del SO. La mejora no vino de un número mágico; vino de dejar de hacer que el sistema se pelee consigo mismo.

La lección: el número de shards no es una perilla de rendimiento. Es una decisión de distribución de datos con consecuencias operativas.

Una práctica aburrida pero correcta que salvó el día: snapshots y simulacros de restauración

Una compañía ejecutaba OpenSearch como servicio autohospedado de nodo único para búsqueda de logs internos y una pequeña función de búsqueda para clientes. No era glamoroso. Tenían un hábito disciplinado: simulacros de restauración de snapshots semanales a una instancia de pruebas. A nadie le gustaba hacerlo. Era un ítem de checklist que siempre parecía menos prioritario que “trabajo real”.

Un día, tras un parche de SO y un reinicio, el nodo arrancó con un problema de sistema de archivos que corrompió parte del store de índices. OpenSearch se negó a arrancar limpiamente. El equipo no debatió teoría por horas. Declararon el nodo no saludable, provisionaron una nueva instancia, instalaron la misma versión de OpenSearch y restauraron el snapshot más reciente.

Tuvieron una ventana de caída, pero fue medida en un periodo predecible en lugar de pánico abierto. La calidad de búsqueda quedó intacta porque su simulacro de restauración validó mappings, templates y el proceso de recuperación de extremo a extremo.

La lección: los snapshots sin práctica de restauración son deseos. La práctica aburrida es lo que convierte “pérdida de datos” en “tarde molesta”.

Guion de diagnóstico rápido

Cuando “la búsqueda está lenta”, necesitas responder una pregunta rápido: ¿es CPU, memoria, disco o diseño de consulta? Esta es una secuencia que funciona en la vida real.

Primero: ¿está muriendo el host?

  • Comprueba carga, steal de CPU (¡VPS!), presión de memoria, swap y saturación de disco.
  • Si el host está enfermo, no empieces a afinar consultas. Arregla el cuello de botella de la plataforma.

Segundo: ¿el servicio es estable?

  • MySQL: conexiones, threads, consultas lentas, estado de InnoDB, comportamiento del buffer pool.
  • OpenSearch: salud del cluster (incluso nodo único), presión de heap de JVM, pausas de GC, thread pools, solicitudes rechazadas.

Tercero: ¿es un problema de indexado/refresh/merge?

  • OpenSearch: comprueba tasa de indexado, intervalo de refresh, merges y translog.
  • MySQL: revisa amplificación de escrituras, fsync y ratio de aciertos del buffer pool.

Cuarto: ¿es la consulta?

  • MySQL: EXPLAIN, índices, escaneos completos, tablas temporales, filesorts.
  • OpenSearch: perfila consultas, analiza tokenización, inspecciona mappings y valida el DSL.

Quinto: decide contención

  • Reduce el radio de impacto: limita el indexado, aumenta el intervalo de refresh, deshabilita agregaciones caras, limita la complejidad de consultas o degrada funciones temporalmente.
  • Luego arregla la causa raíz.

Tareas prácticas: comandos, salidas, decisiones (12+)

Estos son comandos reales que puedes ejecutar en un VPS Linux típico con MySQL y/o OpenSearch. Cada uno incluye qué significa la salida y qué decisión tomar a continuación.

1) Comprobar steal de CPU y carga (realidad VPS)

cr0x@server:~$ mpstat -P ALL 1 3
Linux 6.5.0 (server)  12/30/2025  _x86_64_  (2 CPU)

12:01:00 PM  CPU   %usr %nice  %sys %iowait %irq %soft %steal %idle
12:01:01 PM  all   22.00  0.00  8.00   3.00 0.00  1.00  18.00 48.00

Significado: %steal en 18% es que tu hypervisor te está quitando CPU. Eso no es “tu app está lenta”, es “tu VPS está sobrevendido”.

Decisión: Si %steal es consistentemente >5–10% durante incidentes, actualiza/mueve hosts antes de hacer micro-optimizaciones.

2) Comprobar presión de memoria y uso de swap

cr0x@server:~$ free -h
               total        used        free      shared  buff/cache   available
Mem:           3.8Gi       3.3Gi       120Mi        42Mi       420Mi       180Mi
Swap:          2.0Gi       1.6Gi       400Mi

Significado: Estás intercambiando mucho. OpenSearch + swap es una tragedia lenta; MySQL + swap también es malo, solo que más silencioso.

Decisión: Reduce el heap de OpenSearch, reduce la carga, añade RAM o mueve la búsqueda fuera del servidor. Si el swap es distinto de cero en estado estable, tienes un problema operativo.

3) Comprobar latencia de disco y saturación

cr0x@server:~$ iostat -xz 1 3
Linux 6.5.0 (server)  12/30/2025  _x86_64_  (2 CPU)

Device            r/s     w/s   rMB/s   wMB/s  await  %util
nvme0n1          55.0   220.0    2.1    18.4  42.30  97.00

Significado: 97% util y 42 ms await significa que el disco es el cuello de botella. Los nodos de búsqueda odian esto; MySQL también.

Decisión: Limita indexado/merges (OpenSearch), baja la tasa de escrituras (ambos), muévete a almacenamiento mejor o separa servicios.

4) Comprobar espacio en filesystem y presión de inodos

cr0x@server:~$ df -h /var/lib
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1        80G   74G  2.1G  98% /

Significado: 98% lleno es territorio de incidente. OpenSearch necesita margen para merges; MySQL necesita espacio para logs y tablas temporales.

Decisión: Libera espacio ahora. Si es OpenSearch, asegúrate de tener espacio libre antes de indexados intensos o reindexaciones.

5) Comprobar eventos OOM a nivel kernel

cr0x@server:~$ journalctl -k -S -2h | tail -n 8
Dec 30 10:55:12 server kernel: Out of memory: Killed process 1920 (java) total-vm:6123456kB, anon-rss:2567890kB
Dec 30 10:55:12 server kernel: oom_reaper: reaped process 1920 (java), now anon-rss:0kB, file-rss:0kB

Significado: El kernel mató a OpenSearch (Java). Eso no es un bug de la aplicación; es capacidad/límites.

Decisión: Reduce heap, deshabilita funciones que consumen memoria, muévete a un nodo más grande o deja de autohospedar búsqueda en ese VPS.

6) Verificar que MySQL use índices (no deseos)

cr0x@server:~$ mysql -e "EXPLAIN SELECT id,title FROM posts WHERE title LIKE '%invoice%' ORDER BY created_at DESC LIMIT 20\G"
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: posts
   partitions: NULL
         type: ALL
possible_keys: idx_title,idx_created_at
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 184233
     filtered: 10.00
        Extra: Using where; Using filesort

Significado: type: ALL y key: NULL significa escaneo completo de tabla. LIKE con comodín inicial no usará un índice normal.

Decisión: Rediseña la consulta (búsqueda por prefijo), añade FULLTEXT o acepta que necesitas un motor de búsqueda.

7) Comprobar estado del log de consultas lentas de MySQL (y si miente)

cr0x@server:~$ mysql -e "SHOW VARIABLES LIKE 'slow_query_log%'; SHOW VARIABLES LIKE 'long_query_time';"
+---------------------+-------+
| Variable_name       | Value |
+---------------------+-------+
| slow_query_log      | ON    |
| slow_query_log_file | /var/log/mysql/mysql-slow.log |
+---------------------+-------+
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| long_query_time | 1.000 |
+-----------------+-------+

Significado: El logging de lentas está activo con umbral de 1s. Bien: puedes observar la realidad.

Decisión: Si el slow log está apagado en producción, actívalo (con cuidado) y empieza a medir antes de reescribir sistemas.

8) Inspeccionar presión de InnoDB y comportamiento del buffer pool

cr0x@server:~$ mysql -e "SHOW ENGINE INNODB STATUS\G" | sed -n '1,40p'
=====================================
2025-12-30 12:05:01 INNODB MONITOR OUTPUT
=====================================
BUFFER POOL AND MEMORY
Total large memory allocated 2147483648
Buffer pool size   131072
Free buffers       8
Database pages     130000
Modified db pages  5200

Significado: Casi sin buffers libres, muchas páginas modificadas. Bajo carga de escritura, el flushing puede dominar la latencia.

Decisión: Si el disco está saturado, reduce la tasa de escrituras, ajusta flushing o mueve la carga de búsqueda fuera de MySQL.

9) Comprobar salud del cluster OpenSearch (un nodo aún necesita estado más verde)

cr0x@server:~$ curl -s localhost:9200/_cluster/health?pretty
{
  "cluster_name" : "vps-search",
  "status" : "yellow",
  "timed_out" : false,
  "number_of_nodes" : 1,
  "number_of_data_nodes" : 1,
  "active_primary_shards" : 12,
  "active_shards" : 12,
  "unassigned_shards" : 12
}

Significado: Yellow en nodo único suele significar réplicas sin asignar (porque no hay dónde ponerlas).

Decisión: En nodo único, configura réplicas a 0 para índices donde aceptes no redundancia y compensa con snapshots.

10) Comprobar presión de heap de JVM en OpenSearch

cr0x@server:~$ curl -s localhost:9200/_nodes/stats/jvm?pretty | sed -n '1,40p'
{
  "nodes" : {
    "Q1" : {
      "jvm" : {
        "mem" : {
          "heap_used_in_bytes" : 1638000000,
          "heap_max_in_bytes" : 2147483648
        }
      }
    }
  }
}

Significado: ~76% del heap usado. Está bien hasta que llega al 90% bajo carga y GC empieza a acampar en tu CPU.

Decisión: Si el uso de heap es persistentemente alto, reduce el número de shards, limita fielddata, corrige mappings (keyword vs text) o añade memoria.

11) Comprobar solicitudes rechazadas (saturación de thread pool)

cr0x@server:~$ curl -s localhost:9200/_nodes/stats/thread_pool?pretty | grep -E '"rejected"|"search"|"write"' -n | head
42:          "search" : {
58:            "rejected" : 120
210:          "write" : {
226:            "rejected" : 45

Significado: Rechazos indican sobrecarga. OpenSearch te está diciendo que no puede seguir el ritmo.

Decisión: Añade capacidad, reduce concurrencia de consultas/indexado o implementa backpressure en la app. No “reintentes más rápido”.

12) Inspeccionar merges de OpenSearch (indicador de churn en disco)

cr0x@server:~$ curl -s localhost:9200/_nodes/stats/indices/merges?pretty | sed -n '1,80p'
{
  "nodes" : {
    "Q1" : {
      "indices" : {
        "merges" : {
          "current" : 7,
          "current_docs" : 180000,
          "current_size_in_bytes" : 2140000000,
          "total_throttled_time_in_millis" : 850000
        }
      }
    }
  }
}

Significado: Muchos merges activos y alto tiempo throttleado sugiere que el disco limita el indexado y quizá también las consultas.

Decisión: Aumenta el intervalo de refresh durante cargas masivas, limita la ingestión o muévete a disco más rápido. Considera menos shards.

13) Validar análisis/tokenización (por qué los resultados no coinciden)

cr0x@server:~$ curl -s -H 'Content-Type: application/json' localhost:9200/myindex/_analyze -d '{"text":"ACME-Invoice_2021","analyzer":"standard"}'
{"tokens":[{"token":"acme","start_offset":0,"end_offset":4,"type":"<ALPHANUM>","position":0},{"token":"invoice_2021","start_offset":5,"end_offset":17,"type":"<ALPHANUM>","position":1}]}

Significado: El analizador dejó invoice_2021 como un token. Si esperabas “invoice” y “2021” por separado, la elección del analizador es incorrecta.

Decisión: Cambia analizadores (o añade subcampos) antes de ajustar consultas. Reindexa si es necesario.

14) Perfilar una consulta lenta en OpenSearch

cr0x@server:~$ curl -s -H 'Content-Type: application/json' localhost:9200/myindex/_search -d '{
  "profile": true,
  "query": { "match": { "body": "invoice acme" } },
  "size": 10
}' | sed -n '1,60p'
{
  "took" : 185,
  "timed_out" : false,
  "hits" : {
    "total" : {
      "value" : 12034,
      "relation" : "eq"
    }
  }
}

Significado: took: 185 ms no es horrible, pero si el p95 son segundos, debes inspeccionar las secciones de profile para ver qué parte es cara (scoring, term queries, fetch phase, etc.).

Decisión: Si el fetch es caro, reduce los campos almacenados/_source. Si el scoring es caro, ajusta el tipo de consulta o prefiltra con keywords.

15) Confirmar que OpenSearch está escuchando y no hace flapping

cr0x@server:~$ systemctl status opensearch --no-pager
● opensearch.service - OpenSearch
     Loaded: loaded (/lib/systemd/system/opensearch.service; enabled)
     Active: active (running) since Mon 2025-12-30 11:40:11 UTC; 25min ago
       Docs: man:opensearch
   Main PID: 1920 (java)
      Tasks: 132 (limit: 4620)
     Memory: 2.7G
        CPU: 18min 12.345s

Significado: El servicio está arriba, pero 2.7G de memoria en un VPS pequeño puede ser una señal de advertencia, no una victoria.

Decisión: Comprueba ajustes de heap y RAM total. Si el proceso más la caché del SO exceden la capacidad, vas rumbo a OOM.

16) Comprobar conexiones y presión de threads en MySQL

cr0x@server:~$ mysql -e "SHOW STATUS LIKE 'Threads_connected'; SHOW STATUS LIKE 'Max_used_connections';"
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Threads_connected | 182   |
+-------------------+-------+
+----------------------+-------+
| Variable_name        | Value |
+----------------------+-------+
| Max_used_connections | 240   |
+----------------------+-------+

Significado: Altos conteos de threads pueden significar problemas con el pooling de conexiones o una app atascada. También puede indicar consultas lentas que causan acumulación.

Decisión: Si los threads suben durante incidentes, arregla la latencia de consultas e implementa límites de pooling sensatos. No te limites a aumentar max_connections.

Errores comunes: síntoma → causa raíz → solución

1) “La búsqueda en MySQL está lenta”

Síntoma: Endpoint de búsqueda dispara CPU, consultas tardan segundos, carga de BD sube.

Causa raíz: Uso de LIKE '%term%' en columnas de texto grandes causando escaneos completos; o ordenación/paginación sin índices de soporte.

Solución: Usa búsqueda por prefijo cuando sea posible; añade FULLTEXT; normaliza campos buscables; añade índices compuestos para filtros + orden; considera OpenSearch si necesitas substring/tolerancia a errores tipográficos.

2) “OpenSearch es aleatoriamente lento”

Síntoma: Latencia p95 salta; consultas ocasionales de varios segundos; la CPU parece OK.

Causa raíz: Pausas de GC por alta presión de heap, o latencia de disco durante merges de segmentos y fallos de caché de página.

Solución: Reduce número de shards; corrige mappings para evitar explosiones de fielddata; limita agregaciones; asegura RAM suficiente para la caché del SO; muévete a disco mejor.

3) “La salud del cluster está en yellow y entro en pánico”

Síntoma: OpenSearch nodo único muestra estado yellow.

Causa raíz: Réplicas configuradas > 0 con un solo nodo.

Solución: Ajusta replicas a 0 para esos índices y confía en snapshots para recuperación.

4) “Indexado dejó la búsqueda inutilizable”

Síntoma: Durante importaciones masivas, latencia de búsqueda se dispara y ocurren timeouts.

Causa raíz: Refresh demasiado frecuente, merges dominando disco, indexado compitiendo con consultas en el mismo nodo.

Solución: Aumenta intervalo de refresh durante cargas, limita ingestión, realiza indexado masivo fuera de horas pico; considera nodos separados para indexado y servicio (aunque eso signifique “no lo hagas en un solo VPS”).

5) “OpenSearch funcionó hasta que se llenó el disco”

Síntoma: Fallan escrituras, el cluster pasa a solo lectura, errores raros.

Causa raíz: No tener en cuenta overhead de merges, snapshots, crecimiento de translog y retención. Sin planificación de marcas de agua de disco.

Solución: Mantén espacio libre significativo; aplica retención; monitoriza disco; prueba tamaños de snapshot; evita reindexaciones masivas sin margen.

6) “Faltan resultados evidentes en búsqueda”

Síntoma: Usuarios insisten que los datos existen; la búsqueda no los encuentra.

Causa raíz: Desajuste de analizador/mapping (keyword vs text), sorpresas de tokenización, stopwords/longitud mínima, o índice desactualizado por pipeline fallido.

Solución: Verifica análisis con _analyze; inspecciona mappings; implementa pipeline de indexado robusto con reintentos y manejo de dead-letter; construye verificaciones de consistencia entre MySQL y OpenSearch.

7) “Aumentamos el heap y empeoró”

Síntoma: Menos GCs pero pausas más largas; latencia de consultas empeora; aumentan lecturas de disco.

Causa raíz: Heap demasiado grande que deja sin memoria a la caché de página del SO; Lucene se beneficia de la caché del sistema de archivos.

Solución: Mantén el heap moderado; deja RAM para la caché del SO; arregla shards/mappings en lugar de esconderlos bajo más heap.

Listas de verificación / plan paso a paso

Plan A: Quedarse con MySQL (y ser honesto sobre los requerimientos)

  1. Define las funciones de búsqueda explícitamente. ¿Solo palabras clave? ¿Prefijo? ¿Filtros? ¿Ajuste de relevancia? ¿Errores tipográficos? Si necesitas errores tipográficos y sinónimos, deja de fingir.
  2. Audita las consultas. Reemplaza patrones %term% cuando sea posible; asegúrate de que filtros y órdenes tengan índices.
  3. Prueba FULLTEXT donde encaje. Especialmente para “buscar en título/cuerpo”.
  4. Mide con slow query log. Mantén un umbral estable (1–2s) y revisa los mayores offenders semanalmente.
  5. Plan de capacidad. Asegura que la BD tenga suficiente buffer pool y margen de disco; aisla de otras cargas ruidosas.
  6. Fija expectativas. Documenta limitaciones de relevancia en términos de producto: “palabras exactas, no errores tipográficos”, “sin sinónimos”, “sin stemming”.

Plan B: Usar OpenSearch, pero no conviertas tu VPS en la rata de laboratorio

  1. Empieza con una instancia dev de nodo único. Valida analizadores, mappings y consultas básicas.
  2. Diseña el modelo de documento. Desnormaliza. Evita joins. Decide qué es “text” vs “keyword”.
  3. Implementa pipeline de indexado. Usa patrón queue/outbox para desacoplar escrituras en MySQL y actualizaciones de índice, con reintentos.
  4. Usa aliases para reindex sin downtime. Versiona índices y cambia aliases.
  5. Define estrategia de snapshots. Programa snapshots y prueba restauraciones.
  6. Establece límites. Cap query complexity, limita tamaños de agregación y añade timeouts.
  7. Observa todo. Heap, GC, latencia de disco, rechazos de thread pool, distribución de latencia de consultas.
  8. Solo entonces considera autohospedar en un VPS pequeño. Si no puedes comprometerte con snapshots, monitorización y simulacros de restauración, evita autohospedar OpenSearch en un VPS pequeño.

Plan C: Si insistes en OpenSearch en un VPS, haz al menos esto

  1. Dale suficiente RAM y deja espacio para la caché del SO (no asignes toda la memoria al heap).
  2. Usa almacenamiento rápido y consistente. Si el disco de tu VPS tiene créditos de ráfaga, asume que alcanzarás el techo.
  3. Configura réplicas a 0 en nodo único y confía en snapshots.
  4. Mantén bajo el número de shards. No eres un cluster; no hagas cosplay de uno.
  5. Limita indexado masivo y aumenta intervalo de refresh durante importaciones.
  6. Monitoriza y alerta sobre: disco > 80%, heap > 85%, rechazos de thread pool > 0, p95 de consultas y eventos OOM.
  7. Realiza un simulacro de restauración antes de que lo necesites.

Preguntas frecuentes

1) ¿Puede FULLTEXT de MySQL reemplazar OpenSearch para un sitio pequeño?

Sí, si “pequeño” también significa “simple”. Búsqueda por palabras clave en un par de campos con filtrado básico está bien. El momento en que necesites tolerancia a errores tipográficos, sinónimos y facetas, verás el techo.

2) ¿Es OpenSearch exagerado para un VPS?

A menudo, sí. No porque no funcione, sino porque no funcionará de forma fiable sin suficiente RAM y rendimiento de disco. En un VPS pequeño, estás a una tormenta de merges de un mal día.

3) ¿Por qué OpenSearch necesita tanta memoria?

Es Lucene más una JVM más caches más overhead por shard. Además, Lucene depende mucho de la caché de página del SO para lecturas rápidas. Si privas a la caché del SO, la búsqueda se vuelve dependiente del disco con rapidez.

4) ¿Debo poner el heap de OpenSearch al 75% de la RAM?

No en un VPS donde te importa el rendimiento. Necesitas memoria para la caché de página del SO. Si el heap es demasiado grande, intercambias “problemas de GC” por “problemas de disco”, y ninguna opción es agradable.

5) ¿Cuál es el mayor coste oculto de añadir OpenSearch?

Sincronización y corrección. MySQL es la fuente de la verdad; OpenSearch es un índice. Necesitas un pipeline, reintentos, backfills y una forma de detectar deriva.

6) ¿Puedo ejecutar MySQL y OpenSearch en el mismo VPS?

Puedes, pero probablemente no deberías en producción. La contención de disco es el modo de fallo habitual, seguida de presión de memoria. Si lo haces, aísla recursos y monitoriza la latencia de disco como si tu trabajo dependiera de ello.

7) ¿Por qué mi cluster OpenSearch está en yellow en nodo único?

Las réplicas no pueden asignarse porque solo hay un nodo. Configura number_of_replicas a 0 para esos índices y apóyate en snapshots para recuperación.

8) ¿Cuándo tiene sentido quedarse con MySQL aunque la relevancia no sea perfecta?

Cuando la disponibilidad y la simplicidad importan más que la sofisticación de búsqueda, y tus usuarios toleran búsqueda por “palabra exacta”. Muchas productos viven en silencio aquí y funcionan bien.

9) ¿Cuál es la vía de migración más limpia de MySQL a OpenSearch?

Construye primero el pipeline de indexado, backfill en un índice versionado, valida resultados y luego cambia lecturas gradualmente (o con feature flags). Mantén la posibilidad de volver temporalmente a la búsqueda en MySQL.

Próximos pasos que puedes hacer esta semana

Si aún estás decidiendo, haz esto en orden:

  1. Escribe las funciones de búsqueda requeridas. No “agradable de tener”. Requeridas.
  2. Ejecuta los diagnósticos. Comprueba latencia de disco, swap y steal de CPU. Si el VPS está enfermo, para y arregla eso primero.
  3. Prototipa en MySQL. Prueba FULLTEXT o patrones de prefijo estructurados. Mide con slow logs y EXPLAIN.
  4. Prototipa relevancia en OpenSearch en una máquina dev. Valida analizadores/mappings con _analyze. Perfila tus consultas más lentas.
  5. Decide según la realidad operativa. Si no puedes comprometerte con snapshots, monitorización y simulacros de restauración, evita autohospedar OpenSearch en un VPS pequeño.
  6. Si eliges OpenSearch igualmente: mantén el número de shards bajo, configura réplicas a 0 en nodo único, limita indexado y monitoriza heap + disco como si fuera producción—porque lo es.

La mejor configuración de búsqueda autohospedada es la que sobrevive un mal día. No necesitas un modelo de relevancia perfecto si el servicio está caído. Y no necesitas un cluster bonito si devora tu VPS en cuanto el tráfico se vuelve real.

← Anterior
Marcadores ZFS: salvar incrementales cuando algo sale mal
Siguiente →
Docker «OCI runtime create failed»: descifra el error y arregla la causa real

Deja un comentario