Download - Integrando Redis en aplicaciones Symfony2

Transcript
Page 1: Integrando Redis en aplicaciones Symfony2

Monday, June 24, 13

Page 2: Integrando Redis en aplicaciones Symfony2

Monday, June 24, 13

Page 3: Integrando Redis en aplicaciones Symfony2

¿Quién soy?

• Backend Core Tech Lead @ SocialpointArquitectura y desarrollo de aplicaciones que eficientemente respondan peticiones de millones de usuarios cada día

• Redis Fan

• Made in Cuba

• Poco original eligiendo memes

• @ronnylt

Monday, June 24, 13

Page 4: Integrando Redis en aplicaciones Symfony2

Hablemos de algunos de nuestros desafíos

como desarrolladores

Monday, June 24, 13

Page 5: Integrando Redis en aplicaciones Symfony2

Tenemos aplicaciones que por su naturaleza no es posible usar una cache

Monday, June 24, 13

Page 6: Integrando Redis en aplicaciones Symfony2

Tenemos cientos, miles, de usuarios concurrentes y necesitamos una solución

escalable para almacenar las sesiones

Monday, June 24, 13

Page 7: Integrando Redis en aplicaciones Symfony2

Queremos saber quién y cómo se está usando

nuestra aplicación

Monday, June 24, 13

Page 8: Integrando Redis en aplicaciones Symfony2

Redis WTF?

Redis FTW!

Monday, June 24, 13

Page 9: Integrando Redis en aplicaciones Symfony2

Agenda

• Redis y sus características

• Entendiendo Redis

• Conectando desde PHP

• Integrando Redis en Symfony2

• Casos de uso

Monday, June 24, 13

Page 10: Integrando Redis en aplicaciones Symfony2

REDIS Y SUS CARACTERÍSTICAS

Monday, June 24, 13

Page 11: Integrando Redis en aplicaciones Symfony2

¿Qué es Redis?

• REmote DIctionary Server

• Creado en 2009 por Salvatore Sanfilipo (@antirez)

• Open source

Monday, June 24, 13

Page 12: Integrando Redis en aplicaciones Symfony2

Mejor definido como:

NoSQL

Monday, June 24, 13

Page 13: Integrando Redis en aplicaciones Symfony2

Monday, June 24, 13

Page 14: Integrando Redis en aplicaciones Symfony2

advancedin-memorykey-value

data-structure server

Redis

Monday, June 24, 13

Page 15: Integrando Redis en aplicaciones Symfony2

Data Structure Server

• Cadenas

• Listas

• Conjuntos

• Conjuntos ordenados

• Hashes (hash maps)

Monday, June 24, 13

Page 16: Integrando Redis en aplicaciones Symfony2

In-memory Database

• Datos deben caber en memoria

• Persistencia configurable

• “Memory is the new disc, disc is the new tape”

Monday, June 24, 13

Page 17: Integrando Redis en aplicaciones Symfony2

Advanced key-value store database

• Persistencia (snapshot, append-only file)

• Replicación (master/slave)

• Transacciones

• Pipelining

• Publisher/Subscriber (pub/sub)

• Lua scripting

Monday, June 24, 13

Page 18: Integrando Redis en aplicaciones Symfony2

Ideal para

• Analíticas real-time

• Tracking

• Caching server (memcached on steroid)

• Colas de trabajo

• Escritura/Lectura intensiva (sesiones)

Monday, June 24, 13

Page 19: Integrando Redis en aplicaciones Symfony2

ENTENDIENDO REDIS

Monday, June 24, 13

Page 20: Integrando Redis en aplicaciones Symfony2

Claves y valores

• Los datos (values) son refereciados a través de claves (keys)

• Los datos pueden ser recuperados solo si conocemos el nombre de la clave

Monday, June 24, 13

Page 21: Integrando Redis en aplicaciones Symfony2

Claves(keys)

• Únicas dentro de la BD

• Binary safe string

• Claves muy grandes pueden impactar en el rendimimiento

• Claves muy pequeñas no aportan mucho (u:123:n vs user:123:name)

Monday, June 24, 13

Page 22: Integrando Redis en aplicaciones Symfony2

No es un RMDBS

• No hay consultas (queries)

• No hay índices

• No hay esquemas

Monday, June 24, 13

Page 23: Integrando Redis en aplicaciones Symfony2

Monday, June 24, 13

Page 24: Integrando Redis en aplicaciones Symfony2

Comandos

• Lenguaje de comandos fácil de usar y de aprender

• Los comandos (en su mayoría) son aplicables a un tipo de datos específico

Monday, June 24, 13

Page 25: Integrando Redis en aplicaciones Symfony2

Tipos de datosCadenas

Listas

Conjuntos

Conjuntos ordenados

Hashes

Data structure serverMonday, June 24, 13

Page 26: Integrando Redis en aplicaciones Symfony2

Cadenas

• Tipo de dato simple (cualquier cadena binary-safe)

• Tamaño máximo de 512 MB

key string

GET, SET, STRLEN, APPEND, GETRANGE, SETRANGE

http://redis.io/commands#string

Monday, June 24, 13

Page 27: Integrando Redis en aplicaciones Symfony2

Casos de uso cadenas

• Almacenamiento de cualquier dato (serializado): GET, SET

• Vector de acceso aleatorio con GETRANGE, SETRANGE

• Mapa de bits usando GETBIT, SETBIT, BITCOUNT

Monday, June 24, 13

Page 28: Integrando Redis en aplicaciones Symfony2

Casos de uso cadenas

• Contadores atómicos con:INCR, DECRINCRBY, DECRBYINCRFLOATBY

INCR dowloads:item:123=> 450INCR dowloads:item:123=> 451

Monday, June 24, 13

Page 29: Integrando Redis en aplicaciones Symfony2

Listas

• Listado de cadenas donde el orden es importante

• Operaciones de inserción por la izquierda y por la derecha o por posición

• Máxima longitud de 2^32 -1 (+4 billones)

key s2s1 s3...

http://redis.io/commands#list

Monday, June 24, 13

Page 30: Integrando Redis en aplicaciones Symfony2

Casos de uso Listas

• Representación de colas (insertando por la derecha, leyendo por la izquierda) RPUSH, LPOP

• Representación de pilas (insertando y leyendo por la izquierda) LPUSH, LPOP

• Comandos blocking BLPOP, BRPOP, BRPOPLPUSH

Monday, June 24, 13

Page 31: Integrando Redis en aplicaciones Symfony2

Conjuntos

• Colección de elementos únicos donde el orden no importa

• Operaciones típicas de conjuntos sobre los datos

keyblue greenredblack

Monday, June 24, 13

Page 32: Integrando Redis en aplicaciones Symfony2

Operaciones de conjuntos

SINTERSECT SUNION

SDIFF

Monday, June 24, 13

Page 33: Integrando Redis en aplicaciones Symfony2

Casos de uso Conjuntos

• Representación de relaciones

• Tracking de sucesos únicos

• Cualquier problema donde por su naturaleza se realicen operaciones sobre conjuntos

Monday, June 24, 13

Page 34: Integrando Redis en aplicaciones Symfony2

Conjuntos Ordenados

• Conjuntos de datos, pero ordenados por un score

• Elementos únicos dentro del conjunto, cada uno con un score asignado

key

blue – 520

green – 890

red – 303

black – 680

Monday, June 24, 13

Page 35: Integrando Redis en aplicaciones Symfony2

Conjuntos Ordenados

• Operaciones de conjuntos aplicables

• Operaciones de acceso por score y por rango en tiempo constante y predecible

http://redis.io/commands#sorted_set

Monday, June 24, 13

Page 36: Integrando Redis en aplicaciones Symfony2

Casos de uso Conjuntos Ordenados

• Leaderboards

• Rankings

• Tracking basado en tiempo

Monday, June 24, 13

Page 37: Integrando Redis en aplicaciones Symfony2

Hashes

• Múltiples campo => valor en una misma clave

• Hasta un máximo de 2^32 -1 pares campo => valor

key field1 value1

field2 value2

field3 value3

http://redis.io/commands#hash

Monday, June 24, 13

Page 38: Integrando Redis en aplicaciones Symfony2

Hashes

• Puede verse como un arreglo asociativo en PHP:clave => [ campo1 => valor1, campo2 => valor2, campo3 => valor3]

• Operaciones sobre campos individuales

Monday, June 24, 13

Page 39: Integrando Redis en aplicaciones Symfony2

Casos de uso Hashes

• Almacenamiento de objetos compuestos por varios campos

• Mappings

Monday, June 24, 13

Page 40: Integrando Redis en aplicaciones Symfony2

Resumiendo...

• Tenemos la oportunidad de usar la estructura de datos adecuada para cada tipo de problema

• Tendremos tiempos de ejecución constantes y predecibles, sin importar el tamaño de los conjuntos de datos (dataset)

Monday, June 24, 13

Page 41: Integrando Redis en aplicaciones Symfony2

CONECTANDO DESDE

PHP

Monday, June 24, 13

Page 42: Integrando Redis en aplicaciones Symfony2

Clientes para PHP

• https://github.com/nrk/predis

• https://github.com/nicolasff/phpredis

Clientes disponibles para la mayoría de los lenguajes de programación (http://redis.io/clients)

Monday, June 24, 13

Page 43: Integrando Redis en aplicaciones Symfony2

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

Page 44: Integrando Redis en aplicaciones Symfony2

phpredis

• Escrito en C como una extensión PHP

• Listo para producción

• Extremadamente rápido

• No backward compatible con anteriores versions de Redis

Monday, June 24, 13

Page 45: Integrando Redis en aplicaciones Symfony2

¿Cuál usar?

• Depende...

• Predis cubre la mayoría de las necesidades, fácil de instalar con composer, y nos ofrece un rendimiento aceptable

• phpredis si necesitas un rendimiento excepcional

Monday, June 24, 13

Page 46: Integrando Redis en aplicaciones Symfony2

La latencia de red sigue siendo el principal “performance killer”, no el cliente

Monday, June 24, 13

Page 47: Integrando Redis en aplicaciones Symfony2

INTEGRANDO REDIS EN

SYMFONY2

Monday, June 24, 13

Page 48: Integrando Redis en aplicaciones Symfony2

Monday, June 24, 13

Page 49: Integrando Redis en aplicaciones Symfony2

SncRedisBundle

{ "require": { "snc/redis-bundle": "1.1.*" }}

https://github.com/snc/SncRedisBundle

Monday, June 24, 13

Page 50: Integrando Redis en aplicaciones Symfony2

SncRedisBundle

• Integra Predis y phpredis en Symfony2

• Soporte para:

• Session storage

• Monolog logging handler

• SwiftMailer Spooling

• Doctrine caching

Monday, June 24, 13

Page 51: Integrando Redis en aplicaciones Symfony2

Definiendo clientes

snc_redis: clients: default: type: predis alias: default dsn: redis://redis.example.com

session: type: predis alias: session dsn: - redis://rses1.example.com - redis://rses2.example.com

config.yml / redis.yml

Monday, June 24, 13

Page 52: Integrando Redis en aplicaciones Symfony2

Configuración avanzada

snc_redis: clients: cache: type: predis alias: cache dsn: - redis://cache1.example.com - redis://cache2.example.com options: profile: 2.6 connection_timeout: 10 readwrite_timeout: 30

config.yml / redis.yml

Monday, June 24, 13

Page 53: Integrando Redis en aplicaciones Symfony2

Obteniendo el cliente a través del container

$redis = $container->get('snc_redis.default');$key = 'downloads:' . $pid . ':count'$downloads = $redis->incr($key);

php app/console container:debug | grep snc_redis

Monday, June 24, 13

Page 54: Integrando Redis en aplicaciones Symfony2

Clientes registrados como servicios

php app/console container:debug snc_redis.defaultInformation for service snc_redis.default

Service Id snc_redis.defaultClass Predis\ClientTags -Scope containerPublic yesSynthetic noRequired File -

Monday, June 24, 13

Page 55: Integrando Redis en aplicaciones Symfony2

Inyectando Redis como dependencia

namespace Acme\DemoBundle\Service;

use Snc\RedisBundle\Client\Predis 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

Page 56: Integrando Redis en aplicaciones Symfony2

Inyectando Redis como dependencia

<service id="acme.demo.download_counter" class="Acme\DemoBundle\Service\DownloadCounter">

...

<argument type="service" id="snc_redis.default" />...

</service>

Monday, June 24, 13

Page 57: Integrando Redis en aplicaciones Symfony2

Sesiones

Monday, June 24, 13

Page 58: Integrando Redis en aplicaciones Symfony2

Sesiones

• Difícil de escalar con la configuración por defecto

• Por naturaleza no cacheable (read-change-write back)

• Se necesita mantener estado consistente

Monday, June 24, 13

Page 59: Integrando Redis en aplicaciones Symfony2

Estado inconsistente en cada nodo(no sticky sessions)

Monday, June 24, 13

Page 60: Integrando Redis en aplicaciones Symfony2

• Difícil de escalar con mucho tráfico

• Escrituras en cada request

• Replication lag

Monday, June 24, 13

Page 61: Integrando Redis en aplicaciones Symfony2

• In-memory sessions

• Tiempo de acceso constante y predecible

• Escala horizontalmente

Monday, June 24, 13

Page 62: Integrando Redis en aplicaciones Symfony2

Monday, June 24, 13

Page 63: Integrando Redis en aplicaciones Symfony2

Sesiones en Redis

• Sesiones distribuídas (ej. detrás de un balanceador sin sticky sessions)

• Excepcional rendimiento de escritura/lectura

• Tiempo de acceso constante y predecible

• Escalable horizontalmente (client-side sharding)

Monday, June 24, 13

Page 64: Integrando Redis en aplicaciones Symfony2

Session handlers

• A través de un session handler implementado en PHP, conectando a través de un cliente Redis

• A través de un session handler implementado en una extensión de PHP (phpredis)

Monday, June 24, 13

Page 65: Integrando Redis en aplicaciones Symfony2

Usando Predis

snc_redis: clients: session_cluster: type: predis alias: session dsn: - redis://sess000.example.net - redis://sess001.example.net - redis://sess002.example.net

session: client: session_cluster ttl: 1200 prefix: appsession

config.yml

Monday, June 24, 13

Page 66: Integrando Redis en aplicaciones Symfony2

Usando phpredis

framework: session: # Default storage service storage_id: "session.storage.native"

# No handler service, use default handler_id: ~

# The name for the session cookie name: "appsesid"

config.yml

Monday, June 24, 13

Page 67: Integrando Redis en aplicaciones Symfony2

php.ini usando phpredis

session.save_handler = redis

session.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

Page 68: Integrando Redis en aplicaciones Symfony2

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\";}"

session name

session id (cookie)

ttl(expire time)

session data

Monday, June 24, 13

Page 69: Integrando Redis en aplicaciones Symfony2

Monolog logging

Monday, June 24, 13

Page 70: Integrando Redis en aplicaciones Symfony2

Monolog logging

• Los mensajes de logs son almacenados en una lista

• Ideal cuando se necesita un broker que reciba los logs que serán posteriormente enviados a un agregador (ej. logstash)

Monday, June 24, 13

Page 71: Integrando Redis en aplicaciones Symfony2

Monolog configsnc_redis: clients: monolog: type: predis alias: monolog dsn: redis://localhost/1 logging: false monolog: client: monolog key: monologmonolog: handlers: main: type: service id: monolog.handler.redis level: debug

Monday, June 24, 13

Page 73: Integrando Redis en aplicaciones Symfony2

SwiftMailer Spooling

Monday, June 24, 13

Page 74: Integrando Redis en aplicaciones Symfony2

SwiftMailer Spooling

• Los mensajes no se envian directamente, sino que se mantienen en un “spool” y son enviados por un proceso en background

• Usando redis como “spool”, los mensajes son mantenidos en una lista hasta que son enviados

Monday, June 24, 13

Page 75: Integrando Redis en aplicaciones Symfony2

Mailer spooling

snc_redis: clients: emails: type: predis alias: emails dsn: redis://emails-spool-00.example.com logging: false

swiftmailer: client: emails key: swiftmailer

config.yml

Monday, June 24, 13

Page 76: Integrando Redis en aplicaciones Symfony2

Otros casos de uso en Symfony2

Monday, June 24, 13

Page 77: Integrando Redis en aplicaciones Symfony2

Router dinámicos• Necesitamos convertir URLs amigables a rutas

internas de Symfony2:

Idioma Ruta interna Ruta “amigable”

es /sport/123 /futbol

en /sport/123 /football

Monday, June 24, 13

Page 78: Integrando Redis en aplicaciones Symfony2

Router dinámicos

Idioma Ruta “amigable”

_controller

es /futbol Bundle:SportController:sportPageAction, array(‘sport’ => 123)

es /madrid Bundle:CityController:cityPageActionarray(‘city’ => 456)

Monday, June 24, 13

Page 79: Integrando Redis en aplicaciones Symfony2

Desventajas

• Difícil de cambiar la configuración de routing una vez creadas

• Es requerido tener copia de la base de datos de routings en los ambientes de desarrollo para que la aplicación funcione

Monday, June 24, 13

Page 80: Integrando Redis en aplicaciones Symfony2

Solución alternativa

• Crear un mapping entre rutas amigables y rutas internas

• Subscribirse a KernelEvents::REQUEST y antes que nada, cambiar pathInfo en el objeto Request

Monday, June 24, 13

Page 81: Integrando Redis en aplicaciones Symfony2

FlujoRequest/futbol

Request/sport/123

RouterMapperListener

Controller/Action

Routing System

Monday, June 24, 13

Page 82: Integrando Redis en aplicaciones Symfony2

Monday, June 24, 13

Page 83: Integrando Redis en aplicaciones Symfony2

Usando Redis hashes

/futbol /sport/123

/baloncesto /sport/456

/tenis /sport/789

routes:es

/sport/123 /futbol

/sport/456 /baloncesto

/sport/789 /tenis

alias:es

Monday, June 24, 13

Page 84: Integrando Redis en aplicaciones Symfony2

Integración con el profiler y web debug toolbar

Monday, June 24, 13

Page 85: Integrando Redis en aplicaciones Symfony2

Integración en el profiler

Monday, June 24, 13

Page 86: Integrando Redis en aplicaciones Symfony2

OTROS CASOS DE USO GENERALES

Monday, June 24, 13

Page 87: Integrando Redis en aplicaciones Symfony2

Presencia de usuarios(who is online?)

Monday, June 24, 13

Page 88: Integrando Redis en aplicaciones Symfony2

¿Quién está online?

• Mantenemos un conjunto con los usuarios que han estado online por cada minuto

• En cada request, agregamos al usuario al conjunto de usuarios online del minuto actual

• Obtenemos los usuarios que han estado online de la unión de los 5 últimos conjuntos

Monday, June 24, 13

Page 89: Integrando Redis en aplicaciones Symfony2

Monday, June 24, 13

Page 90: Integrando Redis en aplicaciones Symfony2

Amigos online

• Mantenemos un conjunto con los amigos de cada usuario

• Obtenemos los amigos que están online, de la intersección del conjunto de usuarios online con el conjunto de amigos de un usuario

Monday, June 24, 13

Page 91: Integrando Redis en aplicaciones Symfony2

Usuarios online

Amigos

AmigosOnline

Monday, June 24, 13

Page 92: Integrando Redis en aplicaciones Symfony2

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 the current minute. $this->redis->sadd($key, $userId);

// Expire in 10 minutes. $this->redis->expire(60 * 10); }}

Monday, June 24, 13

Page 93: Integrando Redis en aplicaciones Symfony2

Leaderboards

• Caso de uso típico el cual es fácil de implementar con Redis y díficil de implementar de forma eficiente en otro sistema

• Los conjuntos ordenados son las estructuras de datos perfectas para su implementación

Monday, June 24, 13

Page 94: Integrando Redis en aplicaciones Symfony2

Monday, June 24, 13

Page 95: Integrando Redis en aplicaciones Symfony2

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

Page 96: Integrando Redis en aplicaciones Symfony2

Extra Tips

• Redis es single-threaded, todos los comandos son atómicos

• Transacciones pueden usarse para ejecutar múltiples comandos de forma atómica

• Lua scripts se ejecutan de forma atómica también

Monday, June 24, 13

Page 97: Integrando Redis en aplicaciones Symfony2

Performance Tips

• Usando client-side sharding puede escalarse horizontalmente ganando en capacidad y rendimiento

• Ejecutar múltiples comandos a través de pipelines

Monday, June 24, 13

Page 98: Integrando Redis en aplicaciones Symfony2

CONCLUSIONES

Monday, June 24, 13

Page 99: Integrando Redis en aplicaciones Symfony2

NO usar Redis

• Cuando el conjunto de datos (dataset) no cabe en memoria

• Datos de naturaleza relacional

• Cuando no se conoce de antemano como van a consultarse los datos

Monday, June 24, 13

Page 100: Integrando Redis en aplicaciones Symfony2

Cuándo usar Redis

• Redis para datos temporales, altamente dinámicos y estructuras de datos complejas

• Datos de naturaleza no-relacional

• Ideal para aplicaciones que son write-heavy

• Datos que naturalmente se ajustan a una estructura de Redis

Monday, June 24, 13

Page 101: Integrando Redis en aplicaciones Symfony2

Inegrando Redis en un stack PHP/Symfony2

• No necesariamente como la DB principal

• Resolviendo problemas que son difíciles de resolver en un sistema relacional

• Beneficiandonos de las características de Redis de forma incremental

• Usando la herramienta adecuada para cada tarea

Monday, June 24, 13

Page 102: Integrando Redis en aplicaciones Symfony2

Monday, June 24, 13

Page 103: Integrando Redis en aplicaciones Symfony2

Referencias

http://redis.io/commandshttp://redis.io/documentation

Monday, June 24, 13

Page 104: Integrando Redis en aplicaciones Symfony2

Muchas Graciashttps://joind.in/8844

@ronnylt

https://github.com/ronnylt

Monday, June 24, 13

Page 105: Integrando Redis en aplicaciones Symfony2

We are hiring!

Monday, June 24, 13