Integrando Redis en aplicaciones Symfony2

2,938 views
2,668 views

Published on

Sus múltiples casos de usos y su excepcional rendimiento hacen que Redis sea hoy una pieza clave en la arquitectura de aplicaciones altamente dinámicas.

En la charla se expone de forma práctica cómo puede integrarse Redis en una aplicación Symfoy y cómo pueden implementarse varias de las características de las aplicaciones usando Redis, como por ejemplo: Session storage, Monolog logging handlers, Doctrine caching, SwiftMailer spooling, Profiler storage, Data Collector for Symfony2 Profiler.

Además de estos casos de uso generales, se comentan otros casos de usos específicos de aplicaciones que por su naturaleza no pueden beneficiarse de una capa de cache y se requiere por tanto una herramienta eficiente y escalable para resolver ciertos tipos de problemas.

Published in: Technology
0 Comments
8 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,938
On SlideShare
0
From Embeds
0
Number of Embeds
7
Actions
Shares
0
Downloads
50
Comments
0
Likes
8
Embeds 0
No embeds

No notes for slide

Integrando Redis en aplicaciones Symfony2

  1. 1. Monday, June 24, 13
  2. 2. Monday, June 24, 13
  3. 3. ¿Quién soy?• Backend Core Tech Lead @ SocialpointArquitectura y desarrollo de aplicaciones queeficientemente respondan peticiones de millones deusuarios cada día• Redis Fan• Made in Cuba• Poco original eligiendo memes• @ronnyltMonday, June 24, 13
  4. 4. Hablemos de algunosde nuestros desafíoscomo desarrolladoresMonday, June 24, 13
  5. 5. Tenemos aplicaciones quepor su naturaleza no esposible usar una cacheMonday, June 24, 13
  6. 6. Tenemos cientos, miles,de usuarios concurrentes ynecesitamos una soluciónescalable para almacenar lassesionesMonday, June 24, 13
  7. 7. Queremos saber quiény cómo se está usandonuestra aplicaciónMonday, June 24, 13
  8. 8. Redis WTF?Redis FTW!Monday, June 24, 13
  9. 9. Agenda• Redis y sus características• Entendiendo Redis• Conectando desde PHP• Integrando Redis en Symfony2• Casos de usoMonday, June 24, 13
  10. 10. REDISYSUSCARACTERÍSTICASMonday, June 24, 13
  11. 11. ¿Qué es Redis?• REmote DIctionary Server• Creado en 2009 por Salvatore Sanfilipo(@antirez)• Open sourceMonday, June 24, 13
  12. 12. Mejor definido como:NoSQLMonday, June 24, 13
  13. 13. Monday, June 24, 13
  14. 14. advancedin-memorykey-valuedata-structure serverRedisMonday, June 24, 13
  15. 15. Data Structure Server• Cadenas• Listas• Conjuntos• Conjuntos ordenados• Hashes (hash maps)Monday, June 24, 13
  16. 16. In-memory Database• Datos deben caber en memoria• Persistencia configurable• “Memory is the new disc, disc is the newtape”Monday, June 24, 13
  17. 17. Advanced key-valuestore database• Persistencia (snapshot, append-only file)• Replicación (master/slave)• Transacciones• Pipelining• Publisher/Subscriber (pub/sub)• Lua scriptingMonday, June 24, 13
  18. 18. Ideal para• Analíticas real-time• Tracking• Caching server (memcached on steroid)• Colas de trabajo• Escritura/Lectura intensiva (sesiones)Monday, June 24, 13
  19. 19. ENTENDIENDOREDISMonday, June 24, 13
  20. 20. Claves y valores• Los datos (values) son refereciados a travésde claves (keys)• Los datos pueden ser recuperados solo siconocemos el nombre de la claveMonday, June 24, 13
  21. 21. Claves(keys)• Únicas dentro de la BD• Binary safe string• Claves muy grandes pueden impactar en elrendimimiento• Claves muy pequeñas no aportan mucho(u:123:n vs user:123:name)Monday, June 24, 13
  22. 22. No es un RMDBS• No hay consultas (queries)• No hay índices• No hay esquemasMonday, June 24, 13
  23. 23. Monday, June 24, 13
  24. 24. Comandos• Lenguaje de comandos fácil de usar y deaprender• Los comandos (en su mayoría) son aplicablesa un tipo de datos específicoMonday, June 24, 13
  25. 25. Tipos de datosCadenasListasConjuntosConjuntos ordenadosHashesData structure serverMonday, June 24, 13
  26. 26. Cadenas• Tipo de dato simple (cualquier cadena binary-safe)• Tamaño máximo de 512 MBkey stringGET, SET, STRLEN,APPEND, GETRANGE, SETRANGEhttp://redis.io/commands#stringMonday, June 24, 13
  27. 27. Casos de uso cadenas• Almacenamiento de cualquier dato (serializado):GET, SET• Vector de acceso aleatorio con GETRANGE,SETRANGE• Mapa de bits usando GETBIT, SETBIT,BITCOUNTMonday, June 24, 13
  28. 28. Casos de uso cadenas• Contadores atómicos con:INCR, DECRINCRBY, DECRBYINCRFLOATBYINCR dowloads:item:123=> 450INCR dowloads:item:123=> 451Monday, June 24, 13
  29. 29. Listas• Listado de cadenas donde el orden es importante• Operaciones de inserción por la izquierda y porla derecha o por posición• Máxima longitud de 2^32 -1 (+4 billones)key s2s1 s3...http://redis.io/commands#listMonday, June 24, 13
  30. 30. Casos de uso Listas• Representación de colas (insertando por laderecha, leyendo por la izquierda) RPUSH, LPOP• Representación de pilas (insertando y leyendo porla izquierda) LPUSH, LPOP• Comandos blocking BLPOP, BRPOP, BRPOPLPUSHMonday, June 24, 13
  31. 31. Conjuntos• Colección de elementos únicos donde elorden no importa• Operaciones típicas de conjuntos sobre losdatoskeybluegreenredblackMonday, June 24, 13
  32. 32. Operaciones deconjuntosSINTERSECT SUNIONSDIFFMonday, June 24, 13
  33. 33. Casos de usoConjuntos• Representación de relaciones• Tracking de sucesos únicos• Cualquier problema donde por su naturaleza serealicen operaciones sobre conjuntosMonday, June 24, 13
  34. 34. Conjuntos Ordenados• Conjuntos de datos, pero ordenados porun score• Elementos únicos dentro del conjunto, cadauno con un score asignadokeyblue – 520green – 890red – 303black – 680Monday, June 24, 13
  35. 35. Conjuntos Ordenados• Operaciones de conjuntos aplicables• Operaciones de acceso por score y por rango entiempo constante y predeciblehttp://redis.io/commands#sorted_setMonday, June 24, 13
  36. 36. Casos de usoConjuntos Ordenados• Leaderboards• Rankings• Tracking basado en tiempoMonday, June 24, 13
  37. 37. Hashes• Múltiples campo => valor en una misma clave• Hasta un máximo de 2^32 -1 pares campo => valorkey field1 value1field2 value2field3 value3http://redis.io/commands#hashMonday, June 24, 13
  38. 38. Hashes• Puede verse como un arreglo asociativo en PHP:clave => [campo1 => valor1,campo2 => valor2,campo3 => valor3]• Operaciones sobre campos individualesMonday, June 24, 13
  39. 39. Casos de uso Hashes• Almacenamiento de objetos compuestospor varios campos• MappingsMonday, June 24, 13
  40. 40. Resumiendo...• Tenemos la oportunidad de usar la estructurade datos adecuada para cada tipo de problema• Tendremos tiempos de ejecución constantes ypredecibles, sin importar el tamaño de losconjuntos de datos (dataset)Monday, June 24, 13
  41. 41. CONECTANDODESDEPHPMonday, June 24, 13
  42. 42. Clientes para PHP• https://github.com/nrk/predis• https://github.com/nicolasff/phpredisClientes disponibles para la mayoría de los lenguajes deprogramación (http://redis.io/clients)Monday, June 24, 13
  43. 43. Predis"require": {"predis/predis": "~0.8.3"},• Escrito en PHP• Maduro y activamente mantenido• Extensible• Feature-complete (pipelines, client side sharding,server profiles, master/slave config, etc.)Monday, June 24, 13
  44. 44. phpredis• Escrito en C como una extensión PHP• Listo para producción• Extremadamente rápido• No backward compatible con anterioresversions de RedisMonday, June 24, 13
  45. 45. ¿Cuál usar?• Depende...• Predis cubre la mayoría de las necesidades,fácil de instalar con composer, y nos ofreceun rendimiento aceptable• phpredis si necesitas un rendimientoexcepcionalMonday, June 24, 13
  46. 46. La latencia de red siguesiendo el principal“performance killer”,no el clienteMonday, June 24, 13
  47. 47. INTEGRANDOREDISENSYMFONY2Monday, June 24, 13
  48. 48. Monday, June 24, 13
  49. 49. SncRedisBundle{"require": {"snc/redis-bundle": "1.1.*"}}https://github.com/snc/SncRedisBundleMonday, June 24, 13
  50. 50. SncRedisBundle• Integra Predis y phpredis en Symfony2• Soporte para:• Session storage• Monolog logging handler• SwiftMailer Spooling• Doctrine cachingMonday, June 24, 13
  51. 51. Definiendo clientessnc_redis:clients:default:type: predisalias: defaultdsn: redis://redis.example.comsession:type: predisalias: sessiondsn:- redis://rses1.example.com- redis://rses2.example.comconfig.yml / redis.ymlMonday, June 24, 13
  52. 52. Configuración avanzadasnc_redis:clients:cache:type: predisalias: cachedsn:- redis://cache1.example.com- redis://cache2.example.comoptions:profile: 2.6connection_timeout: 10readwrite_timeout: 30config.yml / redis.ymlMonday, June 24, 13
  53. 53. Obteniendo el cliente através del container$redis = $container->get(snc_redis.default);$key = downloads: . $pid . :count$downloads = $redis->incr($key);php app/console container:debug | grep snc_redisMonday, June 24, 13
  54. 54. Clientes registradoscomo serviciosphp app/console container:debugsnc_redis.defaultInformation for service snc_redis.defaultService Id snc_redis.defaultClass PredisClientTags -Scope containerPublic yesSynthetic noRequired File -Monday, June 24, 13
  55. 55. Inyectando Redis comodependencianamespace AcmeDemoBundleService;use SncRedisBundleClientPredis as Redis;class DownloadCounter{protected $redis;public function __construct(Redis $redis){$this->redis = $redis;}public function count($itemId){return $this->redis->incr(downloads: . $itemId . :count);}}Monday, June 24, 13
  56. 56. Inyectando Redis comodependencia<service id="acme.demo.download_counter"class="AcmeDemoBundleServiceDownloadCounter">...<argument type="service" id="snc_redis.default" />...</service>Monday, June 24, 13
  57. 57. SesionesMonday, June 24, 13
  58. 58. Sesiones• Difícil de escalar con la configuración pordefecto• Por naturaleza no cacheable (read-change-write back)• Se necesita mantener estado consistenteMonday, June 24, 13
  59. 59. Estado inconsistente en cada nodo(no sticky sessions)Monday, June 24, 13
  60. 60. • Difícil de escalar conmucho tráfico• Escrituras en cadarequest• Replication lagMonday, June 24, 13
  61. 61. • In-memory sessions• Tiempo de accesoconstante y predecible• Escala horizontalmenteMonday, June 24, 13
  62. 62. Monday, June 24, 13
  63. 63. Sesiones en Redis• Sesiones distribuídas (ej. detrás de unbalanceador sin sticky sessions)• Excepcional rendimiento de escritura/lectura• Tiempo de acceso constante y predecible• Escalable horizontalmente (client-side sharding)Monday, June 24, 13
  64. 64. Session handlers• A través de un session handler implementadoen PHP, conectando a través de un clienteRedis• A través de un session handler implementadoen una extensión de PHP (phpredis)Monday, June 24, 13
  65. 65. Usando Predissnc_redis:clients:session_cluster:type: predisalias: sessiondsn:- redis://sess000.example.net- redis://sess001.example.net- redis://sess002.example.netsession:client: session_clusterttl: 1200prefix: appsessionconfig.ymlMonday, June 24, 13
  66. 66. Usando phpredisframework:session:# Default storage servicestorage_id: "session.storage.native"# No handler service, use defaulthandler_id: ~# The name for the session cookiename: "appsesid"config.ymlMonday, June 24, 13
  67. 67. php.ini usando phpredissession.save_handler = redissession.save_path = "tcp://s000.example.net:6379?weight=1,tcp://s001.example.net:6379?weight=2,tcp://s002.example.net:6379?weight=2"Monday, June 24, 13
  68. 68. redis 127.0.0.1:6379> MONITOROK"GET" "appsession:9jmmp11dvh3b4f1bp9trfuqlj3""SETEX" "appsession:9jmmp11dvh3b4f1bp9trfuqlj3""1440" "_sf2_attributes|a:1:{s:5:"visit";i:1371678033;}_sf2_flashes|a:0:{}_sf2_meta|a:3:{s:1:"u";i:1371678033;s:1:"c";i:1371678023;s:1:"l";s:1:"0";}"sessionnamesession id(cookie)ttl(expiretime)sessiondataMonday, June 24, 13
  69. 69. Monolog loggingMonday, June 24, 13
  70. 70. Monolog logging• Los mensajes de logs son almacenados enuna lista• Ideal cuando se necesita un broker quereciba los logs que serán posteriormenteenviados a un agregador (ej. logstash)Monday, June 24, 13
  71. 71. Monolog configsnc_redis:clients:monolog:type: predisalias: monologdsn: redis://localhost/1logging: falsemonolog:client: monologkey: monologmonolog:handlers:main:type: serviceid: monolog.handler.redislevel: debugMonday, June 24, 13
  72. 72. Referencias• http://blog.lusis.org/blog/2012/01/31/load-balancing-logstash-with-redis/Monday, June 24, 13
  73. 73. SwiftMailer SpoolingMonday, June 24, 13
  74. 74. SwiftMailer Spooling• Los mensajes no se envian directamente, sino quese mantienen en un “spool” y son enviados por unproceso en background• Usando redis como “spool”, los mensajes sonmantenidos en una lista hasta que son enviadosMonday, June 24, 13
  75. 75. Mailer spoolingsnc_redis:clients:emails:type: predisalias: emailsdsn: redis://emails-spool-00.example.comlogging: falseswiftmailer:client: emailskey: swiftmailerconfig.ymlMonday, June 24, 13
  76. 76. Otros casos de uso enSymfony2Monday, June 24, 13
  77. 77. Router dinámicos• Necesitamos convertir URLs amigables a rutasinternas de Symfony2:Idioma Ruta interna Ruta “amigable”es /sport/123 /futbolen /sport/123 /footballMonday, June 24, 13
  78. 78. Router dinámicosIdiomaRuta“amigable”_controlleres /futbolBundle:SportController:sportPageAction,array(‘sport’ => 123)es /madridBundle:CityController:cityPageActionarray(‘city’ => 456)Monday, June 24, 13
  79. 79. Desventajas• Difícil de cambiar la configuración de routinguna vez creadas• Es requerido tener copia de la base de datosde routings en los ambientes de desarrollopara que la aplicación funcioneMonday, June 24, 13
  80. 80. Solución alternativa• Crear un mapping entre rutas amigables yrutas internas• Subscribirse a KernelEvents::REQUEST yantes que nada, cambiar pathInfo en el objetoRequestMonday, June 24, 13
  81. 81. FlujoRequest/futbolRequest/sport/123RouterMapperListenerController/ActionRouting SystemMonday, June 24, 13
  82. 82. Monday, June 24, 13
  83. 83. Usando Redis hashes/futbol /sport/123/baloncesto /sport/456/tenis /sport/789routes:es/sport/123 /futbol/sport/456 /baloncesto/sport/789 /tenisalias:esMonday, June 24, 13
  84. 84. Integración con el profilery web debug toolbarMonday, June 24, 13
  85. 85. Integración en el profilerMonday, June 24, 13
  86. 86. OTROSCASOSDEUSOGENERALESMonday, June 24, 13
  87. 87. Presencia de usuarios(who is online?)Monday, June 24, 13
  88. 88. ¿Quién está online?• Mantenemos un conjunto con los usuariosque han estado online por cada minuto• En cada request, agregamos al usuario alconjunto de usuarios online del minutoactual• Obtenemos los usuarios que han estadoonline de la unión de los 5 últimosconjuntosMonday, June 24, 13
  89. 89. Monday, June 24, 13
  90. 90. Amigos online• Mantenemos un conjunto con los amigosde cada usuario• Obtenemos los amigos que están online, dela intersección del conjunto de usuariosonline con el conjunto de amigos de unusuarioMonday, June 24, 13
  91. 91. Usuarios onlineAmigosAmigosOnlineMonday, June 24, 13
  92. 92. class OnlineUsersManager{protected $redis;public function __construct(Redis $redis){$this->redis = $redis;}public function trackUser($userId){$timestamp = time();$minute = date(i, $timestamp);$key = online_users: . $minute;// Add the user to the set of online users in thecurrent minute.$this->redis->sadd($key, $userId);// Expire in 10 minutes.$this->redis->expire(60 * 10);}Monday, June 24, 13
  93. 93. Leaderboards• Caso de uso típico el cual es fácil de implementarcon Redis y díficil de implementar de formaeficiente en otro sistema• Los conjuntos ordenados son las estructuras dedatos perfectas para su implementaciónMonday, June 24, 13
  94. 94. Monday, June 24, 13
  95. 95. class RankingManager{protected $redis;public function __construct(Redis $redis){$this->redis = $redis;}public function onCombatFinished(Combat $combat){$winner = $combat->getAttacker();$score = $combat->getScoreResult();$this->redis->zincr(ranking, $score, $winner->getId());}public function getTopScores($limit){return $this->redis->zrevrange(ranking, 0, $limit);}}Monday, June 24, 13
  96. 96. Extra Tips• Redis es single-threaded, todos loscomandos son atómicos• Transacciones pueden usarse para ejecutarmúltiples comandos de forma atómica• Lua scripts se ejecutan de forma atómicatambién•Monday, June 24, 13
  97. 97. Performance Tips• Usando client-side sharding puede escalarsehorizontalmente ganando en capacidad yrendimiento• Ejecutar múltiples comandos a través depipelinesMonday, June 24, 13
  98. 98. CONCLUSIONESMonday, June 24, 13
  99. 99. NO usar Redis• Cuando el conjunto de datos (dataset) nocabe en memoria• Datos de naturaleza relacional• Cuando no se conoce de antemano comovan a consultarse los datosMonday, June 24, 13
  100. 100. Cuándo usar Redis• Redis para datos temporales, altamente dinámicosy estructuras de datos complejas• Datos de naturaleza no-relacional• Ideal para aplicaciones que son write-heavy• Datos que naturalmente se ajustan a unaestructura de RedisMonday, June 24, 13
  101. 101. Inegrando Redis en unstack PHP/Symfony2• No necesariamente como la DB principal• Resolviendo problemas que son difíciles deresolver en un sistema relacional• Beneficiandonos de las características de Redis deforma incremental• Usando la herramienta adecuada para cada tareaMonday, June 24, 13
  102. 102. Monday, June 24, 13
  103. 103. Referenciashttp://redis.io/commandshttp://redis.io/documentationMonday, June 24, 13
  104. 104. Muchas Graciashttps://joind.in/8844@ronnylthttps://github.com/ronnyltMonday, June 24, 13
  105. 105. We are hiring!Monday, June 24, 13

×