Cómo construir una plataforma de libro electrónico y no morir en el intento

Post on 21-Jun-2015

2.125 views 3 download

Transcript of Cómo construir una plataforma de libro electrónico y no morir en el intento

CÓMO  CONSTRUIR  UNA  PLATAFORMA  DE  LIBRO  

ELECTRÓNICO  Y  

NO  MORIR  EN  EL  INTENTO  

Los speakers

Alberto  Vilches    •  Programando  desde  1998  

•  5  años  de  experiencia  con  Grails  

•  Soy  el  que  organiza  todo  esto  

•  TwiIer:  @albertovilches  

Roberto  Mar=n    •  Programador  desde  2008  

•  4  años  de  experiencia  con  Grails  

•  Miembro  de  plataforma  Java  en  BQ  

•  TwiIer:  @roberto_mf  

De que vamos a hablar

10%  Negocio  

 20%  Experiencia    30%  Arquitectura    40%  Grails  (con  algo  de  código!)    

Donde trabajamos

Donde trabajamos

Mundoreader  –  BQ  Readers    •  Empresa  100%  española  (sedes  en  todo  el  mundo)  

•  2º  fabricante  y  vendedor  de  tablets  en  España  (después  de  Apple)  

•  Primera  plataforma  completa  de  libro  electrónico.  

•  Y  otros  negocios:  memorias  USB,  accesorios,  etc.  

Negocio

Negocio  principal:  venta  de  disposiNvos  (tablets,  ereaders)  

Siguiente  objebvo:  venta  de  contenidos  

 

Beneficios  €  

Inversión  

Negocio

Venta  de  contenido  

•  Diseño,  creación  y  distribución  de  E-­‐readers  

•  Acuerdos  con  editoriales  

•  Creación  de  plataforma  de  venta  de  libros  

Modelo de negocio

1.  BQReaders  NO  es  una  benda  de  libros  

2.  Los  libros  los  venden  las  Nendas  grandes  librerías  y  superficies  /  pequeños  comercios  no  podemos  decir  quienes…    

3.  Lo  hacen  a  través  de  nuestra  plataforma  

4.  Y  nos  llevamos  comisión  por  libro  vendido  -­‐>                    !!!  

5.  ¿Tienes  una  benda?  ¿Eres  una  editorial?  Habla  con  nosotros!  

 

 

Modelo de negocio

1.  Las  bendas  usan  nuestra  plataforma  para  crear  una  web  y  vender  libros  

 aunque  a  veces  se  la  hacemos  también  nosotros…                !  

 2.  Las  bendas  venden  E-­‐readers  a  sus  usuarios  

3.  Lo  hacen  con  su  marca,  pero  nos  los  compran  a  nosotros…              !  

4.   Vendemos  la  solución  completa  

 

 

Modelo de negocio

Y  más  cosas    

1.  Suscripción  Esblo  Spobfy:  cuota  mensual  y  barra  libre    

2.  Bibliotecas  Préstamos,  adquisición  de  licencias  

3.  Aplicaciones  en  IOS  y  Android  

 

 

Cómo funciona

   

 

 

 Tienda  WEB  

App  nabva  IOS  

App  nabva  Android  

Compra  y  lee  libros  

Consumen  Servicios  (muchos!)  

Plataforma  contenidos  

E-­‐Reader  

Plataforma de contenidos

Tecnologías  usadas  

•  Grails  3  wars:  services,  content,  backoffice    

•  MySql  2  esquemas  en  2  máquinas  disbntas  

1.  SERVICES  (usuarios,  compras,  disposibvos)  2.  CONTENT  (libros,  editoriales,  categorías,  catálogos)  

Plataforma de contenidos

Tecnologías  usadas  

•  ElasbcSearch  •  Búsqueda  de  libros,  facetas  •  Evita  acceder  a  la  base  de  datos    •  Si  se  cae,  usamos  la  base  de  datos  (pero  no  tenemos  facetas)  

•  Mahout  •  Recomendaciones  de  libros  en  función  de  las  compras  y  visitas  

•  MongoDB  •  Auditoría  y  tablas  maestras  (paises-­‐ips,  reports,  )  

Plataforma de contenidos

Componentes  

•  API  para  bendas:  JSON  100%  (rest  90%)    Listados  de  libros,  búsquedas,  categorías,  compras  

•  API  para  Ereader,  IOS  y  Android    Sincronizar  librería,  descargar  libro,  anotaciones,  bookmarks  

•  Carga  de  contenidos    Proceso  nocturno  desde  editoriales  (tp,  epubs,  pdf,  onix,  carátulas)  

•  Backoffice  Administración  de  libros,  categorías,  catálogos,  reports,  liquidaciones  

 Problemas  y…  

 “nuestras”  soluciones  

 

Plataforma de contenidos

API  En  caso  de  error:    •  Debe  seguir  devolviendo  JSON  

•  Si  es  un  error  incontrolado,  debe  nobficar  del  error  •  Log,  auditoria,  email  

       

Plataforma de contenidos

API    

Plataforma de contenidos

API    

Plataforma de contenidos

Seguridad  API    

“No  queremos  usar  login/token/sesión  por  cliente”    

 

Plataforma de contenidos

Seguridad  API    

“No  queremos  usar  login/token/sesión  por  cliente”    

1.  Las  password  son  siempre  débiles  2.  El  cliente  no  maneja  sesión  

3.  El  servidor  tampoco  (stateless,  más  fácil  de  replicar)  

Solución:  pebciones  firmadas    

Plataforma de contenidos

Seguridad  API  Firmar  una  pebción    

•  Se  concatena  la  url  y  todos  sus  parámetros  (get  o  post,  todos)  

•  Se  obbene  su  hash  •  Se  encripta  la  hash  con  la  clave  privada  =  firma  •  Se  envía  la  firma  en  una  cabecera  

hex(  crypt(  sha1(  url+params,  key  )  )  )  

•  El  servidor  hace  el  paso  inverso.  Si  los  parámetros  coinciden,  ejecuta  la  operación.  

 

Plataforma de contenidos

Seguridad  API    

Al  estar  basada  en  una  hash,  la  firma  cambiará  cada  vez  que  cambie  la  url  y/o  los  parámetros.  

 Interceptar  la  firma  no  permite  manipular  la  

pebción    

¡Pero  una  pebción  interceptada  se  puede  replicar  N  veces!  

 

Plataforma de contenidos

Seguridad  API  Evitar  que  se  repliquen  las  pebciones    Solución:  nonce  

•  Cada  pebción  debe  enviar  un  parámetro  obligatorio  llamado  “nonce”.  

•  Su  valor  debe  ser  un  número  no  usado  antes  (milesegundos?)  •  El  servidor  conserva  cada  nonce  enviado  y  verifica  que  no  se  

repita.  •  Si  se  envía  el  mismo  “nonce”  se  rechaza  la  pebción.  

Algunos trucos

Trabajar  con  decimales    

Algunos trucos

Trabajar  con  decimales  •  Los  números  decimales  pierden  precisión  cuando  se  

transforman  de  binario  a  decimal  

•  No  importa  cuando  trabajamos  con  muchos  decimales  (de  hecho,  es  necesario):  distancias,  pesos  

•  Pero  SI  importa  cuando  trabajamos  con  precios!  

Algunos trucos

Trabajar  con  decimales:  solución    

1.  Clases  de  dominio:  usar  BigDecimal!

Algunos trucos

Trabajar  con  decimales:  solución    

1.  Clases  de  dominio:  usar  BigDecimal!2.  Base  de  datos.  Precisión  de  n+1  para  

productos  3  decimales  para  €  -­‐>  DECIMAL(16,  3)  

Algunos trucos

Trabajar  con  decimales:  solución    

1.  Clases  de  dominio:  usar  BigDecimal!2.  Base  de  datos.  Precisión  de  n+1  para  

productos  3  decimales  para  €  -­‐>  DECIMAL(16,  3)  

3.  Base  de  datos.  Precisión  de  n  para  compras  2  decimales  para  €  -­‐>  DECIMAL(15,  2)  

Algunos trucos

Trabajar  con  decimales:  solución    

1.  Clases  de  dominio:  usar  BigDecimal!2.  Base  de  datos.  Precisión  de  n+1  para  

productos  3  decimales  para  €  -­‐>  DECIMAL(16,  3)  

3.  Base  de  datos.  Precisión  de  n  para  compras  2  decimales  para  €  -­‐>  DECIMAL(15,  2)  

4.  Evitar  recalcular    Al  hacer  una  compra,  guardar  una  “foto”  con  todos  los  valores  ya  

calculados.  

Concurrencia

Típico  problema  de  concurrencia    

Concurrencia

Típico  problema  de  concurrencia    1.  Un  usuario  se  conecta  desde  diferentes  

clientes  a  la  vez  (ipad  y  web),…  

2.  …  ejecuta  dos  operaciones  que  escriben  en  el  mismo  registro  de  la  base  de  datos…              

Concurrencia

Típico  problema  de  concurrencia    

Concurrencia

A)  Cuando  NO  ES  un  registro  importante:      

         Fecha  de  úlbma  conexión/sincronización/actualización            Actualizar  una  anotación  de  un  libro            Datos  personales  del  usuario,…  

   

 

 

Concurrencia

A)  Cuando  NO  ES  un  registro  importante:    1.  Desacbvar  opbmisbc  locking  2.  Acbvar  dynamicUpdate  (opcional)  

 

 

 

Concurrencia

A)  Cuando  NO  ES  un  registro  importante:    1.  Desacbvar  opbmisbc  locking  2.  Acbvar  dynamicUpdate  (opcional)  

 

 

  UPDATE … WHERE ID = 2678 AND VERSION = 10!

UPDATE table SET campo_que_ha_cambiado WHERE ID = 2678!

Concurrencia

DynamicUpdate  PITFALL!!  LLLLLLL    

Si  se  modifica  un  campo  dentro  de    beforeInsert  /  beforeUpdate  

¡No  se  escribirá!  Bug?    

Solución:  Usar  beforeValidate  

Se  ejecuta  después  de  save(),  al  insertar  o  modificar  

Concurrencia

B)  Cuando  ES  un  registro  importante    

                             Modificar  el  saldo  de  un  usuario              Devolver  una  compra  

                 Consumir  un  cupón  prepago  

 

Concurrencia

B)  Cuando  ES  un  registro  importante  1.  Iniciar  transacción    

 

Concurrencia

B)  Cuando  ES  un  registro  importante  1.  Iniciar  transacción  2.  Bloquear  el  registro      

 

Concurrencia

B)  Cuando  ES  un  registro  importante  1.  Iniciar  transacción  2.  Bloquear  el  registro      

 

SELECT * FROM USER … FOR UPDATE!

Algunos trucos

Operaciones  en  background  Escritura  de  logs,  actualizar  estadísbcas,  envío  de  mensajes,  colas…  

 

Algunos trucos

Operaciones  en  background  Escritura  de  logs,  actualizar  estadísbcas,  envío  de  mensajes,  colas…    

1.  Objebvo    Finalizar  la  pebción  lo  antes  posible  

2.  Que  necesitamos:    Crear  un  hilo  con  la  sesión  de  Hibernate  

3.  Plugins:  1.  BackgroundThread  plugin  2.  Executor  3.  Quartz  

 

Algunos trucos

Actualizaciones  masivas                  

Si  hay  muchos  registros  (cientes  de  miles  o  millones)  •  Extremadamento  lento  •  Puedo  agotar  el  heap  •  No  es  eficiente  

Algunos trucos

Actualizaciones  masivas        

•  A  veces  se  puede  susbtuir…  J  

 

Algunos trucos

Actualizaciones  masivas    •  Pero  otras  no  se  puede!  

       Cada  registro  requiere  lógica  de  negocio  L  

Algunos trucos

Actualizaciones  masivas    

Solución  •  Hilo  en  background  •  Seleccionar  solo  lo  necesario  (projecbons)  •  Paginar  (hacer  de  1000  en  1000  elementos)  •  Limpiar  la  sesión  de  nivel  de  1  de  Hibernate  •  Introducir  pausas  si  es  necesario  

Si  falla  todo  lo  demás  •  Crear  un  PLSQL  y  llamarlo  on  demand  o  por  la  noche  

Algunos trucos

Actualizaciones  masivas    

Algunos trucos

Actualizaciones  masivas    

Projection

Algunos trucos

Actualizaciones  masivas    

Paginación

Algunos trucos

Actualizaciones  masivas    

Vaciar la sesión de Hibernate Pausa

Algunos trucos

Actualizaciones  masivas    

¿Que  sucede  si  cada  operación  individual  es  muuuuuy  lenta?  

 Cada  operación  una  llamada  a  un  servicio  externo…    

Algunos trucos

Actualizaciones  masivas    

¿Que  sucede  si  cada  operación  individual  es  muuuuuy  lenta?  

 

SOLUCIÓN:  Un  pool  de  hilos    

Algunos trucos

Actualizaciones  masivas  Configuración  pool  de  hilos:  plugin  Executor  

     

Algunos trucos

Actualizaciones  masivas  Configuración  pool  de  hilos:  plugin  Executor  

     

Número de hilos máximos a la vez

Algunos trucos

Actualizaciones  masivas    

     

Se obtienen primero SOLO los ids

Algunos trucos

Actualizaciones  masivas    

     

Operación lenta: Cargo € en tarjeta

Se encola la operación

Algunos trucos

Actualizaciones  masivas    

     

Operación lenta: Cargo € en tarjeta

Esperamos a que acaben todos los hilos

Se encola la operación

Algunos trucos

Actualizaciones  masivas    

     

Vaciamos la sesión de Hibernate y volvemos a empezar

Escalabilidad

   

   

Escalabilidad

Arquitectura    

   

hIps://services.mundoreader.com  

hIps://panel.mundoreader.com  

Tiendas  (web)  

Tomcat  Grails  

MySql  

Escalabilidad

Arquitectura    

   

hIps://services.mundoreader.com  

hIps://panel.mundoreader.com  

Tiendas  (web)  

Tomcat  Grails  

Stateless!!  JJJJ  

MySql  

Escalabilidad

Arquitectura    

   

hIps://services.mundoreader.com  

hIps://panel.mundoreader.com  

Tiendas  (web)  

Tomcat  Grails  

Stateless!!  JJJJ  

Escalabilidad

Arquitectura    

   

hIps://services.mundoreader.com  

hIps://panel.mundoreader.com  

Tiendas  (web)  

Tomcat  Grails  

Stateless!!  JJJJ  

Escalabilidad

Evitar  trabajo  innecesario  -­‐>  Delegar  en  la  bbdd.    Evitar  N+1  consultas.  Peligro!  Gorm!!    

•  Usar  JOINs.  Crear  índices  si  es  necesario.  

•  Inyectar  propiedades  (valores  agrupados,  etc)  

•  Desnormalizar    

   

Escalabilidad

Inyectar  propiedades  

•  En  vez  de:  

 

 

   

Escalabilidad

Inyectar  propiedades  

•  En  vez  de:  

•  Usar  

 

   

Escalabilidad

Analizar  el  rendimiento  de  la  bbdd  

•  OpenNMS  •  Script  de  análisis  •  MySql  Slow  Queries  

   

show variables like 'slow_query_log';!set global slow_query_log='ON';!!/var/log/mysql/mysql-slow.log!!

Escalabilidad

Arquitectura    

   

hIps://services.mundoreader.com  

hIps://panel.mundoreader.com  Tomcat  Grails  

Stateless!!  JJJJ  

Escalabilidad

Dividir  el  esquema  en  dos  •  2  MySql  fisicamente  disbntas  •  Relaciones  ligeras  entre  tablas  de  disbnta  bbdd  •  2  datasources  por  Tomcat  •  No  JOINs!  -­‐>  Desnormalizar  

   

hIps://panel.mundoreader.com  Tomcat  Grails  

MySql  1  

MySql  2  

Escalabilidad

Escalabilidad  Dos  datasources  •  Configuración  

•  Clases  de  dominio  

     

Escalabilidad

Rendimiento  DESNORMALIZAR  •  Duplicar  datos  de  otras  tablas  •  Evita  joins  -­‐>  más  rápido  •  Perdida  de  consistencia  •  Uso  de  otros  bpos  de  base  de  datos  

•  Libros  -­‐>  ElasbcSearch  •  Auditoría  -­‐>  MongoDb  con  Gorm  

   

Escalabilidad

Rendimiento  ElasbcSearch    •  Motor  de  búsqueda  en  texto  plano  •  Basado  en  Lucene  •  Api  JSON  100%  •  Alta  escalabilidad:  cluster,  nodos,  shards  •  Facetas  

   

Escalabilidad

Rendimiento  ElasbcSearch  Problema:  Indexar  desde  diferentes  puntos  de  la  aplicación    •  Al  modificar  un  libro  •  Al  modificar  una  categoría  (actualizar  todos  sus  libros)  

•  Al  modificar  un  catálogo                    “                                “                “              “  •  Bucles,  hilos  de  fondo,  barras  de  progreso…  LLL  

   

Escalabilidad

Rendimiento  ElasbcSearch  Problema:  Indexar  desde  diferentes  puntos  de  la  aplicación  Solución:  Demonio  de  indexación    •  Único  punto  de  acceso  al  ES  para  escribir  •  Conbnuamente  procesa  libros  encolados  para  

indexar  •  Para  indexar  un  libro,  solo  hay  que  encolarlo      

Escalabilidad

Rendimiento  ElasbcSearch  Problema:  Indexar  desde  diferentes  puntos  de  la  aplicación  Solución:  Demonio  de  indexación    •  Al  arrancar,  si  no  hay  nodo,  lo  crea  y  reindexa  •  Permite  encolar  reindexaciones  completas  •  Reconstruir  con  alias  (truco)  •  Índice  por  versión  de  app.      

Escalabilidad

Rendimiento  Cachear  todo!!  

•  SpringCache  •  JCS  •  Implementaciones  propias  

MySql  •  Cluster  Master/Slave  •  Servidores  read  only  •  Amazon  RDS  

Escalabilidad

Rendimiento  Pruebas  de  carga:  conoce  tu  límite  •  Antes  y  después  de  aplicar  mejoras.  Mide  lo  que  has  

ganado.  Profile  tus  JVMs  •  YourKit  Java  Profiler:  memory  leaks,  threads  •  Java  Melody  (no  funciona  con  múlbples  datasources)  •  Plugin  BigDesk  para  ElasbcSearch  

Monitorización

Crea  tu  propia  página  de  información  

Monitorización

Monitorizar:  página  con  información  

Monitorización

Crea  tu  propia  página  de  información  

Monitorización

Crea  tu  propia  página  de  información    <app>/scripts/_Events.groovy!

Monitorización

Crea  tu  propia  página  de  información    1.  Mostrar  estado  de  

servicios  2.  Chequeo  de  

servicios  3.  Mostrar  hosts/ips      

Monitorización

Crea  tu  propia  página  de  información    1.  Mostrar  estado  de  

servicios  2.  Chequeo  de  

servicios  3.  Mostrar  hosts/ips      

Monitorización

Crea  tu  propia  página  de  información    1.  Mostrar  estado  de  

servicios  2.  Chequeo  de  

servicios  3.  Mostrar  hosts/ips      

Pase a producción

Build  •  Scripts  de  update  SVN,  war  y  upload  a  repo  Test  •  SoapUI  y  manuales  Config  •  Configuración  externa  en  SVN  y  por  versión  Deploy  •  Script  de  descarga  de  war  desde  repo  (por  versión)  Rollback  •  Dump  de  base  datos.  Deploy  versión  anterior.  Config  

se  conserva  entre  versiones.          

Pase a producción

Config          Un  directorio  por  versión:          

     

 

¡Gracias!      

¿Preguntas?  (Tienen  premio!)