Django + Elasticsearch
Problemas y soluciones
Miguel González Nieto (@scenting)
Miguel Sánchez Rodríguez (@miguelsr1987)
- Miguel González Nieto
- @scenting
- Back-end engineer en Acceso
- Miguel Sánchez Rodríguez
- @miguelsr1987
- Full-stack web engineer en Acceso
AccesoHub - Stack
¿Qué necesitábamos?
- Búsqueda full-text
- Gran volumen de documentos (ahora, +50M)
- Búsqueda More Like This
- Asignación inversa (índices sobre búsquedas)
- ¿Estadísticas? ¿Datos agregados?
¿Por qué ElasticSearch?
Posibles Alternativas
- ¿Core?
- Transversal a la empresa, sin conocimiento de cada aplicación
- ¿PostgreSQL?
- Preferimos BDs sin guardar el texto
- No tenemos More Like This
- No escala para nuestro volumen de busquedas
- ¿SolR?
- Esquema muy plano, sin jerarquias
- Búsquedas poco expresivas
- En general: ElasticSearch mejora a SolR
Winning Points de Elasticsearch
- Todo es configurable vía API. Respuestas JSON.
- Esquemas dinámicos.
- Altamente configurable desde shell.
- Posibilidad de esquema con jerarquías.
- More Like This y Percolator out-of-the-box.
- Fácilmente extensible (plugins, analizadores).
- Librería completa para Python (¡y Haystack!).
- Herramienta de moda, comunidad potente!
Historia de un buscador
Indexado (I)
- ¿Cómo indexamos nuestros documentos?
- Definimos un JSON con el mapeo de cada campo a indexar (¡respetaremos las IDs!)
-
ES es esencialmente plano, pero soporta jerarquía:
- Inner objects (Sin queries)
- Nested documents (Overkill en update)
- Parent/child (Menos rápido)
- Denormalization (Demasiados documentos)
- En nuestro caso, parent/child, por rendimiento en las actualizaciones.
- Se recomienda nested documents para un set de documentos actualizado poco frecuentemente.
Puesta en producción
- Ya tenemos claro el esquema pero ¿cómo desplegarlo?
- A priori, con un nodo puede ser suficiente.
- Con dos nodos, nos beneficiamos de mayor resiliencia y actualizaciones en caliente.
- Para mayor seguridad y mitigar split-brains se recomiendan al menos 3
- Con la configuración por defecto de sharding nos es suficiente
¿Cómo nos conectamos?
- Al principio, directamente desde el navegador, a través de la API con el cliente JS de Elasticsearch.
- Poco seguro
- Problemático detrás de un proxy
- Over-engineering en front-end
- Mejor hacerlo todo desde nuestro back-end Django
- JS sólo para presentación
- Autenticación compartida con la App.
- Librería para Python de ES muy completa.
- Atomicidad transaccional con nuestros modelos.
Indexado (II)
- Ya tenemos nuestro ES desplegando y funcionando
- ¿Primer problema?
Muuuuy lento. Según la documentación, ¡hasta un 10x más!
Indexado (III)
- Un índice por cada mes y tipo de documento.
- Búsquedas muchísimo más rápidas con filtrado.
- Puedes buscar en varios indices y despues unir
- Configuracion dinamica de shards
- Distribución más o menos homogénea por meses.
- Los indices son transparentes
- Se pueden crear automáticamente con templates
Particionado (I)
- ¡Horror! Nuevos problemas con el particionado
- Las noticias pueden cambiar de fecha (wtf?) y por tanto, de indice
- Aparecen documentos duplicados en diferentes indices
- ¿IDs repetidos? ¿Es posible?
- Sí, el ID es único, ¡pero por índice!
Debemos borrar los datos viejos cada vez que cambiemos un documento de índice.
Problemas de Integridad (I)
- No tenemos monitorización de datos, confiamos en que todo está sincronizado.
- Nuestros users nos desmuestran que no.
- ¿Cómo podemos garantizar la integridad de datos?
- Nuestras escrituras a BD son transaccionales y fuertemente ligadas con ES mediante señales.
- Aun así, en algún momento se crea un desacoplamiento.
- ES no es ni pretende ser una base de datos.
- Necesitamos un Sincronizador!
Problemas de Integridad (II)
- Creamos un sincronizador que se ejecuta de manera periódica.
- Comando de django-admin, periodic Task de Celery.
- Comprueba que el conteo de documentos por tipo coincide.
- Dado que los IDs en Elastic y pgSQL coinciden, hacemos scaneos de los indices y comprobamos por su equivalente en fechas en nuestra BD.
- ¡Sorprendentemente rápido!
Problemas de Integridad (III)
- No es suficiente.
- Puede darse el caso de que los documentos mantengan la ID pero cambian en algún atributo.
- Añadimos una opción a nuestro Sincronizador para que chequee ciertos campos, en caso de necesidad.
- ¡Sorprendentemente rápido! (de nuevo)
Problemas de Integridad (y IV)
- Alta concurrencia en las escrituras
- Un mismo documento puede intentar actualizarse con datos desfasados.
- Para solucionarlo, empleamos versiones externas basadas en el timestamp de la última actualización.
- Se genera un timestamp al principio del proceso, y si es menor que la versión en ES, se descarta el cambio.
ES & Beyond
- Todo esto nos da cierta tranquilidad, pero todavía carecemos de monitorización formal.
- ¿Posibilidades?
- Marvel: Monitorización del cluster.
- Watcher: Monitorización y alerta por contenido.
- Kibana: Visualizacion de estadísticas.
- Logstash: ETL de logs
Rendimiento (I)
/_all/newsitem/_search?q=body:motril
{
took: 1550,
timed_out: false,
_shards: {
total: 99,
successful: 99,
failed: 0
},
hits: {
total: 19869,
max_score: 4.725038,
hits: [
{
_index: "accesonews_2014_07",
_type: "newsitem",
_id: "2130936",
_score: 4.725038,
_source: {
body: "@djnieto76 @raphapeugeot motril mejorrr",
source_name: "Twitter / Bolsonblanco",
author: [ ],
klout_score: 50,
title: "@djnieto76 @raphapeugeot motril mejorrr",
creation_time: "2014-07-26T23:24:19.584741+00:00",
remote_code: "/i/g/t493174869069406210",
client: [
21
],
project: [
43
],
Rendimiento (II)
/accesonews_2015_10/newsitem/_search?q=body:volkswagen
{
took: 5,
timed_out: false,
_shards: {
total: 1,
successful: 1,
failed: 0
},
hits: {
total: 22659,
max_score: 2.687686,
hits: [
{
_index: "accesonews_2015_10",
_type: "newsitem",
_id: "17973385",
_score: 1.6798037,
_source: {
body: "#Bankia Comienzan los problemas financieros para Volkswagen http://t.co/YE9xcEZkM6",
source_rank: null,
source_name: "Twitter / Bankia_Acciones",
publication_date: "2015-10-01T16:22:53+00:00",
author: [ ],
url: "http://twitter.com/Bankia_Acciones/statuses/649620508716077056",
klout_score: null,
title: "#Bankia Comienzan los problemas financieros para Volkswagen http://t.co/YE9xcEZkM6",
creation_time: "2015-10-01T16:23:18.849Z",
remote_code: "/i/g/t649620508716077056",
source_url: "http://www.twitter.com/Bankia_Acciones",
Muchas gracias.
¿Preguntas?
deck
By migueles
deck
- 4,030